diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index e7076aeed61..ebec6dc27d0 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -33,7 +33,7 @@ #define COBJMACROS #include -#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 ed1022030bc..e83aebfa56f 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 9cd6a6e3de6..e9750c41c50 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 678ad1a4ef2..3372b4b6be3 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 307f7a42ade..88833aef709 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"