Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45978 Signed-off-by: Paul Gofman gofmanp@gmail.com --- dlls/d3d9/tests/visual.c | 162 +++++++++++++++++++++++++++++++++ dlls/wined3d/adapter_gl.c | 7 ++ dlls/wined3d/context.c | 45 +++++++++ dlls/wined3d/wined3d_gl.h | 2 + dlls/wined3d/wined3d_private.h | 3 +- 5 files changed, 218 insertions(+), 1 deletion(-)
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index 5823fe3cbc..b5993678c6 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -26683,6 +26683,167 @@ 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) + { + while (IDirect3DQuery9_GetData(event_query, NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) + ; + + 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) { @@ -26830,4 +26991,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 5e88642f20..4a99786c3b 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) @@ -3409,6 +3415,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..f7fcf1b9b5 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -3687,6 +3687,23 @@ static void context_update_stream_info(struct wined3d_context *context, const st } }
+static void context_texture_check_fbo_attached(struct wined3d_context *context, + const struct wined3d_state *state, const struct wined3d_resource *resource) +{ + struct wined3d_rendertarget_view * const *rts = &state->fb->render_targets[0]; + unsigned int i; + + for (i = 0; i < MAX_RENDER_TARGET_VIEWS; ++i) + if (rts[i] && rts[i]->resource == resource) + { + context->uses_fbo_attached_resources = 1; + return; + } + + if (state->fb->depth_stencil && state->fb->depth_stencil->resource == resource) + context->uses_fbo_attached_resources = 1; +} + /* Context activation is done by the caller. */ static void context_preload_texture(struct wined3d_context *context, const struct wined3d_state *state, unsigned int idx) @@ -3696,6 +3713,8 @@ static void context_preload_texture(struct wined3d_context *context, if (!(texture = state->textures[idx])) return;
+ context_texture_check_fbo_attached(context, state, &texture->resource); + wined3d_texture_load(texture, context, is_srgb_enabled(state->sampler_states[idx])); }
@@ -3929,6 +3948,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 +5005,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 d30e4107a2..91d6ba42bf 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1969,6 +1969,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; @@ -1977,7 +1978,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;
On Mon, 21 Oct 2019 at 15:53, Paul Gofman gofmanp@gmail.com wrote:
+static void context_texture_check_fbo_attached(struct wined3d_context *context,
const struct wined3d_state *state, const struct wined3d_resource *resource)
+{
- struct wined3d_rendertarget_view * const *rts = &state->fb->render_targets[0];
- unsigned int i;
- for (i = 0; i < MAX_RENDER_TARGET_VIEWS; ++i)
if (rts[i] && rts[i]->resource == resource)
{
context->uses_fbo_attached_resources = 1;
return;
}
This can only happen if the resource has WINED3D_BIND_RENDER_TARGET.
- if (state->fb->depth_stencil && state->fb->depth_stencil->resource == resource)
context->uses_fbo_attached_resources = 1;
And this can only happen for resources with WINED3D_BIND_DEPTH_STENCIL. It may not be worth checking for that individually since it's only a single bind point, but if the resource has neither WINED3D_BIND_RENDER_TARGET nor WINED3D_BIND_DEPTH_STENCIL, you wouldn't need to call context_texture_check_fbo_attached() at all.
Note that this doesn't handle resources bound through SRVs. I don't know for sure whether it should, but it doesn't seem unlikely.
On 10/21/19 15:47, Henri Verbeet wrote:
On Mon, 21 Oct 2019 at 15:53, Paul Gofman gofmanp@gmail.com wrote:
+static void context_texture_check_fbo_attached(struct wined3d_context *context,
const struct wined3d_state *state, const struct wined3d_resource *resource)
+{
- struct wined3d_rendertarget_view * const *rts = &state->fb->render_targets[0];
- unsigned int i;
- for (i = 0; i < MAX_RENDER_TARGET_VIEWS; ++i)
if (rts[i] && rts[i]->resource == resource)
{
context->uses_fbo_attached_resources = 1;
return;
}
This can only happen if the resource has WINED3D_BIND_RENDER_TARGET.
- if (state->fb->depth_stencil && state->fb->depth_stencil->resource == resource)
context->uses_fbo_attached_resources = 1;
And this can only happen for resources with WINED3D_BIND_DEPTH_STENCIL. It may not be worth checking for that individually since it's only a single bind point, but if the resource has neither WINED3D_BIND_RENDER_TARGET nor WINED3D_BIND_DEPTH_STENCIL, you wouldn't need to call context_texture_check_fbo_attached() at all.
Yeah, sure, I will improve this.
Note that this doesn't handle resources bound through SRVs. I don't know for sure whether it should, but it doesn't seem unlikely.
I did not test this with d3d10+ yet, but I suspect it might behave differently, so I intentionally tried not to touch it behaviour here. I read somewhere that d3d11 silently unbinds texture if it is bound to output through RTV, but this of course need to verified.
On Mon, 21 Oct 2019 at 16:25, Paul Gofman gofmanp@gmail.com wrote:
Note that this doesn't handle resources bound through SRVs. I don't know for sure whether it should, but it doesn't seem unlikely.
I did not test this with d3d10+ yet, but I suspect it might behave differently, so I intentionally tried not to touch it behaviour here. I read somewhere that d3d11 silently unbinds texture if it is bound to output through RTV, but this of course need to verified.
Yes, it's fine to not touch SRVs in this patch, but it would be a shame not to investigate.
On 10/21/19 15:59, Henri Verbeet wrote:
On Mon, 21 Oct 2019 at 16:25, Paul Gofman gofmanp@gmail.com wrote:
Note that this doesn't handle resources bound through SRVs. I don't know for sure whether it should, but it doesn't seem unlikely.
I did not test this with d3d10+ yet, but I suspect it might behave differently, so I intentionally tried not to touch it behaviour here. I read somewhere that d3d11 silently unbinds texture if it is bound to output through RTV, but this of course need to verified.
Yes, it's fine to not touch SRVs in this patch, but it would be a shame not to investigate.
I will test it before resending the patch.