Hi, Here is a first shot at implementing depth/stencil buffer locking in wined3d.
Currently depth/stencil buffer locations are onscreen and offscreen, with transitions between the two states done in load_ds_location. I added another location, sysmem, and implemented transitions from offscreen to sysmem and from sysmem to offscreen. If buffer is onscreen, it will be moved offscreen first, then to sysmem. Some issues with this implementation: 1) make dsurface.ok in ddraw/tests crashes in context_acquire (wined3d/context.c:2456) called from surface_load_location (wined3d/surface.c:6323), I'm guessing in because there is no swapchain. How can I prevent this crash and still get a context? Loading from offscreen to sysmem shouldn't require a swapchain. 2) When running my test app [1] I also get this error: err:d3d_surface:surface_load_ds_location >>>>>>>>>>>>>>>>> GL_INVALID_VALUE (0x501) from glTexSubImage2D @ ../../../../wine/dlls/wined3d/surface.c / 5877 3) There are other issues with my test app (looks like it's related to textures), so can't be sure if locking works correctly. There is an improvement over the unpatched version, but can't be sure until the other issue is resolved. Game uses pre-rendered backgrounds and probably loads the Z-buffer by locking the surface, so it can render 3D characters correctly over the pre-rendered backgrounds. It happens in the "if (surface->flags & SFLAG_DS_SYSMEM)" branch of the surface_load_ds_location function. Uploading happens on each frame, this error only happens for the first upload. I'm quite new to wined3d code so I might have missed some obvious things. Any comments and suggestions are welcome. Thanks. Octavian [1] The demo of The Longest Journey, available for download here (to reproduce, click on the Begin Journey, press ESC to skip intro movies; notice how rendered characters look): http://games.softpedia.com/get/Games-Demo/The-Longest-Journey-161-Demo.shtml
From a8367fd5229d153ecbcd8a14f6a5a577758d709b Mon Sep 17 00:00:00 2001 From: Octavian Voicu <[email protected]> Date: Wed, 2 Nov 2011 09:45:43 +0200 Subject: wined3d: Implement depth/stencil locking support. Reply-To: wine-devel <[email protected]> --- dlls/wined3d/surface.c | 130 ++++++++++++++++++++++++++++++++++++++-- dlls/wined3d/wined3d_private.h | 4 +- 2 files changed, 128 insertions(+), 6 deletions(-) diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index e3c77da..b9bd12f 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -1020,7 +1020,11 @@ static void surface_unmap(struct wined3d_surface *surface) } else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)) { - FIXME("Depth / stencil buffer locking is not implemented.\n"); + surface_modify_ds_location(surface, SFLAG_DS_SYSMEM, surface->ds_current_size.cx, surface->ds_current_size.cy); + surface_load_location(surface, surface->draw_binding, NULL); + surface_modify_location(surface, surface->draw_binding, TRUE); + surface_evict_sysmem(surface); + surface_modify_ds_location(surface, SFLAG_DS_OFFSCREEN, surface->ds_current_size.cx, surface->ds_current_size.cy); } done: @@ -5712,7 +5716,7 @@ void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_co return; } - if (location == SFLAG_DS_OFFSCREEN) + if (surface->flags & SFLAG_DS_ONSCREEN) { GLint old_binding = 0; GLenum bind_target; @@ -5778,8 +5782,114 @@ void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_co LEAVE_GL(); if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ + + w = surface->resource.width; + h = surface->resource.height; + } + + if (location == SFLAG_DS_SYSMEM) + { + const struct wined3d_gl_info *gl_info = context->gl_info; + GLenum gl_format = surface->resource.format->glFormat; + GLenum gl_type = surface->resource.format->glType; + GLint old_binding = 0; + GLenum bind_target; + + TRACE("Downloading depth texture to sysmem depth buffer.\n"); + + surface_prepare_system_memory(surface); + + ENTER_GL(); + + if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB) + { + glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding); + bind_target = GL_TEXTURE_RECTANGLE_ARB; + } + else + { + glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding); + bind_target = GL_TEXTURE_2D; + } + glBindTexture(bind_target, surface->texture_name); + + if (surface->flags & SFLAG_PBO) + { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo)); + checkGLcall("glBindBufferARB"); + + glGetTexImage(surface->texture_target, surface->texture_level, gl_format, gl_type, NULL); + checkGLcall("glGetTexImage"); + + GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + } + else + { + glGetTexImage(surface->texture_target, surface->texture_level, gl_format, gl_type, + surface->resource.allocatedMemory); + checkGLcall("glGetTexImage"); + } + + glBindTexture(bind_target, old_binding); + + LEAVE_GL(); + + if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ } - else if (location == SFLAG_DS_ONSCREEN) + + if (surface->flags & SFLAG_DS_SYSMEM) + { + const struct wined3d_gl_info *gl_info = context->gl_info; + GLenum gl_format = surface->resource.format->glFormat; + GLenum gl_type = surface->resource.format->glType; + UINT byte_count = surface->resource.format->byte_count; + UINT pitch = wined3d_surface_get_pitch(surface); + GLint old_binding = 0; + GLenum bind_target; + + TRACE("Uploading sysmem depth buffer to depth texture.\n"); + + ENTER_GL(); + + if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB) + { + glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding); + bind_target = GL_TEXTURE_RECTANGLE_ARB; + } + else + { + glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding); + bind_target = GL_TEXTURE_2D; + } + glBindTexture(bind_target, surface->texture_name); + + if (surface->pbo) + { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo)); + checkGLcall("glBindBufferARB"); + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / byte_count); + glTexSubImage2D(surface->texture_target, surface->texture_level, 0, 0, w, h, + gl_format, gl_type, surface->resource.allocatedMemory); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + checkGLcall("glTexSubImage2D"); + + if (surface->pbo) + { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + } + + glBindTexture(bind_target, old_binding); + + LEAVE_GL(); + + if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ + } + + if (location == SFLAG_DS_ONSCREEN) { TRACE("Copying depth texture to onscreen depth buffer.\n"); @@ -5797,12 +5907,13 @@ void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_co if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */ } - else + + if (!(location & SFLAG_DS_LOCATIONS)) { ERR("Invalid location (%#x) specified.\n", location); } - surface->flags |= location; + surface->flags |= location | SFLAG_DS_OFFSCREEN; surface->ds_current_size.cx = surface->resource.width; surface->ds_current_size.cy = surface->resource.height; } @@ -6207,6 +6318,15 @@ HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, c context_release(context); return WINED3D_OK; } + else if (location == SFLAG_INSYSMEM) + { + struct wined3d_context *context = context_acquire(device, NULL); + if (surface->flags & SFLAG_DS_ONSCREEN) + FIXME("Depth/stencil buffer is onscreen on lock, will be moved offscreen on unlock.\n"); + surface_load_ds_location(surface, context, SFLAG_DS_SYSMEM); + context_release(context); + return WINED3D_OK; + } else { FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location)); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 26be952..04da561 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2141,6 +2141,7 @@ void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back) D #define SFLAG_INRB_RESOLVED 0x00400000 /* The resolved renderbuffer is current. */ #define SFLAG_DS_ONSCREEN 0x00800000 /* This is a depth / stencil surface, last modified onscreen. */ #define SFLAG_DS_OFFSCREEN 0x01000000 /* This is a depth / stencil surface, last modified offscreen. */ +#define SFLAG_DS_SYSMEM 0x02000000 /* This is a depth / stencil surface, last modified sysmem. */ /* In some conditions the surface memory must not be freed: * SFLAG_CONVERTED: Converting the data back would take too long @@ -2166,7 +2167,8 @@ void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back) D SFLAG_INRB_RESOLVED) #define SFLAG_DS_LOCATIONS (SFLAG_DS_ONSCREEN | \ - SFLAG_DS_OFFSCREEN) + SFLAG_DS_OFFSCREEN | \ + SFLAG_DS_SYSMEM) #define SFLAG_DS_DISCARDED SFLAG_DS_LOCATIONS typedef enum { -- 1.7.4.1
