[PATCH 2/6] wined3d: Implement draw calls with no attachments.

Józef Kucia jkucia at codeweavers.com
Thu Mar 1 12:36:52 CST 2018


Supported when ARB_framebuffer_no_attachments is available.

It was reported that no attachments framebuffers trigger GPU hangs
in The Witcher 3 on some system configurations with radeonsi driver.
MESA_EXTENSION_OVERRIDE=-GL_ARB_framebuffer_no_attachments can be used
as a workaround until it's fixed.

Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---

I wasn't able to reproduce the mentioned issue. The game works fine here
on 2 different AMD GPUs with radeonsi.

---
 dlls/wined3d/context.c         | 35 ++++++++++++++++++++++++++++-------
 dlls/wined3d/directx.c         | 13 +++++++++++++
 dlls/wined3d/state.c           | 13 ++++---------
 dlls/wined3d/wined3d_private.h |  3 +++
 4 files changed, 48 insertions(+), 16 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 975a79c9b660..c73e4d12b5ce 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -700,8 +700,8 @@ static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context,
 static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
-    unsigned int i;
     GLuint read_binding, draw_binding;
+    unsigned int i;
 
     if (entry->flags & WINED3D_FBO_ENTRY_FLAG_ATTACHED)
     {
@@ -713,6 +713,16 @@ static void context_apply_fbo_entry(struct wined3d_context *context, GLenum targ
     draw_binding = context->fbo_draw_binding;
     context_bind_fbo(context, GL_FRAMEBUFFER, entry->id);
 
+    if (gl_info->supported[ARB_FRAMEBUFFER_NO_ATTACHMENTS])
+    {
+        GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER,
+                GL_FRAMEBUFFER_DEFAULT_WIDTH, gl_info->limits.framebuffer_width));
+        GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER,
+                GL_FRAMEBUFFER_DEFAULT_HEIGHT, gl_info->limits.framebuffer_height));
+        GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, 1));
+        GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, 1));
+    }
+
     /* Apply render targets */
     for (i = 0; i < gl_info->limits.buffers; ++i)
     {
@@ -2996,12 +3006,13 @@ void context_apply_blit_state(struct wined3d_context *context, const struct wine
     context_invalidate_state(context, STATE_FRAMEBUFFER);
 }
 
-static BOOL context_validate_rt_config(UINT rt_count, struct wined3d_rendertarget_view * const *rts,
+static BOOL have_framebuffer_attachment(unsigned int rt_count, struct wined3d_rendertarget_view * const *rts,
         const struct wined3d_rendertarget_view *ds)
 {
     unsigned int i;
 
-    if (ds) return TRUE;
+    if (ds)
+        return TRUE;
 
     for (i = 0; i < rt_count; ++i)
     {
@@ -3009,7 +3020,6 @@ static BOOL context_validate_rt_config(UINT rt_count, struct wined3d_rendertarge
             return TRUE;
     }
 
-    WARN("Invalid render target config, need at least one attachment.\n");
     return FALSE;
 }
 
@@ -3026,8 +3036,11 @@ BOOL context_apply_clear_state(struct wined3d_context *context, const struct win
     if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != state->fb
             || rt_count != gl_info->limits.buffers)
     {
-        if (!context_validate_rt_config(rt_count, rts, dsv))
+        if (!have_framebuffer_attachment(rt_count, rts, dsv))
+        {
+            WARN("Invalid render target config, need at least one attachment.\n");
             return FALSE;
+        }
 
         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
         {
@@ -3908,8 +3921,16 @@ static BOOL context_apply_draw_state(struct wined3d_context *context,
     unsigned int i;
     WORD map;
 
-    if (!context_validate_rt_config(gl_info->limits.buffers, fb->render_targets, fb->depth_stencil))
-        return FALSE;
+    if (!have_framebuffer_attachment(gl_info->limits.buffers, fb->render_targets, fb->depth_stencil))
+    {
+        if (!gl_info->supported[ARB_FRAMEBUFFER_NO_ATTACHMENTS])
+        {
+            FIXME("OpenGL implementation does not support framebuffers with no attachments.\n");
+            return FALSE;
+        }
+
+        context_set_render_offscreen(context, TRUE);
+    }
 
     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && isStateDirty(context, STATE_FRAMEBUFFER))
     {
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index a95ded351dde..b73966afec26 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -3779,6 +3779,19 @@ static void wined3d_adapter_init_limits(struct wined3d_gl_info *gl_info)
         gl_info->limits.samples = gl_max;
     }
 
+    if (gl_info->supported[ARB_FRAMEBUFFER_NO_ATTACHMENTS])
+    {
+        gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &gl_max);
+        gl_info->limits.framebuffer_width = gl_max;
+        gl_info->gl_ops.gl.p_glGetIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &gl_max);
+        gl_info->limits.framebuffer_height = gl_max;
+    }
+    else
+    {
+        gl_info->limits.framebuffer_width = gl_info->limits.texture_size;
+        gl_info->limits.framebuffer_height = gl_info->limits.texture_size;
+    }
+
     gl_info->limits.samplers[WINED3D_SHADER_TYPE_PIXEL] =
             min(gl_info->limits.samplers[WINED3D_SHADER_TYPE_PIXEL], MAX_GL_FRAGMENT_SAMPLERS);
     sampler_count = 0;
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 407ad623802d..fd858c505391 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -4671,17 +4671,15 @@ static void viewport_miscpart(struct wined3d_context *context, const struct wine
     }
     else if (depth_stencil)
     {
-        width = depth_stencil->width;
         height = depth_stencil->height;
     }
     else
     {
-        FIXME("No attachments draw calls not supported.\n");
-        return;
+        height = gl_info->limits.framebuffer_height;
     }
 
     gl_info->gl_ops.gl.p_glDepthRange(vp.min_z, vp.max_z);
-    checkGLcall("glDepthRange");
+
     /* Note: GL requires lower left, DirectX supplies upper left. This is
      * reversed when using offscreen rendering. */
     y = context->render_offscreen ? vp.y : height - (vp.y + vp.height);
@@ -4690,7 +4688,7 @@ static void viewport_miscpart(struct wined3d_context *context, const struct wine
         GL_EXTCALL(glViewportIndexedf(0, vp.x, y, vp.width, vp.height));
     else
         gl_info->gl_ops.gl.p_glViewport(vp.x, y, vp.width, vp.height);
-    checkGLcall("glViewport");
+    checkGLcall("setting clip space and viewport");
 }
 
 static void viewport_miscpart_cc(struct wined3d_context *context,
@@ -4717,17 +4715,14 @@ static void viewport_miscpart_cc(struct wined3d_context *context,
     }
     else if (depth_stencil)
     {
-        width = depth_stencil->width;
         height = depth_stencil->height;
     }
     else
     {
-        FIXME("No attachments draw calls not supported.\n");
-        return;
+        height = gl_info->limits.framebuffer_height;
     }
 
     gl_info->gl_ops.gl.p_glDepthRange(vp.min_z, vp.max_z);
-    checkGLcall("glDepthRange");
 
     if (context->render_offscreen)
     {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index f085f2d8b85e..1c4c3ef2b49a 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2533,6 +2533,9 @@ struct wined3d_gl_limits
 
     unsigned int texture_buffer_offset_alignment;
 
+    unsigned int framebuffer_width;
+    unsigned int framebuffer_height;
+
     UINT glsl_varyings;
     UINT glsl_vs_float_constants;
     UINT glsl_ps_float_constants;
-- 
2.16.1




More information about the wine-devel mailing list