(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
--- 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();