[19/19] WineD3D: Reinstall the nvrc texture unit mapping

Stefan Dösinger stefan at codeweavers.com
Tue Dec 19 16:33:34 CST 2006


This patch puts the junk texture unit skipping back which patch 1 removed.

Problem one is that changing the mapping tramples like an elephant over not 
dirtified stages, so the code tries to avoid a non 1:1 mapping as much as 
possible.

Problem 2 is that we have no real-world game that is working and needs this. 
Command and Conquer Generals seems to need it according to Henri, but it does 
not work yet for some other reason, so a non-1:1 mapping is untested and a 
FIXME written.
-------------- next part --------------
From bab89fb355e91de728724bab40e41bbc92295180 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Tue, 19 Dec 2006 22:24:06 +0100
Subject: [PATCH] WineD3D: Renable nvrc texture stage to unit mapping

---
 dlls/wined3d/device.c          |   92 ++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/state.c           |   15 +++----
 dlls/wined3d/wined3d_private.h |    4 ++
 3 files changed, 104 insertions(+), 7 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 99f24f7..80f3f2a 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -2075,6 +2075,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl
 
     /* TODO: Test if OpenGL is compiled in and loaded */
 
+    /* Initialize the texture unit mapping to a 1:1 mapping */
+    for(state = 0; state < MAX_SAMPLERS; state++) {
+        This->texUnitMap[state] = state;
+    }
+    This->oneToOneTexUnitMap = TRUE;
+
     /* Setup the implicit swapchain */
     TRACE("Creating implicit swapchain\n");
     if (D3D_OK != D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain) || swapchain == NULL) {
@@ -3672,6 +3678,72 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     return WINED3D_OK;
 }
 
+static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
+    DWORD i;
+    for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
+        IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
+    }
+}
+
+static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
+    DWORD i, tex;
+    /* This code can assume that GL_NV_register_combiners are supported, otherwise
+     * it is never called.
+     *
+     * Rules are:
+     * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
+     * that would be really messy and require shader recompilation
+     * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
+     * to be reset. Because of that try to work with a 1:1 mapping as much as possible
+     * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
+     * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
+     */
+    if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
+        if(This->oneToOneTexUnitMap) {
+            TRACE("Not touching 1:1 map\n");
+            return;
+        }
+        TRACE("Restoring 1:1 texture unit mapping\n");
+        /* Restore a 1:1 mapping */
+        for(i = 0; i < MAX_SAMPLERS; i++) {
+            if(This->texUnitMap[i] != i) {
+                This->texUnitMap[i] = i;
+                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
+                markTextureStagesDirty(This, i);
+            }
+        }
+        This->oneToOneTexUnitMap = TRUE;
+        return;
+    } else {
+        /* No pixel shader, and we do not have enought texture units available. Try to skip NULL textures
+         * First, see if we can succeed at all
+         */
+        tex = 0;
+        for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
+            if(This->stateBlock->textures[i] == NULL) tex++;
+        }
+
+        if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
+            FIXME("Too many bound textures to support the combiner settings\n");
+            return;
+        }
+
+        /* Now work out the mapping */
+        tex = 0;
+        This->oneToOneTexUnitMap = FALSE;
+        FIXME("Non 1:1 mapping UNTESTED!\n");
+        for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
+            if(This->stateBlock->textures[i] == NULL) tex++;
+            TRACE("Mapping texture stage %d to unit %d\n", i, tex);
+            if(This->texUnitMap[i] != tex) {
+                This->texUnitMap[i] = tex;
+                IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
+                markTextureStagesDirty(This, i);
+            }
+        }
+    }
+}
+
 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
     IWineD3DDeviceImpl *This        = (IWineD3DDeviceImpl *)iface;
     IWineD3DPixelShader *oldShader  = This->updateStateBlock->pixelShader;
@@ -3703,6 +3775,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl
 
     TRACE("(%p) : setting pShader(%p)\n", This, pShader);
     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
+
+    /* Rebuild the texture unit mapping if nvrc's are supported */
+    if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
+        IWineD3DDeviceImpl_FindTexUnitMap(This);
+    }
+
     return WINED3D_OK;
 }
 
@@ -4432,6 +4510,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl
 
     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
 
+    /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
+     * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
+     * will call FindTexUnitMap too.
+     */
+    if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
+        IWineD3DDeviceImpl_FindTexUnitMap(This);
+    }
     return WINED3D_OK;
 }
 
@@ -4545,6 +4630,13 @@ #endif
 
     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
 
+    /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
+     * pixel shader is used
+     */
+    if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
+        IWineD3DDeviceImpl_FindTexUnitMap(This);
+    }
+
     return WINED3D_OK;
 }
 
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index f5e52f3..0b9f224 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -1362,14 +1362,15 @@ static void tex_colorop(DWORD state, IWi
 
     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
         /* TODO: register combiners! */
-        if(stage >= GL_LIMITS(sampler_stages)) {
+        if(stage != stateblock->wineD3DDevice->texUnitMap[stage]) ERR("Foo: %d is %d!\n", stage, stateblock->wineD3DDevice->texUnitMap[stage]);
+        if(stateblock->wineD3DDevice->texUnitMap[stage] >= GL_LIMITS(sampler_stages)) {
             if(stateblock->textureState[stage][WINED3DTSS_COLOROP] != WINED3DTOP_DISABLE &&
               stateblock->textureState[stage][WINED3DTSS_COLOROP] != 0) {
                 FIXME("Attempt to enable unsupported stage!\n");
             }
             return;
         }
-        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stage));
+        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stateblock->wineD3DDevice->texUnitMap[stage]));
         checkGLcall("glActiveTextureARB");
     } else if (stage > 0) {
         WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
@@ -1408,7 +1409,7 @@ static void tex_colorop(DWORD state, IWi
                          stateblock->textureState[stage][WINED3DTSS_COLORARG1],
                          stateblock->textureState[stage][WINED3DTSS_COLORARG2],
                          stateblock->textureState[stage][WINED3DTSS_COLORARG0],
-                         stage);
+                         stateblock->wineD3DDevice->texUnitMap[stage]);
     } else {
         set_tex_op((IWineD3DDevice *)stateblock->wineD3DDevice, FALSE, stage,
                     stateblock->textureState[stage][WINED3DTSS_COLOROP],
@@ -1432,7 +1433,7 @@ static void tex_alphaop(DWORD state, IWi
             }
             return;
         }
-        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stage));
+        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stateblock->wineD3DDevice->texUnitMap[stage]));
         checkGLcall("glActiveTextureARB");
     } else if (stage > 0) {
         /* We can't do anything here */
@@ -1447,7 +1448,7 @@ static void tex_alphaop(DWORD state, IWi
                          stateblock->textureState[stage][WINED3DTSS_ALPHAARG1],
                          stateblock->textureState[stage][WINED3DTSS_ALPHAARG2],
                          stateblock->textureState[stage][WINED3DTSS_ALPHAARG0],
-                         stage);
+                         stateblock->wineD3DDevice->texUnitMap[stage]);
     } else {
         set_tex_op((IWineD3DDevice *)stateblock->wineD3DDevice, TRUE, stage, stateblock->textureState[stage][WINED3DTSS_ALPHAOP],
                     stateblock->textureState[stage][WINED3DTSS_ALPHAARG1],
@@ -1464,7 +1465,7 @@ static void tex_coordindex(DWORD state, 
         if(stage >= GL_LIMITS(sampler_stages)) {
             return;
         }
-        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stage));
+        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stateblock->wineD3DDevice->texUnitMap[stage]));
         checkGLcall("glActiveTextureARB");
     } else if (stage > 0) {
         /* We can't do anything here */
@@ -1661,7 +1662,7 @@ static void sampler(DWORD state, IWineD3
         if(sampler >= GL_LIMITS(sampler_stages)) {
             return;
         }
-        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + sampler));
+        GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stateblock->wineD3DDevice->texUnitMap[sampler]));
         checkGLcall("glActiveTextureARB");
     } else if (sampler > 0) {
         /* We can't do anything here */
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 1054f5f..3d39b96 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -651,6 +651,10 @@ #define                         NEEDS_DI
     DWORD                   numDirtyEntries;
     DWORD                   isStateDirty[STATE_HIGHEST/32 + 1]; /* Bitmap to find out quickly if a state is dirty */
 
+    /* With register combiners we can skip junk texture stages */
+    DWORD                     texUnitMap[MAX_SAMPLERS];
+    BOOL                      oneToOneTexUnitMap;
+
 } IWineD3DDeviceImpl;
 
 extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl;
-- 
1.4.2.4



More information about the wine-patches mailing list