Broken character models in dx8/9 games in wined3d

Jason Green jave27 at gmail.com
Wed Jul 26 01:36:08 CDT 2006


Well, we discussed a few different ways of handling this, and here are
the results:

1) We can flip the texture we get from the framebuffer in
Device_LoadTexture.  Getting images from the back framebuffer always
are upside down, so we'll need to manually flip it before setting it
as the next render target.

a) Use glCopyTexSubImage2D() to swap each row

b) Use glReadPixels() to copy to a buffer, flip the image, then use
glTexImage2D() to write it back.

Both of these methods fixed the upside down rendering, but the issue
of the disconnected/broken models is still there, although less
prevalent now that things look more normal to begin with.  I've
attached both patches.  However, performance takes a pretty serious
hit:

Max Payne 2 with pixel shaders enabled in High detail mode (there are
still some lighting bugs, though):
Current git (upside-down):  ~65 fps
1a:  ~35 fps
1b:  ~15 fps

Civ4 with pixel shaders enabled
Current git (some upside-down stuff and very broken models): 30-50 fps
1a (still some broken models):  ~35 fps
1b (still some broken modles):  25-35 fps


2) Try to do some kind of fixup in the shader itself.  I'm not
entirely sure how to do this other than being creative with the small
hack I posted originally.  There are no noticable performance losses,
but visually, some things are broken (the sky in Tomb Raider Legends
as well as Half Life 2 are completely wrong, but Max Payne is about
99% right).

Any other suggestions?  Also, the models are still broke, so that may
be a separate topic and not related like I thought it was.
-------------- next part --------------
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 323a2f5..f0fe2ec 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3463,25 +3463,15 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         case D3DCULL_CW:
             glEnable(GL_CULL_FACE);
             checkGLcall("glEnable GL_CULL_FACE");
-            if (This->renderUpsideDown) {
-                glFrontFace(GL_CW);
-                checkGLcall("glFrontFace GL_CW");
-            } else {
-                glFrontFace(GL_CCW);
-                checkGLcall("glFrontFace GL_CCW");
-            }
+            glFrontFace(GL_CCW);
+            checkGLcall("glFrontFace GL_CCW");
             glCullFace(GL_BACK);
             break;
         case D3DCULL_CCW:
             glEnable(GL_CULL_FACE);
             checkGLcall("glEnable GL_CULL_FACE");
-            if (This->renderUpsideDown) {
-                glFrontFace(GL_CCW);
-                checkGLcall("glFrontFace GL_CCW");
-            } else {
-                glFrontFace(GL_CW);
-                checkGLcall("glFrontFace GL_CW");
-            }
+            glFrontFace(GL_CW);
+            checkGLcall("glFrontFace GL_CW");
             glCullFace(GL_BACK);
             break;
         default:
@@ -7385,28 +7375,9 @@ #endif
     IWineD3DSurface_AddRef(This->renderTarget);
     IWineD3DSurface_Release(tmp);
 
-    {
-        DWORD value;
-
-        /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
-        /* Check that the container is not a swapchain member */
-
-        IWineD3DSwapChain *tmpSwapChain;
-        if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
-            This->renderUpsideDown = TRUE;
-        }else{
-            This->renderUpsideDown = FALSE;
-            IWineD3DSwapChain_Release(tmpSwapChain);
-        }
-        /* Force updating the cull mode */
-        TRACE("setting render state\n");
-        IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
-        IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
-
-        /* Force updating projection matrix */
-        This->last_was_rhw = FALSE;
-        This->proj_valid = FALSE;
-    }
+    /* Force updating projection matrix */
+    This->last_was_rhw = FALSE;
+    This->proj_valid = FALSE;
 
     /* Restore recording state */
     This->isRecordingState = oldRecording;
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index bb48982..485e0fe 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -148,12 +148,6 @@ static void init_materials(IWineD3DDevic
 
 }
 
-static GLfloat invymat[16] = {
-	1.0f, 0.0f, 0.0f, 0.0f,
-	0.0f, -1.0f, 0.0f, 0.0f,
-	0.0f, 0.0f, 1.0f, 0.0f,
-	0.0f, 0.0f, 0.0f, 1.0f};
-
 void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) {
     /* If the last draw was transformed as well, no need to reapply all the matrixes */
     if ( (!This->last_was_rhw) || (This->viewport_changed) ) {
@@ -190,10 +184,6 @@ void d3ddevice_set_ortho(IWineD3DDeviceI
             a pixel (See comment above glTranslate below)                         */
         glTranslatef(0.375, 0.375, 0);
         checkGLcall("glTranslatef(0.375, 0.375, 0)");
-        if (This->renderUpsideDown) {
-            glMultMatrixf(invymat);
-            checkGLcall("glMultMatrixf(invymat)");
-        }
 
         /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */
         if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) {
@@ -295,10 +285,6 @@ static void primitiveInitState(
             glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
             checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
 
-            if (This->renderUpsideDown) {
-                glMultMatrixf(invymat);
-                checkGLcall("glMultMatrixf(invymat)");
-            }
             glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_PROJECTION].u.m[0][0]);
             checkGLcall("glLoadMatrixf");
         }
@@ -318,10 +304,6 @@ static void primitiveInitState(
                a pixel (See comment above glTranslate above)                         */
             glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
             checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
-            if (This->renderUpsideDown) {
-                glMultMatrixf(invymat);
-                checkGLcall("glMultMatrixf(invymat)");
-            }
             This->modelview_valid = FALSE;
             This->proj_valid = FALSE;
         }
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 9c2ed60..0017804 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -1656,11 +1656,14 @@ static HRESULT WINAPI IWineD3DSurfaceImp
             FIXME("Format %d not supported\n", This->resource.format);
         else {
             GLint prevRead;
+            int i;
+            
             glGetIntegerv(GL_READ_BUFFER, &prevRead);
             vcheckGLcall("glGetIntegerv");
             glReadBuffer(GL_BACK);
             vcheckGLcall("glReadBuffer");
 
+            /* Setup the initial target texture array */
             glCopyTexImage2D(This->glDescription.target,
                              This->glDescription.level,
                              This->glDescription.glFormatInternal,
@@ -1669,8 +1672,21 @@ static HRESULT WINAPI IWineD3DSurfaceImp
                              This->currentDesc.Width,
                              This->currentDesc.Height,
                              0);
-
             checkGLcall("glCopyTexImage2D");
+            
+            /* Now, we need to flip this texture because we are taking it from the backbuffer */
+            for (i=0; i<This->currentDesc.Height; i++) {
+                glCopyTexSubImage2D(This->glDescription.target,
+                                    This->glDescription.level,
+                                    0,
+                                    i,
+                                    0,
+                                    This->currentDesc.Height -i - 1,
+                                    This->currentDesc.Width,
+                                    1);
+            }
+            checkGLcall("glCopyTexSubImage2D");
+
             glReadBuffer(prevRead);
             vcheckGLcall("glReadBuffer");
             TRACE("Updating target %d\n", This->glDescription.target);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 1f51e3b..7a9b8ac 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -531,9 +531,6 @@ #define                         NEEDS_DI
     PALETTEENTRY            palettes[MAX_PALETTES][256];
     UINT                    currentPalette;
 
-    /* For rendering to a texture using glCopyTexImage */
-    BOOL                    renderUpsideDown;
-
     /* Cursor management */
     BOOL                    bCursorVisible;
     UINT                    xHotSpot;
-------------- next part --------------
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 323a2f5..17b3a9a 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3463,25 +3463,15 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         case D3DCULL_CW:
             glEnable(GL_CULL_FACE);
             checkGLcall("glEnable GL_CULL_FACE");
-            if (This->renderUpsideDown) {
-                glFrontFace(GL_CW);
-                checkGLcall("glFrontFace GL_CW");
-            } else {
-                glFrontFace(GL_CCW);
-                checkGLcall("glFrontFace GL_CCW");
-            }
+            glFrontFace(GL_CCW);
+            checkGLcall("glFrontFace GL_CCW");
             glCullFace(GL_BACK);
             break;
         case D3DCULL_CCW:
             glEnable(GL_CULL_FACE);
             checkGLcall("glEnable GL_CULL_FACE");
-            if (This->renderUpsideDown) {
-                glFrontFace(GL_CCW);
-                checkGLcall("glFrontFace GL_CCW");
-            } else {
-                glFrontFace(GL_CW);
-                checkGLcall("glFrontFace GL_CW");
-            }
+            glFrontFace(GL_CW);
+            checkGLcall("glFrontFace GL_CW");
             glCullFace(GL_BACK);
             break;
         default:
@@ -7385,28 +7375,9 @@ #endif
     IWineD3DSurface_AddRef(This->renderTarget);
     IWineD3DSurface_Release(tmp);
 
-    {
-        DWORD value;
-
-        /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */
-        /* Check that the container is not a swapchain member */
-
-        IWineD3DSwapChain *tmpSwapChain;
-        if (WINED3D_OK != IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmpSwapChain)) {
-            This->renderUpsideDown = TRUE;
-        }else{
-            This->renderUpsideDown = FALSE;
-            IWineD3DSwapChain_Release(tmpSwapChain);
-        }
-        /* Force updating the cull mode */
-        TRACE("setting render state\n");
-        IWineD3DDevice_GetRenderState(iface, WINED3DRS_CULLMODE, &value);
-        IWineD3DDevice_SetRenderState(iface, WINED3DRS_CULLMODE, value);
-
-        /* Force updating projection matrix */
-        This->last_was_rhw = FALSE;
-        This->proj_valid = FALSE;
-    }
+    /* Force updating projection matrix */
+    This->last_was_rhw = FALSE;
+    This->proj_valid = FALSE;
 
     /* Restore recording state */
     This->isRecordingState = oldRecording;
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index bb48982..485e0fe 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -148,12 +148,6 @@ static void init_materials(IWineD3DDevic
 
 }
 
-static GLfloat invymat[16] = {
-	1.0f, 0.0f, 0.0f, 0.0f,
-	0.0f, -1.0f, 0.0f, 0.0f,
-	0.0f, 0.0f, 1.0f, 0.0f,
-	0.0f, 0.0f, 0.0f, 1.0f};
-
 void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) {
     /* If the last draw was transformed as well, no need to reapply all the matrixes */
     if ( (!This->last_was_rhw) || (This->viewport_changed) ) {
@@ -190,10 +184,6 @@ void d3ddevice_set_ortho(IWineD3DDeviceI
             a pixel (See comment above glTranslate below)                         */
         glTranslatef(0.375, 0.375, 0);
         checkGLcall("glTranslatef(0.375, 0.375, 0)");
-        if (This->renderUpsideDown) {
-            glMultMatrixf(invymat);
-            checkGLcall("glMultMatrixf(invymat)");
-        }
 
         /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */
         if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) {
@@ -295,10 +285,6 @@ static void primitiveInitState(
             glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
             checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
 
-            if (This->renderUpsideDown) {
-                glMultMatrixf(invymat);
-                checkGLcall("glMultMatrixf(invymat)");
-            }
             glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_PROJECTION].u.m[0][0]);
             checkGLcall("glLoadMatrixf");
         }
@@ -318,10 +304,6 @@ static void primitiveInitState(
                a pixel (See comment above glTranslate above)                         */
             glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
             checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
-            if (This->renderUpsideDown) {
-                glMultMatrixf(invymat);
-                checkGLcall("glMultMatrixf(invymat)");
-            }
             This->modelview_valid = FALSE;
             This->proj_valid = FALSE;
         }
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 9c2ed60..25e6e12 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -1656,21 +1656,45 @@ static HRESULT WINAPI IWineD3DSurfaceImp
             FIXME("Format %d not supported\n", This->resource.format);
         else {
             GLint prevRead;
+            int i;
+            unsigned pitch;
+            BYTE* mem;
+            BYTE *top, *bottom;
+            
             glGetIntegerv(GL_READ_BUFFER, &prevRead);
             vcheckGLcall("glGetIntegerv");
             glReadBuffer(GL_BACK);
             vcheckGLcall("glReadBuffer");
 
-            glCopyTexImage2D(This->glDescription.target,
-                             This->glDescription.level,
-                             This->glDescription.glFormatInternal,
-                             0,
-                             0,
-                             This->currentDesc.Width,
-                             This->currentDesc.Height,
-                             0);
+            mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(BYTE));
+
+            glReadPixels(0, 0, This->currentDesc.Width, This->currentDesc.Height, 
+                    This->glDescription.glFormat, This->glDescription.glType, mem);
+
+            top = mem;
+            pitch = This->resource.size / (This->currentDesc.Height);
+            bottom = mem + (pitch * (This->currentDesc.Height - 1));
+            for(i = 0; i < This->currentDesc.Height / 2; i++) {
+                memcpy(mem, top, pitch);
+                memcpy(top, bottom, pitch);
+                memcpy(bottom, mem, pitch);
+                top += pitch;
+                bottom -= pitch;
+            }
+            
+            glTexImage2D(This->glDescription.target,
+                         This->glDescription.level,
+                         This->glDescription.glFormatInternal,
+                         This->currentDesc.Width,
+                         This->currentDesc.Height,
+                         0,
+                         This->glDescription.glFormat,
+                         This->glDescription.glType,
+                         mem);
+            checkGLcall("glTexImage2D");
 
-            checkGLcall("glCopyTexImage2D");
+            HeapFree(GetProcessHeap(), 0, mem); 
+            
             glReadBuffer(prevRead);
             vcheckGLcall("glReadBuffer");
             TRACE("Updating target %d\n", This->glDescription.target);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 1f51e3b..7a9b8ac 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -531,9 +531,6 @@ #define                         NEEDS_DI
     PALETTEENTRY            palettes[MAX_PALETTES][256];
     UINT                    currentPalette;
 
-    /* For rendering to a texture using glCopyTexImage */
-    BOOL                    renderUpsideDown;
-
     /* Cursor management */
     BOOL                    bCursorVisible;
     UINT                    xHotSpot;


More information about the wine-devel mailing list