[dx73b] Try3: Performance of texture states

Ann and Jason Edmeades us at the-edmeades.demon.co.uk
Sun Aug 3 05:02:01 CDT 2003


(Try#3 - Also fixes Operation Flashpoint problem which was introduced
AND includes the patch... oops!)

This is the first patch which looks at the performance of changing the
textures on a texture unit. As was pointed out to me by Lucho, certain
information is per texture unit and hence not affected when a different
texture object is bound. This patch on my machine changes the displayed
fps by the Billboard sample from 30.6 to about 42.6. [Actually it was
43.0
with patch b, but I dont see why!]

There is still more optimization which can be done here, but this is a
start.

Let me know if anyone notices any regressions with this one.

Changelog
Only reapply the texture states necessary when a different texture gets
bound to the same texture unit.
Jason
-------------- next part --------------
--- dlls/d3d8/dx72/d3d8_private.h	2003-07-31 00:26:59.000000000 +0100
+++ dlls/d3d8/d3d8_private.h	2003-08-03 00:54:30.000000000 +0100
@@ -73,6 +73,10 @@
 #define HIGHEST_TRANSFORMSTATE 512
 #define D3DSBT_RECORDED 0xfffffffe
 
+/* Performance changes - Only reapply what is necessary */
+#define REAPPLY_ALPHAOP  0x0001
+#define REAPPLY_ALL      0xFFFF
+
 /* CreateVertexShader can return > 0xFFFF */
 #define VS_HIGHESTFIXEDFXF 0xF0000000
 #define VERTEX_SHADER(Handle) \
@@ -1239,7 +1243,7 @@
  * to see how not defined it here
  */ 
 void   GetSrcAndOpFromValue(DWORD iValue, BOOL isAlphaArg, GLenum* source, GLenum* operand);
-void   setupTextureStates(LPDIRECT3DDEVICE8 iface, DWORD Stage);
+void   setupTextureStates(LPDIRECT3DDEVICE8 iface, DWORD Stage, DWORD Flags);
 void   set_tex_op(LPDIRECT3DDEVICE8 iface, BOOL isAlpha, int Stage, D3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3);
 
 SHORT  D3DFmtGetBpp(IDirect3DDevice8Impl* This, D3DFORMAT fmt);
--- dlls/d3d8/dx72/device.c	2003-07-30 23:45:41.000000000 +0100
+++ dlls/d3d8/device.c	2003-08-03 01:03:39.000000000 +0100
@@ -66,37 +66,69 @@
 } while (0)
 
 /* Apply the current values to the specified texture stage */
-void setupTextureStates(LPDIRECT3DDEVICE8 iface, DWORD Stage) {
+void setupTextureStates(LPDIRECT3DDEVICE8 iface, DWORD Stage, DWORD Flags) {
     ICOM_THIS(IDirect3DDevice8Impl,iface);
     int i = 0;
     float col[4];
-
-    /* Make appropriate texture active */
-    if (GL_SUPPORT(ARB_MULTITEXTURE)) {
-#if defined(GL_VERSION_1_3)
-        glActiveTexture(GL_TEXTURE0 + Stage);
-#else
-        glActiveTextureARB(GL_TEXTURE0_ARB + Stage);
-#endif
-        checkGLcall("glActiveTextureARB");
-    } else if (Stage > 0) {
-        FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
-    }
+    BOOL changeTexture = TRUE;
 
     TRACE("-----------------------> Updating the texture at stage %ld to have new texture state information\n", Stage);
     for (i = 1; i < HIGHEST_TEXTURE_STATE; i++) {
 
+        BOOL skip = FALSE;
+
+        switch (i) {
         /* Performance: For texture states where multiples effect the outcome, only bother
               applying the last one as it will pick up all the other values                */
-        switch (i) {
         case D3DTSS_COLORARG0:  /* Will be picked up when setting color op */
         case D3DTSS_COLORARG1:  /* Will be picked up when setting color op */
         case D3DTSS_COLORARG2:  /* Will be picked up when setting color op */
         case D3DTSS_ALPHAARG0:  /* Will be picked up when setting alpha op */
         case D3DTSS_ALPHAARG1:  /* Will be picked up when setting alpha op */
         case D3DTSS_ALPHAARG2:  /* Will be picked up when setting alpha op */
+           skip = TRUE;
            break;
+
+        /* Performance: If the texture states only impact settings for the texture unit 
+             (compared to the texture object) then there is no need to reapply them. The
+             only time they need applying is the first time, since we cheat and put the  
+             values into the stateblock without applying.                                
+             Per-texture unit: texture function (eg. combine), ops and args
+                               texture env color                                               
+                               texture generation settings                               
+           Note: Due to some special conditions there may be a need to do particular ones
+             of these, which is what the Flags allows                                     */
+        case D3DTSS_COLOROP:       
+        case D3DTSS_TEXCOORDINDEX:
+            if (!(Flags == REAPPLY_ALL)) skip=TRUE;
+            break;
+
+        case D3DTSS_ALPHAOP:       
+            if (!(Flags & REAPPLY_ALPHAOP)) skip=TRUE;
+            break;
+
         default:
+            skip = FALSE;
+        }
+
+        if (skip == FALSE) {
+           /* Performance: Only change to this texture if we have to */
+           if (changeTexture) {
+               /* Make appropriate texture active */
+               if (GL_SUPPORT(ARB_MULTITEXTURE)) {
+#if defined(GL_VERSION_1_3)
+                   glActiveTexture(GL_TEXTURE0 + Stage);
+#else
+                   glActiveTextureARB(GL_TEXTURE0_ARB + Stage);
+#endif
+                   checkGLcall("glActiveTextureARB");
+                } else if (Stage > 0) {
+                    FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
+                }
+                changeTexture = FALSE;
+           }
+
+           /* Now apply the change */
            IDirect3DDevice8Impl_SetTextureStageState(iface, Stage, i, This->StateBlock->texture_state[Stage][i]);
         }
     }
@@ -2671,6 +2703,8 @@
 
     IDirect3DBaseTexture8 *oldTxt;
     BOOL reapplyStates = TRUE;
+    DWORD oldTextureDimensions = -1;
+    DWORD reapplyFlags = 0;
 
     ICOM_THIS(IDirect3DDevice8Impl,iface);
     D3DRESOURCETYPE textureType;
@@ -2694,6 +2728,7 @@
         return D3D_OK;
     }
 
+    oldTextureDimensions = This->UpdateStateBlock->textureDimensions[Stage];
     ENTER_GL();
 
     /* Make appropriate texture active */
@@ -2766,10 +2801,30 @@
         TRACE("Bound dummy Texture to stage %ld (gl name %d)\n", Stage, This->dummyTextureName[Stage]);
     }
 
+    /* Disable the old texture binding and enable the new one (unless operations are disabled) */
+    if (oldTextureDimensions != This->UpdateStateBlock->textureDimensions[Stage]) {
+       glDisable(oldTextureDimensions);
+       checkGLcall("Disable oldTextureDimensions");
+       if (This->StateBlock->texture_state[Stage][D3DTSS_COLOROP] != D3DTOP_DISABLE) {
+          glEnable(This->UpdateStateBlock->textureDimensions[Stage]);
+          checkGLcall("Disable new texture dimensions");
+       }
+
+       /* If Alpha arg1 is texture then handle the special case when there changes between a
+          texture and no texture - See comments in set_tex_op                                  */
+       if ((This->StateBlock->texture_state[Stage][D3DTSS_ALPHAARG1] == D3DTA_TEXTURE) && 
+           ((oldTxt == NULL) && (pTexture != NULL)) || 
+           ((pTexture == NULL) && (oldTxt != NULL))) 
+       {
+           reapplyFlags |= REAPPLY_ALPHAOP;
+       }
+    }
+
+
     /* Even if the texture has been set to null, reapply the stages as a null texture to directx requires
        a dummy texture in opengl, and we always need to ensure the current view of the TextureStates apply */
     if (reapplyStates) {
-       setupTextureStates(iface, Stage);
+       setupTextureStates(iface, Stage, reapplyFlags);
     }
 
     LEAVE_GL();   
--- dlls/d3d8/dx72/stateblock.c	2003-07-17 01:26:35.000000000 +0100
+++ dlls/d3d8/stateblock.c	2003-08-03 00:44:34.000000000 +0100
@@ -234,7 +234,7 @@
         checkGLcall("glTexImage1D");
 
         /* Reapply all the texture state information to this texture */
-        setupTextureStates(iface, i);
+        setupTextureStates(iface, i, REAPPLY_ALL);
     }
 
     LEAVE_GL();



More information about the wine-patches mailing list