[PATCH v4 2/3] wined3d: Issue texture barrier before using a texture attached to FBO.

Paul Gofman gofmanp at gmail.com
Wed Oct 23 11:44:58 CDT 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45978
Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
    v4:
        - use wait_query function.

 dlls/d3d9/tests/visual.c       | 163 ++++++++++++++++++++++++++++++++-
 dlls/wined3d/adapter_gl.c      |   7 ++
 dlls/wined3d/context.c         |  29 ++++++
 dlls/wined3d/wined3d_gl.h      |   2 +
 dlls/wined3d/wined3d_private.h |  23 ++++-
 5 files changed, 222 insertions(+), 2 deletions(-)

diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index e7076aeed6..ebec6dc27d 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -33,7 +33,7 @@
 
 #define COBJMACROS
 #include <d3d9.h>
-#include "wine/test.h"
+#include "utils.h"
 #include "wine/heap.h"
 
 struct vec2
@@ -26263,6 +26263,166 @@ static void test_draw_mapped_buffer(void)
     DestroyWindow(window);
 }
 
+static void test_sample_attached_rendertarget(void)
+{
+    D3DADAPTER_IDENTIFIER9 identifier;
+    IDirect3DQuery9 *event_query;
+    IDirect3DTexture9 *texture;
+    IDirect3DVertexBuffer9 *vb;
+    IDirect3DPixelShader9 *ps;
+    IDirect3DDevice9 *device;
+    IDirect3DSurface9 *rt;
+    IDirect3D9 *d3d;
+    unsigned int i;
+    ULONG refcount;
+    D3DCOLOR color;
+    BOOL is_warp;
+    HWND window;
+    HRESULT hr;
+    void *data;
+
+    static const struct
+    {
+        struct vec3 posistion;
+        struct vec2 texcoord;
+    }
+    quad[] =
+    {
+        {{-1.0f, -1.0f, 0.1f}, {0.0f, 0.0f}},
+        {{-1.0f,  1.0f, 0.1f}, {0.0f, 1.0f}},
+        {{ 1.0f, -1.0f, 0.0f}, {1.0f, 0.0f}},
+        {{ 1.0f,  1.0f, 0.1f}, {1.0f, 1.0f}},
+    };
+
+    static const DWORD pixel_shader_code[] =
+    {
+        0xffff0200,                                                 /* ps_2_0                 */
+        0x05000051, 0xa00f0000, 0x3e800000, 0x3e800000, 0x3e800000, 0x3e800000,
+                /* def c0, 0.25, 0.25, 0.25, 0.25 */
+        0x0200001f, 0x80000000, 0xb00f0000,                         /* dcl t0                 */
+        0x0200001f, 0x90000000, 0xa00f0800,                         /* dcl_2d s0              */
+        0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800,             /* texld r0, t0, s0       */
+        0x03000002, 0x800f0000, 0x80e40000, 0xa0e40000,             /* add r0, r0, c0         */
+        0x02000001, 0x800f0800, 0x80e40000,                         /* mov oC0, r0            */
+        0x0000ffff
+    };
+
+    window = create_window();
+    ok(!!window, "Failed to create a window.\n");
+
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    ok(!!d3d, "Failed to create a D3D object.\n");
+
+    hr = IDirect3D9_GetAdapterIdentifier(d3d, D3DADAPTER_DEFAULT, 0, &identifier);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    is_warp = adapter_is_warp(&identifier);
+
+    if (!(device = create_device(d3d, window, window, TRUE)))
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        IDirect3D9_Release(d3d);
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice9_CreateQuery(device, D3DQUERYTYPE_EVENT, NULL);
+    if (hr == D3DERR_NOTAVAILABLE)
+    {
+        /* Without synchronization native d3d seems to show race condition on
+         * render target update, similar to opengl without using texture barrier. */
+        skip("Event queries are not supported, skipping test.\n");
+        IDirect3DDevice9_Release(device);
+        IDirect3D9_Release(d3d);
+        DestroyWindow(window);
+        return;
+   }
+
+    hr = IDirect3DDevice9_CreateQuery(device, D3DQUERYTYPE_EVENT, &event_query);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DQuery9_Issue(event_query, D3DISSUE_END);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_CreateVertexBuffer(device, sizeof(quad), D3DUSAGE_DYNAMIC,
+            D3DFVF_XYZ | D3DFVF_TEX1, D3DPOOL_DEFAULT, &vb, NULL);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    hr = IDirect3DVertexBuffer9_Lock(vb, 0, sizeof(quad), &data, 0);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    memcpy(data, quad, sizeof(quad));
+    hr = IDirect3DVertexBuffer9_Unlock(vb);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetStreamSource(device, 0, vb, 0, sizeof(quad[0]));
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_TEX1);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, FALSE);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_CreateTexture(device, 64, 64, 1, D3DUSAGE_RENDERTARGET,
+            D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, NULL);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    hr = IDirect3DTexture9_GetSurfaceLevel(texture, 0, &rt);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetRenderTarget(device, 0, rt);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetTexture(device, 0, (IDirect3DBaseTexture9 *)texture);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0x01010101, 0.0, 0);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    check_rt_color(rt, 0x00010101);
+
+    hr = IDirect3DDevice9_CreatePixelShader(device, pixel_shader_code, &ps);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_BeginScene(device);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetPixelShader(device, ps);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    for (i = 0; i < 3; ++i)
+    {
+        wait_query(event_query);
+
+        hr = IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, 0, 2);
+        ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+        IDirect3DQuery9_Issue(event_query, D3DISSUE_END);
+        ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+    }
+
+    hr = IDirect3DDevice9_EndScene(device);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+    ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+    color = getPixelColor(device, 0, 0);
+    if (is_warp || color == 0x00010101)
+        skip("Sampling attached render targets is not supported.\n");
+    else
+        check_rt_color(rt, 0x00c1c1c1);
+
+    IDirect3DQuery9_Release(event_query);
+
+    IDirect3DVertexBuffer9_Release(vb);
+
+    IDirect3DPixelShader9_Release(ps);
+    IDirect3DSurface9_Release(rt);
+    IDirect3DTexture9_Release(texture);
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+
+    IDirect3D9_Release(d3d);
+    DestroyWindow(window);
+}
 
 START_TEST(visual)
 {
@@ -26409,4 +26569,5 @@ START_TEST(visual)
     test_desktop_window();
     test_mismatched_sample_types();
     test_draw_mapped_buffer();
+    test_sample_attached_rendertarget();
 }
diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c
index ed1022030b..e83aebfa56 100644
--- a/dlls/wined3d/adapter_gl.c
+++ b/dlls/wined3d/adapter_gl.c
@@ -159,6 +159,7 @@ static const struct wined3d_extension_map gl_extension_map[] =
     {"GL_ARB_vertex_shader",                ARB_VERTEX_SHADER             },
     {"GL_ARB_vertex_type_2_10_10_10_rev",   ARB_VERTEX_TYPE_2_10_10_10_REV},
     {"GL_ARB_viewport_array",               ARB_VIEWPORT_ARRAY            },
+    {"GL_ARB_texture_barrier",              ARB_TEXTURE_BARRIER           },
 
     /* ATI */
     {"GL_ATI_fragment_shader",              ATI_FRAGMENT_SHADER           },
@@ -228,6 +229,7 @@ static const struct wined3d_extension_map gl_extension_map[] =
     {"GL_NV_vertex_program2",               NV_VERTEX_PROGRAM2            },
     {"GL_NV_vertex_program2_option",        NV_VERTEX_PROGRAM2_OPTION     },
     {"GL_NV_vertex_program3",               NV_VERTEX_PROGRAM3            },
+    {"GL_NV_texture_barrier",               NV_TEXTURE_BARRIER            },
 };
 
 static const struct wined3d_extension_map wgl_extension_map[] =
@@ -2454,6 +2456,8 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info)
     USE_GL_FUNC(glViewportArrayv)
     USE_GL_FUNC(glViewportIndexedf)
     USE_GL_FUNC(glViewportIndexedfv)
+    /* GL_ARB_texture_barrier */
+    USE_GL_FUNC(glTextureBarrier);
     /* GL_ATI_fragment_shader */
     USE_GL_FUNC(glAlphaFragmentOp1ATI)
     USE_GL_FUNC(glAlphaFragmentOp2ATI)
@@ -2644,6 +2648,8 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info)
     USE_GL_FUNC(glCombinerParameteriNV)
     USE_GL_FUNC(glCombinerParameterivNV)
     USE_GL_FUNC(glFinalCombinerInputNV)
+    /* GL_NV_texture_barrier */
+    USE_GL_FUNC(glTextureBarrierNV);
     /* WGL extensions */
     USE_GL_FUNC(wglChoosePixelFormatARB)
     USE_GL_FUNC(wglGetExtensionsStringARB)
@@ -3406,6 +3412,7 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter,
         {ARB_CULL_DISTANCE,                MAKEDWORD_VERSION(4, 5)},
         {ARB_DERIVATIVE_CONTROL,           MAKEDWORD_VERSION(4, 5)},
         {ARB_SHADER_TEXTURE_IMAGE_SAMPLES, MAKEDWORD_VERSION(4, 5)},
+        {ARB_TEXTURE_BARRIER,              MAKEDWORD_VERSION(4, 5)},
 
         {ARB_PIPELINE_STATISTICS_QUERY,    MAKEDWORD_VERSION(4, 6)},
         {ARB_POLYGON_OFFSET_CLAMP,         MAKEDWORD_VERSION(4, 6)},
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 9cd6a6e3de..e9750c41c5 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -3696,6 +3696,9 @@ static void context_preload_texture(struct wined3d_context *context,
     if (!(texture = state->textures[idx]))
         return;
 
+    if (wined3d_resource_check_fbo_attached(state, &texture->resource))
+        context->uses_fbo_attached_resources = 1;
+
     wined3d_texture_load(texture, context, is_srgb_enabled(state->sampler_states[idx]));
 }
 
@@ -3929,6 +3932,8 @@ static BOOL context_apply_draw_state(struct wined3d_context *context,
     unsigned int i, base;
     WORD map;
 
+    context->uses_fbo_attached_resources = 0;
+
     if (!have_framebuffer_attachment(gl_info->limits.buffers, fb->render_targets, fb->depth_stencil))
     {
         if (!gl_info->supported[ARB_FRAMEBUFFER_NO_ATTACHMENTS])
@@ -4984,6 +4989,30 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s
         checkGLcall("glPatchParameteri");
     }
 
+    if (context->uses_fbo_attached_resources)
+    {
+        static unsigned int fixme_once;
+
+        if (gl_info->supported[ARB_TEXTURE_BARRIER])
+        {
+            GL_EXTCALL(glTextureBarrier());
+        }
+        else if (gl_info->supported[NV_TEXTURE_BARRIER])
+        {
+            GL_EXTCALL(glTextureBarrierNV());
+        }
+        else
+        {
+            if (!fixme_once++)
+                FIXME("Sampling attached render targets is not supported.\n");
+
+            WARN("Sampling attached render targets is not supported, skipping draw.\n");
+            context_release(context);
+            return;
+        }
+        checkGLcall("glTextureBarrier");
+    }
+
     if (parameters->indirect)
     {
         if (!context->use_immediate_mode_draw && !emulation)
diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h
index 678ad1a4ef..3372b4b6be 100644
--- a/dlls/wined3d/wined3d_gl.h
+++ b/dlls/wined3d/wined3d_gl.h
@@ -142,6 +142,7 @@ enum wined3d_gl_extension
     ARB_VERTEX_SHADER,
     ARB_VERTEX_TYPE_2_10_10_10_REV,
     ARB_VIEWPORT_ARRAY,
+    ARB_TEXTURE_BARRIER,
     /* ATI */
     ATI_FRAGMENT_SHADER,
     ATI_SEPARATE_STENCIL,
@@ -204,6 +205,7 @@ enum wined3d_gl_extension
     NV_VERTEX_PROGRAM2,
     NV_VERTEX_PROGRAM2_OPTION,
     NV_VERTEX_PROGRAM3,
+    NV_TEXTURE_BARRIER,
     /* WGL extensions */
     WGL_ARB_PIXEL_FORMAT,
     WGL_EXT_SWAP_CONTROL,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 307f7a42ad..88833aef70 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1961,6 +1961,7 @@ struct wined3d_context
 
     DWORD use_immediate_mode_draw : 1;
     DWORD uses_uavs : 1;
+    DWORD uses_fbo_attached_resources : 1;
     DWORD transform_feedback_active : 1;
     DWORD transform_feedback_paused : 1;
     DWORD fog_coord : 1;
@@ -1969,7 +1970,7 @@ struct wined3d_context
     DWORD destroyed : 1;
     DWORD destroy_delayed : 1;
     DWORD clip_distance_mask : 8; /* WINED3D_MAX_CLIP_DISTANCES, 8 */
-    DWORD padding : 15;
+    DWORD padding : 14;
 
     DWORD constant_update_mask;
     DWORD numbered_array_mask;
@@ -5279,6 +5280,26 @@ static inline void wined3d_context_copy_bo_address(struct wined3d_context *conte
             dst, dst_bind_flags, src, src_bind_flags, size);
 }
 
+static inline BOOL wined3d_resource_check_fbo_attached(const struct wined3d_state *state,
+        const struct wined3d_resource *resource)
+{
+    struct wined3d_rendertarget_view * const *rts = &state->fb->render_targets[0];
+    unsigned int i;
+
+    if ((resource->bind_flags & WINED3D_BIND_DEPTH_STENCIL)
+            && state->fb->depth_stencil && state->fb->depth_stencil->resource == resource)
+        return TRUE;
+
+    if (!(resource->bind_flags & WINED3D_BIND_RENDER_TARGET))
+        return FALSE;
+
+    for (i = 0; i < MAX_RENDER_TARGET_VIEWS; ++i)
+        if (rts[i] && rts[i]->resource == resource)
+            return TRUE;
+
+    return FALSE;
+}
+
 /* The WNDCLASS-Name for the fake window which we use to retrieve the GL capabilities */
 #define WINED3D_OPENGL_WINDOW_CLASS_NAME "WineD3D_OpenGL"
 
-- 
2.21.0




More information about the wine-devel mailing list