[D3D] Add ZBuffer locking support

Lionel Ulmer lionel.ulmer at free.fr
Sat Sep 13 13:36:40 CDT 2003


This makes Grim Fandango almost work in D3D mode... When I say 'almost' is
because it is abysmally slow (which I find strange as the same Z buffer
write code seems to work relatively fast in Residual).

Anyway, I would be interested to know what people experience on their boxes
:-)

        Lionel

Changelog:
 - add ZBuffer write support
 - some TRACEing fixes

-- 
		 Lionel Ulmer - http://www.bbrox.org/
-------------- next part --------------
--- dlls/ddraw_CVS/d3d_private.h	Wed Jun 18 23:14:02 2003
+++ dlls/ddraw/d3d_private.h	Tue Sep  9 21:53:23 2003
@@ -199,7 +199,8 @@
     D3DVIEWPORT7 active_viewport;
 
     IDirectDrawSurfaceImpl *current_texture[MAX_TEXTURES];
-
+    IDirectDrawSurfaceImpl *current_zbuffer;
+    
     /* Current transformation matrices */
     D3DMATRIX *world_mat;
     D3DMATRIX *view_mat;
--- dlls/ddraw_CVS/d3ddevice/mesa.c	Fri Aug 22 22:42:24 2003
+++ dlls/ddraw/d3ddevice/mesa.c	Thu Sep 11 22:12:50 2003
@@ -1093,6 +1093,54 @@
     return ret_value;
 }
 
+static void flush_zbuffer_to_GL(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
+    static BOOLEAN first = TRUE;
+    IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
+    int row;
+    GLenum type;
+    
+    if (first == TRUE) {
+	MESSAGE("Warning : application does direct locking of ZBuffer - expect slowdowns on many GL implementations :-)\n");
+	first = FALSE;
+    }
+    
+    TRACE("flushing ZBuffer back to GL\n");
+    
+    if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
+	gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
+	d3ddevice_set_ortho(d3d_dev);
+    }
+    
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    if (gl_d3d_dev->depth_test == 0) glEnable(GL_DEPTH_TEST);
+    if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS) glDepthFunc(GL_ALWAYS);
+    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 
+
+    /* This loop here is to prevent using PixelZoom that may be unoptimized for the 1.0 / -1.0 case
+       in some drivers...
+    */
+    switch (surf->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth) {
+        case 16: type = GL_UNSIGNED_SHORT; break;
+	case 32: type = GL_UNSIGNED_INT; break;
+	default: FIXME("Unhandled ZBuffer format !\n"); goto restore_state;
+    }
+	
+    for (row = 0; row < surf->surface_desc.dwHeight; row++) {
+	// glRasterPos3d(0.0, row + 1.0, 0.5);
+	glRasterPos2i(0, row + 1);
+	glDrawPixels(surf->surface_desc.dwWidth, 1, GL_DEPTH_COMPONENT, type,
+		     ((unsigned char *) surf->surface_desc.lpSurface) + (row * surf->surface_desc.u1.lPitch));
+    }
+
+  restore_state:
+    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+    if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS)
+	glDepthFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1]));
+    if (gl_d3d_dev->depth_test == 0) glDisable(GL_DEPTH_TEST);
+}
+
 /* These are the various handler used in the generic path */
 inline static void handle_xyz(D3DVALUE *coords) {
     glVertex3fv(coords);
@@ -1248,8 +1296,26 @@
     if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
         This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
     }
-
     glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
+
+    if (This->current_zbuffer == NULL) {
+	/* Search for an attached ZBuffer */
+	static const DDSCAPS2 zbuf_caps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
+	LPDIRECTDRAWSURFACE7 zbuf;
+	HRESULT hr;
+	
+	hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->surface, IDirectDrawSurface7),
+						    (DDSCAPS2 *) &zbuf_caps, &zbuf);
+	if (!FAILED(hr)) {
+	    This->current_zbuffer = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, zbuf);
+	    IDirectDrawSurface7_Release(zbuf);
+	}
+    }
+    if (This->current_zbuffer != NULL) {
+	if (This->current_zbuffer->get_dirty_status(This->current_zbuffer, NULL)) {
+	    flush_zbuffer_to_GL(This, NULL, This->current_zbuffer);
+	}
+    }
     
     /* Just a hack for now.. Will have to find better algorithm :-/ */
     if ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
@@ -1267,7 +1333,6 @@
 	glThis->current_active_tex_unit = GL_TEXTURE0_WINE;
     }
 
-    
     draw_primitive_handle_GL_state(This,
 				   (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
 				   vertex_lighted);
@@ -3157,11 +3222,11 @@
        to OpenGL screen coordinates (ie the upper left corner is not the same).
        For Z, the mystery is what should it be mapped to ? Ie should the resulting range be between
        -1.0 and 1.0 (as the X and Y coordinates) or between 0.0 and 1.0 ? */
-    trans_mat[ 0] = 2.0 / width;  trans_mat[ 4] = 0.0;  trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
-    trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] =  1.0;
-    trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0;           trans_mat[14] = -1.0;
-    trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0;           trans_mat[15] =  1.0;
-
+    trans_mat[ 0] = 2.0 / width;  trans_mat[ 4] = 0.0;           trans_mat[ 8] = 0.0;    trans_mat[12] = -1.0;
+    trans_mat[ 1] = 0.0;          trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0;    trans_mat[13] =  1.0;
+    trans_mat[ 2] = 0.0;          trans_mat[ 6] = 0.0;           trans_mat[10] = 2.0;    trans_mat[14] = -1.0;
+    trans_mat[ 3] = 0.0;          trans_mat[ 7] = 0.0;           trans_mat[11] = 0.0;    trans_mat[15] =  1.0;
+    
     ENTER_GL();
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
@@ -3871,6 +3936,7 @@
 static void fill_caps(void)
 {
     GLint max_clip_planes;
+    GLint depth_bits;
     
     /* Fill first all the fields with default values which will be overriden later on with
        correct ones from the GL code
@@ -3883,7 +3949,6 @@
     fill_opengl_primcaps(&(opengl_device_caps.dpcLineCaps));
     fill_opengl_primcaps(&(opengl_device_caps.dpcTriCaps));
     opengl_device_caps.dwDeviceRenderBitDepth  = DDBD_16|DDBD_24|DDBD_32;
-    opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32;
     opengl_device_caps.dwMinTextureWidth  = 1;
     opengl_device_caps.dwMinTextureHeight = 1;
     opengl_device_caps.dwMaxTextureWidth  = 1024;
@@ -3934,6 +3999,15 @@
     glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
     opengl_device_caps.wMaxUserClipPlanes = max_clip_planes;
     TRACE(": max clipping planes = %d\n", opengl_device_caps.wMaxUserClipPlanes);
+
+    glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
+    TRACE(": Z bits = %d\n", depth_bits);
+    switch (depth_bits) {
+        case 16: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16; break;
+        case 24: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_24; break;
+	case 32: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_32; break;
+	default: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32; break;
+    }
 }
 
 BOOL
--- dlls/ddraw_CVS/ddraw_private.h	Fri Jun  6 21:24:12 2003
+++ dlls/ddraw/ddraw_private.h	Tue Sep  9 22:17:10 2003
@@ -320,6 +320,7 @@
     LPVOID tex_private;
     void (*lock_update_prev)(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags);
     void (*unlock_update_prev)(IDirectDrawSurfaceImpl* This, LPCRECT pRect);
+    BOOLEAN (*get_dirty_status)(IDirectDrawSurfaceImpl* This, LPCRECT pRect);
 };
 
 /*****************************************************************************
--- dlls/ddraw_CVS/dsurface/fakezbuffer.c	Fri Jun  6 21:24:12 2003
+++ dlls/ddraw/dsurface/fakezbuffer.c	Tue Sep  9 22:24:12 2003
@@ -44,12 +44,34 @@
 
 static ICOM_VTABLE(IDirectDrawSurface7) FakeZBuffer_IDirectDrawSurface7_VTable;
 
+#ifdef HAVE_OPENGL
+static void zbuffer_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
+{
+    /* Note that this does not do anything for now... At least it's not needed for Grim Fandango :-) */
+}
+
+static void zbuffer_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
+{
+    ((FakeZBuffer_DirectDrawSurfaceImpl *) This->private)->in_memory = TRUE;
+}
+
+static BOOLEAN zbuffer_get_dirty_status(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
+{
+    if (((FakeZBuffer_DirectDrawSurfaceImpl *) This->private)->in_memory == TRUE) {
+	((FakeZBuffer_DirectDrawSurfaceImpl *) This->private)->in_memory = FALSE;
+	return TRUE;
+    }
+    return FALSE;
+}
+#endif
+
 HRESULT FakeZBuffer_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl *This,
 						IDirectDrawImpl *pDD,
 						const DDSURFACEDESC2 *pDDSD)
 {
     HRESULT hr;
-
+    BYTE zdepth = 16; /* Default value.. Should use the one from GL */
+    
     assert(pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER);
 
     hr = Main_DirectDrawSurface_Construct(This, pDD, pDDSD);
@@ -61,6 +83,33 @@
     This->final_release = FakeZBuffer_DirectDrawSurface_final_release;
     This->duplicate_surface = FakeZBuffer_DirectDrawSurface_duplicate_surface;
 
+#ifdef HAVE_OPENGL     
+    if (opengl_initialized) {
+	This->lock_update = zbuffer_lock_update;
+	This->unlock_update = zbuffer_unlock_update;
+	This->get_dirty_status = zbuffer_get_dirty_status;
+    }
+#endif
+	
+    
+    /* Beginning of some D3D hacks :-) */
+    if (This->surface_desc.dwFlags & DDSD_ZBUFFERBITDEPTH) {
+	zdepth = This->surface_desc.u2.dwMipMapCount; /* This is where the Z buffer depth is stored in 'old' versions */
+    }
+    
+    if ((This->surface_desc.dwFlags & DDSD_PIXELFORMAT) == 0) {
+	This->surface_desc.dwFlags |= DDSD_PIXELFORMAT;
+	This->surface_desc.u4.ddpfPixelFormat.dwSize = sizeof(This->surface_desc.u4.ddpfPixelFormat);
+	This->surface_desc.u4.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
+	This->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth = zdepth;
+    }
+    if ((This->surface_desc.dwFlags & DDSD_PITCH) == 0) {
+	This->surface_desc.dwFlags |= DDSD_PITCH;
+	This->surface_desc.u1.lPitch = ((zdepth + 7) / 8) * This->surface_desc.dwWidth;
+    }
+    This->surface_desc.lpSurface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+					     This->surface_desc.u1.lPitch * This->surface_desc.dwHeight);
+    
     return DD_OK;
 }
 
--- dlls/ddraw_CVS/dsurface/fakezbuffer.h	Tue Jul 23 20:39:11 2002
+++ dlls/ddraw/dsurface/fakezbuffer.h	Tue Sep  9 21:50:49 2003
@@ -19,14 +19,9 @@
 #ifndef DDRAW_DSURFACE_FAKEZBUFFER_H_INCLUDED
 #define DDRAW_DSURFACE_FAKEZBUFFER_H_INCLUDED
 
-struct FakeZBuffer_DirectDrawSurfaceImpl_Part
-{
-  int dummy;
-};
-
 typedef struct
 {
-    struct FakeZBuffer_DirectDrawSurfaceImpl_Part fakezbuffer;
+    BOOLEAN in_memory;
 } FakeZBuffer_DirectDrawSurfaceImpl;
 
 HRESULT
--- dlls/ddraw_CVS/gl_api.h	Sat Aug  9 12:06:51 2003
+++ dlls/ddraw/gl_api.h	Thu Sep 11 21:57:28 2003
@@ -38,6 +38,7 @@
 GL_API_FUNCTION(glColor3f)
 GL_API_FUNCTION(glColor3ub)
 GL_API_FUNCTION(glColor4ub)
+GL_API_FUNCTION(glColorMask)
 GL_API_FUNCTION(glColorMaterial)
 GL_API_FUNCTION(glCopyPixels)
 GL_API_FUNCTION(glCopyTexSubImage2D)
@@ -76,11 +77,13 @@
 GL_API_FUNCTION(glMultMatrixf)
 GL_API_FUNCTION(glNormal3f)
 GL_API_FUNCTION(glNormal3fv)
+GL_API_FUNCTION(glOrtho)
 GL_API_FUNCTION(glPixelStorei)
 GL_API_FUNCTION(glPolygonMode)
 GL_API_FUNCTION(glPolygonOffset)
 GL_API_FUNCTION(glPopMatrix)
 GL_API_FUNCTION(glPushMatrix)
+GL_API_FUNCTION(glRasterPos2i)
 GL_API_FUNCTION(glRasterPos3d)
 GL_API_FUNCTION(glReadBuffer)
 GL_API_FUNCTION(glReadPixels)
--- dlls/ddraw_CVS/gl_private.h	Fri Aug 22 22:42:24 2003
+++ dlls/ddraw/gl_private.h	Thu Sep 11 21:57:40 2003
@@ -81,6 +81,7 @@
 #define glColor3f pglColor3f
 #define glColor3ub pglColor3ub
 #define glColor4ub pglColor4ub
+#define glColorMask pglColorMask
 #define glCopyPixels pglCopyPixels
 #define glCopyTexSubImage2D pglCopyTexSubImage2D
 #define glColorMaterial pglColorMaterial
@@ -119,11 +120,13 @@
 #define glMultMatrixf pglMultMatrixf
 #define glNormal3f pglNormal3f
 #define glNormal3fv pglNormal3fv
+#define glOrtho pglOrtho
 #define glPixelStorei pglPixelStorei
 #define glPolygonMode pglPolygonMode
 #define glPolygonOffset pglPolygonOffset
 #define glPopMatrix pglPopMatrix
 #define glPushMatrix pglPushMatrix
+#define glRasterPos2i pglRasterPos2i
 #define glRasterPos3d pglRasterPos3d
 #define glReadBuffer pglReadBuffer
 #define glReadPixels pglReadPixels
--- dlls/ddraw_CVS/helper.c	Fri Aug  1 21:38:18 2003
+++ dlls/ddraw/helper.c	Sun Sep  7 20:21:53 2003
@@ -347,6 +347,7 @@
             ME(DDSD_LINEARSIZE, DDRAW_dump_DWORD, u1.dwLinearSize),
             ME(DDSD_BACKBUFFERCOUNT, DDRAW_dump_DWORD, dwBackBufferCount),
             ME(DDSD_MIPMAPCOUNT, DDRAW_dump_DWORD, u2.dwMipMapCount),
+	    ME(DDSD_ZBUFFERBITDEPTH, DDRAW_dump_DWORD, u2.dwMipMapCount), /* This is for 'old-style' D3D */
             ME(DDSD_REFRESHRATE, DDRAW_dump_DWORD, u2.dwRefreshRate),
             ME(DDSD_ALPHABITDEPTH, DDRAW_dump_DWORD, dwAlphaBitDepth),
             ME(DDSD_LPSURFACE, DDRAW_dump_PTR, lpSurface),


More information about the wine-patches mailing list