From c40912214c25157535452b1d12a0074e2d749934 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Thu, 6 Aug 2009 20:30:20 +0200
Subject: [PATCH 1/4] WineD3D: Watch out about higher constants when clamping ps 1.x consts

ps 1.x supports only 8 constants, so the shader load code dirtifies the
first 8 on a shader switch. However, the constant load code reloaded all dirty
consts with clamping. That potentially left constants > 8 clamped.

Only clamp the first 8 constants, and load higher dirty pshader constants
normally. That way we can mark all constants clean, which helps ps1.x only
apps.
---
 dlls/wined3d/arb_program_shader.c |   61 ++++++++++++++++++++++---------------
 1 files changed, 36 insertions(+), 25 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index cc039c5..7aa247e 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -284,7 +284,7 @@ static unsigned int shader_arb_load_constantsF(IWineD3DBaseShaderImpl *This, con
         GLuint target_type, unsigned int max_constants, const float *constants, char *dirty_consts)
 {
     local_constant* lconst;
-    DWORD i, j;
+    DWORD i = 0, j;
     unsigned int ret;
 
     if (TRACE_ON(d3d_shader)) {
@@ -299,7 +299,10 @@ static unsigned int shader_arb_load_constantsF(IWineD3DBaseShaderImpl *This, con
     if (target_type == GL_FRAGMENT_PROGRAM_ARB && This->baseShader.reg_maps.shader_version.major == 1)
     {
         float lcl_const[4];
-        for(i = 0; i < max_constants; i++) {
+        /* ps 1.x supports only 8 constants, clamp only those. When switching between 1.x and higher
+         * shaders, the first 8 constants are marked dirty for reload
+         */
+        for(; i < min(8, max_constants); i++) {
             if(!dirty_consts[i]) continue;
             dirty_consts[i] = 0;
 
@@ -322,31 +325,39 @@ static unsigned int shader_arb_load_constantsF(IWineD3DBaseShaderImpl *This, con
 
             GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, lcl_const));
         }
-    } else {
-        if(GL_SUPPORT(EXT_GPU_PROGRAM_PARAMETERS)) {
-            /* TODO: Benchmark if we're better of with finding the dirty constants ourselves,
-             * or just reloading *all* constants at once
-             *
-            GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, 0, max_constants, constants));
-             */
-            for(i = 0; i < max_constants; i++) {
-                if(!dirty_consts[i]) continue;
 
-                /* Find the next block of dirty constants */
-                dirty_consts[i] = 0;
-                j = i;
-                for(i++; (i < max_constants) && dirty_consts[i]; i++) {
-                    dirty_consts[i] = 0;
-                }
+        /* If further constants are dirty, reload them without clamping.
+         *
+         * The alternative is not to touch them, but then we cannot reset the dirty constant count
+         * to zero. That's bad for apps that only use PS 1.x shaders, because in that case the code
+         * above would always re-check the first 8 constants since max_constant remains at the init
+         * value
+         */
+    }
+
+    if(GL_SUPPORT(EXT_GPU_PROGRAM_PARAMETERS)) {
+        /* TODO: Benchmark if we're better of with finding the dirty constants ourselves,
+         * or just reloading *all* constants at once
+         *
+        GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, i, max_constants, constants + (i * 4)));
+         */
+        for(; i < max_constants; i++) {
+            if(!dirty_consts[i]) continue;
 
-                GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, j, i - j, constants + (j * 4)));
+            /* Find the next block of dirty constants */
+            dirty_consts[i] = 0;
+            j = i;
+            for(i++; (i < max_constants) && dirty_consts[i]; i++) {
+                dirty_consts[i] = 0;
             }
-        } else {
-            for(i = 0; i < max_constants; i++) {
-                if(dirty_consts[i]) {
-                    dirty_consts[i] = 0;
-                    GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4)));
-                }
+
+            GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, j, i - j, constants + (j * 4)));
+        }
+    } else {
+        for(; i < max_constants; i++) {
+            if(dirty_consts[i]) {
+                dirty_consts[i] = 0;
+                GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4)));
             }
         }
     }
-- 
1.6.3.3


