[8/10] WineD3D: Move the projection matrix into its own state

Stefan Dösinger stefandoesinger at gmx.at
Tue Jan 2 15:50:38 CST 2007


Its pointless to reapply the vdecl if the projection transform  
setting has changed. Simmilar to the lighting state.

-------------- next part --------------
From 5189f91b62b321b20466deecb7336e18e7ce81b1 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Stefan_D=C3=B6singer?= <stefan at imac.local>
Date: Tue, 2 Jan 2007 22:00:45 +0100
Subject: [PATCH] WineD3D: Move the projection matrix to the state table

---
 dlls/wined3d/drawprim.c |   57 ---------------------------
 dlls/wined3d/state.c    |  100 ++++++++++++++++++++++++++++++++++++-----------
 dlls/wined3d/surface.c  |    6 +++
 3 files changed, 82 insertions(+), 81 deletions(-)

diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index c79c2b0..9ccc358 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -158,8 +158,6 @@ static const GLfloat invymat[16] = {
 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) ) {
-
-        double X, Y, height, width, minZ, maxZ;
         This->last_was_rhw = TRUE;
         This->viewport_changed = FALSE;
 
@@ -170,61 +168,6 @@ void d3ddevice_set_ortho(IWineD3DDeviceI
         checkGLcall("glMatrixMode(GL_MODELVIEW)");
         glLoadIdentity();
         checkGLcall("glLoadIdentity");
-
-        glMatrixMode(GL_PROJECTION);
-        checkGLcall("glMatrixMode(GL_PROJECTION)");
-        glLoadIdentity();
-        checkGLcall("glLoadIdentity");
-
-        /* Set up the viewport to be full viewport */
-        X      = This->stateBlock->viewport.X;
-        Y      = This->stateBlock->viewport.Y;
-        height = This->stateBlock->viewport.Height;
-        width  = This->stateBlock->viewport.Width;
-        minZ   = This->stateBlock->viewport.MinZ;
-        maxZ   = This->stateBlock->viewport.MaxZ;
-        if(!This->untransformed) {
-            TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
-            glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
-        } else {
-            TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0);
-            glOrtho(X, X + width, Y + height, Y, 1.0, -1.0);
-        }
-        checkGLcall("glOrtho");
-
-        /* Window Coord 0 is the middle of the first pixel, so translate by half
-            a pixel (See comment above glTranslate below)                         */
-        glTranslatef(0.375, 0.375, 0);
-        checkGLcall("glTranslatef(0.375, 0.375, 0)");
-        /* D3D texture coordinates are flipped compared to OpenGL ones, so
-         * render everything upside down when rendering offscreen. */
-        if (This->render_offscreen) {
-            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] != WINED3DFOG_NONE) {
-            if(GL_SUPPORT(EXT_FOG_COORD)) {
-                glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
-                checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)");
-                glFogi(GL_FOG_MODE, GL_LINEAR);
-                checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
-                /* The dx fog range in this case is fixed to 0 - 255,
-                 * but in GL it still depends on the fog start and end (according to the ext)
-                 * Use this to turn around the fog as it's needed. That prevents some
-                 * calculations during drawing :-)
-                 */
-                glFogf(GL_FOG_START, (float) 0xff);
-                checkGLcall("glFogfv GL_FOG_END");
-                glFogf(GL_FOG_END, 0.0);
-                checkGLcall("glFogfv GL_FOG_START");
-            } else {
-                /* Disable GL fog, handle this in software in drawStridedSlow */
-                glDisable(GL_FOG);
-                checkGLcall("glDisable(GL_FOG)");
-            }
-        }
     }
 }
 
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 9f690c5..0e9c8a5 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -1890,6 +1890,74 @@ static const GLfloat invymat[16] = {
     0.0f, 0.0f, 1.0f, 0.0f,
     0.0f, 0.0f, 0.0f, 1.0f};
 
+static void transform_projection(DWORD state, IWineD3DStateBlockImpl *stateblock) {
+    glMatrixMode(GL_PROJECTION);
+    checkGLcall("glMatrixMode(GL_PROJECTION)");
+    glLoadIdentity();
+    checkGLcall("glLoadIdentity");
+
+    if(stateblock->wineD3DDevice->last_was_rhw) {
+        double X, Y, height, width, minZ, maxZ;
+
+        X      = stateblock->viewport.X;
+        Y      = stateblock->viewport.Y;
+        height = stateblock->viewport.Height;
+        width  = stateblock->viewport.Width;
+        minZ   = stateblock->viewport.MinZ;
+        maxZ   = stateblock->viewport.MaxZ;
+
+        if(!stateblock->wineD3DDevice->untransformed) {
+            /* Transformed vertices are supposed to bypass the whole transform pipeline including
+             * frustum clipping. This can't be done in opengl, so this code adjusts the Z range to
+             * suppress depth clipping. This can be done because it is an orthogonal projection and
+             * the Z coordinate does not affect the size of the primitives
+             */
+            TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
+            glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
+        } else {
+            /* If the app mixes transformed and untransformed primitives we can't use the coordinate system
+             * trick above because this would mess up transformed and untransformed Z order. Pass the z position
+             * unmodified to opengl.
+             *
+             * If the app depends on mixed types and disabled clipping we're out of luck without a pipeline
+             * replacement shader.
+             */
+            TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0);
+            glOrtho(X, X + width, Y + height, Y, 1.0, -1.0);
+        }
+        checkGLcall("glOrtho");
+
+        /* Window Coord 0 is the middle of the first pixel, so translate by 3/8 pixels */
+        glTranslatef(0.375, 0.375, 0);
+        checkGLcall("glTranslatef(0.375, 0.375, 0)");
+        /* D3D texture coordinates are flipped compared to OpenGL ones, so
+         * render everything upside down when rendering offscreen. */
+        if (stateblock->wineD3DDevice->render_offscreen) {
+            glMultMatrixf(invymat);
+            checkGLcall("glMultMatrixf(invymat)");
+        }
+    } else {
+        /* The rule is that the window coordinate 0 does not correspond to the
+            beginning of the first pixel, but the center of the first pixel.
+            As a consequence if you want to correctly draw one line exactly from
+            the left to the right end of the viewport (with all matrices set to
+            be identity), the x coords of both ends of the line would be not
+            -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
+            instead.                                                               */
+        glTranslatef(0.9 / stateblock->viewport.Width, -0.9 / stateblock->viewport.Height, 0);
+        checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
+
+        /* D3D texture coordinates are flipped compared to OpenGL ones, so
+            * render everything upside down when rendering offscreen. */
+        if (stateblock->wineD3DDevice->render_offscreen) {
+            glMultMatrixf(invymat);
+            checkGLcall("glMultMatrixf(invymat)");
+        }
+        glMultMatrixf((float *) &stateblock->transforms[WINED3DTS_PROJECTION].u.m[0][0]);
+        checkGLcall("glLoadMatrixf");
+    }
+}
+
 static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock) {
     BOOL useVertexShaderFunction = FALSE, updateFog = FALSE;
     BOOL transformed;
@@ -1983,29 +2051,6 @@ static void vertexdeclaration(DWORD stat
 
         if (!useVertexShaderFunction) {
             device->proj_valid = TRUE;
-            glMatrixMode(GL_PROJECTION);
-            checkGLcall("glMatrixMode");
-
-            /* The rule is that the window coordinate 0 does not correspond to the
-               beginning of the first pixel, but the center of the first pixel.
-               As a consequence if you want to correctly draw one line exactly from
-               the left to the right end of the viewport (with all matrices set to
-               be identity), the x coords of both ends of the line would be not
-               -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
-               instead.                                                               */
-            glLoadIdentity();
-
-            glTranslatef(0.9 / stateblock->viewport.Width, -0.9 / stateblock->viewport.Height, 0);
-            checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
-
-            /* D3D texture coordinates are flipped compared to OpenGL ones, so
-             * render everything upside down when rendering offscreen. */
-            if (device->render_offscreen) {
-                glMultMatrixf(invymat);
-                checkGLcall("glMultMatrixf(invymat)");
-            }
-            glMultMatrixf((float *) &stateblock->transforms[WINED3DTS_PROJECTION].u.m[0][0]);
-            checkGLcall("glLoadMatrixf");
         }
 
         /* Vertex Shader output is already transformed, so set up identity matrices */
@@ -2017,6 +2062,13 @@ static void vertexdeclaration(DWORD stat
         device->last_was_rhw = FALSE;
     }
 
+    /* TODO: Move this mainly to the viewport state and only apply when the vp has changed
+     * or transformed / untransformed was switched
+     */
+    if(!isStateDirty(stateblock->wineD3DDevice, STATE_TRANSFORM(WINED3DTS_PROJECTION))) {
+        transform_projection(STATE_TRANSFORM(WINED3DTS_PROJECTION), stateblock);
+    }
+
     /* Setup fogging */
     if(updateFog) {
         state_fog(STATE_RENDER(WINED3DRS_FOGENABLE), stateblock);
@@ -2525,7 +2577,7 @@ const struct StateEntry StateTable[] =
       /* Transform states follow                    */
     { /*  1, undefined                              */      0,                                                  state_undefined     },
     { /*  2, WINED3DTS_VIEW                         */      STATE_TRANSFORM(WINED3DTS_VIEW),                    transform_view      },
-    { /*  3, WINED3DTS_PROJECTION                   */      STATE_VDECL,                                        vertexdeclaration   },
+    { /*  3, WINED3DTS_PROJECTION                   */      STATE_TRANSFORM(WINED3DTS_PROJECTION),              transform_projection},
     { /*  4, undefined                              */      0,                                                  state_undefined     },
     { /*  5, undefined                              */      0,                                                  state_undefined     },
     { /*  6, undefined                              */      0,                                                  state_undefined     },
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 5cf43f1..d9355d4 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -1150,6 +1150,9 @@ static HRESULT WINAPI IWineD3DSurfaceImp
                we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
                per drawprim (and leave set - it will sort itself out due to last_was_rhw */
             d3ddevice_set_ortho(This->resource.wineD3DDevice);
+            /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */
+            StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock);
+            /* Will reapply the projection matrix too */
             IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
 
             if (iface ==  implSwapChain->frontBuffer) {
@@ -2474,6 +2477,9 @@ static HRESULT IWineD3DSurfaceImpl_BltOv
             /* Draw a textured quad
              */
             d3ddevice_set_ortho(This->resource.wineD3DDevice);
+            /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */
+            StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock);
+            /* That will reapply the projection matrix too */
             IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
 
             glBegin(GL_QUADS);
-- 
1.4.2.4



More information about the wine-patches mailing list