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



Reply via email to