[D3D] Texturing fixes (again :-) )

Lionel Ulmer lionel.ulmer at free.fr
Mon Jun 2 15:28:26 CDT 2003


This should optimize a bit the texture handling in the D3D code...
Basically, it prevents the most changes to the texturing parameters
possible.

                    Lionel

Changelog:
 - some GL critical section fixes
 - only bind textures at start of rendering
 - optimized the texture parameter code
 - optimize of the 'dirty checking code' for mipmapping
 - handles the MAXMIPLEVEL texture parameter
     
-- 
		 Lionel Ulmer - http://www.bbrox.org/
-------------- next part --------------
--- dlls/ddraw_CVS/d3ddevice/mesa.c	Sun Jun  1 20:56:09 2003
+++ dlls/ddraw/d3ddevice/mesa.c	Mon Jun  2 17:59:06 2003
@@ -56,13 +56,6 @@
   { 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
 };
 
-#ifndef HAVE_GLEXT_PROTOTYPES
-/* This is for non-OpenGL ABI compliant glext.h headers :-) */
-typedef void (* PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat,
-					 GLsizei width, GLenum format, GLenum type,
-					 const GLvoid *table);
-#endif
-
 const float id_mat[16] = {
     1.0, 0.0, 0.0, 0.0,
     0.0, 1.0, 0.0, 0.0,
@@ -79,6 +72,8 @@
 				   DWORD dwIndexCount,
 				   DWORD dwFlags) ;
 
+static DWORD draw_primitive_handle_textures(IDirect3DDeviceImpl *This);
+
 /* retrieve the X display to use on a given DC */
 inline static Display *get_display( HDC hdc )
 {
@@ -651,9 +646,7 @@
 	IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
 
 	if (mat != NULL) {
-	    ENTER_GL();
 	    mat->activate(mat);
-	    LEAVE_GL();
 	} else {
 	    ERR(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
 	}
@@ -1084,9 +1077,6 @@
 
     glThis->state = SURFACE_GL;
     
-    /* Compute the number of active texture stages */
-    while (This->current_texture[num_active_stages] != NULL) num_active_stages++;
-
     if (TRACE_ON(ddraw)) {
         TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
     }
@@ -1098,6 +1088,9 @@
         if ((d3dvtVertexType & D3DFVF_NORMAL) == 0) glNormal3f(0.0, 0.0, 0.0);
     }
     
+    /* Compute the number of active texture stages and set the various texture parameters */
+    num_active_stages = draw_primitive_handle_textures(This);
+
     draw_primitive_handle_GL_state(This,
 				   (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
 				   vertex_lighted);
@@ -1433,70 +1426,6 @@
     return DD_OK;
 }
 
-static GLenum
-convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState, D3DTEXTUREMIPFILTER dwMipState)
-{
-    GLenum gl_state;
-
-    if (dwMipState == D3DTFP_NONE) {
-        switch (dwMinState) {
-            case D3DTFN_POINT:  gl_state = GL_NEAREST; break;
-	    case D3DTFN_LINEAR: gl_state = GL_LINEAR;  break;
-	    default:            gl_state = GL_LINEAR;  break;
-	}
-    } else if (dwMipState == D3DTFP_POINT) {
-        switch (dwMinState) {
-            case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_NEAREST; break;
-	    case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
-	    default:            gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
-	}
-    } else {
-        switch (dwMinState) {
-            case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_LINEAR; break;
-	    case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
-	    default:            gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
-	}
-    }
-    return gl_state;
-}
-
-static GLenum
-convert_mag_filter_to_GL(D3DTEXTUREMAGFILTER dwState)
-{
-    GLenum gl_state;
-
-    switch (dwState) {
-        case D3DTFG_POINT:
-	    gl_state = GL_NEAREST;
-	    break;
-        case D3DTFG_LINEAR:
-	    gl_state = GL_LINEAR;
-	    break;
-        default:
-	    gl_state = GL_LINEAR;
-	    break;
-    }
-    return gl_state;
-}
-
-static GLenum
-convert_tex_address_to_GL(D3DTEXTUREADDRESS dwState)
-{
-    GLenum gl_state;
-    switch (dwState) {
-        case D3DTADDRESS_WRAP:   gl_state = GL_REPEAT; break;
-	case D3DTADDRESS_CLAMP:  gl_state = GL_CLAMP; break;
-	case D3DTADDRESS_BORDER: gl_state = GL_CLAMP_TO_EDGE; break;
-#if defined(GL_VERSION_1_4)
-	case D3DTADDRESS_MIRROR: gl_state = GL_MIRRORED_REPEAT; break;
-#elif defined(GL_ARB_texture_mirrored_repeat)
-	case D3DTADDRESS_MIRROR: gl_state = GL_MIRRORED_REPEAT_ARB; break;
-#endif
-	default:                 gl_state = GL_REPEAT; break;
-    }
-    return gl_state;
-}
-
 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
 static BOOLEAN
 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
@@ -1650,10 +1579,6 @@
 		    }
 		}
 	    }
-
-	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-			    convert_min_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MINFILTER - 1],
-						     This->state_block.texture_stage_state[dwStage][D3DTSS_MIPFILTER - 1]));
 	    break;
 	    
         case D3DTSS_MAGFILTER:
@@ -1664,14 +1589,11 @@
 		    default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
 		}
 	    }
-	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, convert_mag_filter_to_GL(dwState));
             break;
 
         case D3DTSS_ADDRESS:
         case D3DTSS_ADDRESSU:
         case D3DTSS_ADDRESSV: {
-	    GLenum arg = convert_tex_address_to_GL(dwState);
-	    
 	    switch ((D3DTEXTUREADDRESS) dwState) {
 	        case D3DTADDRESS_WRAP:   TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
 	        case D3DTADDRESS_CLAMP:  TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
@@ -1683,13 +1605,6 @@
 #endif
 	        default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
 	    }
-	    
-	    if ((d3dTexStageStateType == D3DTSS_ADDRESS) ||
-		(d3dTexStageStateType == D3DTSS_ADDRESSU))
-	        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, arg);
-	    if ((d3dTexStageStateType == D3DTSS_ADDRESS) ||
-		(d3dTexStageStateType == D3DTSS_ADDRESSV))
-	        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, arg);
         } break;
 
 	case D3DTSS_ALPHAOP:
@@ -1890,29 +1805,16 @@
 	} break;
 
 	case D3DTSS_MAXMIPLEVEL: 
-	    if (dwState == 0) {
-	        TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => 0 (disabled) \n");
-	    } else {
-	        FIXME(" Unhandled stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
-	    }
+	    TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => 0 (disabled) \n");
 	    break;
 
-	case D3DTSS_BORDERCOLOR: {
-	    GLfloat color[4];
-
-	    color[0] = ((dwState >> 16) & 0xFF) / 255.0;
-	    color[1] = ((dwState >>  8) & 0xFF) / 255.0;
-	    color[2] = ((dwState >>  0) & 0xFF) / 255.0;
-	    color[3] = ((dwState >> 24) & 0xFF) / 255.0;
-
-	    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
-
+	case D3DTSS_BORDERCOLOR:
 	    TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
 		  ((dwState >> 16) & 0xFF),
 		  ((dwState >>  8) & 0xFF),
 		  ((dwState >>  0) & 0xFF),
 		  ((dwState >> 24) & 0xFF));
-	} break;
+	    break;
 	    
 	case D3DTSS_TEXCOORDINDEX: {
 	    BOOLEAN handled = TRUE;
@@ -1976,6 +1878,48 @@
     return DD_OK;
 }
 
+static DWORD
+draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
+{
+    IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
+    DWORD stage;
+    
+    for (stage = 0; stage < MAX_TEXTURES; stage++) {
+	IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
+
+	/* First check if we need to bind any other texture for this stage */
+	if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
+	    if (This->current_texture[stage] == NULL) {
+		TRACE(" disabling 2D texturing for stage %ld.\n", stage);
+		glBindTexture(GL_TEXTURE_2D, 0);
+		glDisable(GL_TEXTURE_2D);
+	    } else {
+		GLenum tex_name = ((IDirect3DTextureGLImpl *) surf_ptr->tex_private)->tex_name;
+		
+		if (glThis->current_bound_texture[stage] == NULL) {
+		    if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
+			glEnable(GL_TEXTURE_2D);
+		    }
+		}
+		TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
+		glBindTexture(GL_TEXTURE_2D, tex_name);
+	    }
+
+	    glThis->current_bound_texture[stage] = This->current_texture[stage];
+	}
+
+	/* If no texure valid for this stage, go out of the loop */
+	if (This->current_texture[stage] == NULL) break;
+
+	/* Then check if we need to flush this texture to GL or not (ie did it change) ?.
+	   This will also update the various texture parameters if needed.
+	*/
+	gltex_upload_texture(surf_ptr, This, stage);
+    }
+
+    return stage;
+}
+
 HRESULT WINAPI
 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
 				       DWORD dwStage,
@@ -1991,57 +1935,13 @@
 	IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
     }
     
-    ENTER_GL();
     if (lpTexture2 == NULL) {
 	This->current_texture[dwStage] = NULL;
-
-        TRACE(" disabling 2D texturing.\n");
-	glBindTexture(GL_TEXTURE_2D, 0);
-        glDisable(GL_TEXTURE_2D);
     } else {
         IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
-	GLint max_mip_level;
-	GLfloat color[4];
-	
-	IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7)); /* Not sure about this either */
-
-	if (This->current_texture[dwStage] == tex_impl) {
-	    /* No need to do anything as the texture did not change. */
-	    return DD_OK;
-	}
+	IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
 	This->current_texture[dwStage] = tex_impl;
-	
-	if (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
-	    /* Do not re-enable texturing if it was disabled due to the COLOROP code */
-	    glEnable(GL_TEXTURE_2D);
-	    TRACE(" enabling 2D texturing.\n");
-	}
-	gltex_upload_texture(tex_impl);
-
-	if ((tex_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) == 0) {
-	    max_mip_level = 0;
-	} else {
-	    max_mip_level = tex_impl->surface_desc.u2.dwMipMapCount - 1;
-	}
-
-	/* Now we need to reset all glTexParameter calls for this particular texture... */
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
-			convert_mag_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MAGFILTER - 1]));
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-			convert_min_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MINFILTER - 1],
-						  This->state_block.texture_stage_state[dwStage][D3DTSS_MIPFILTER - 1]));
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
-			convert_tex_address_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1]));
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
-			convert_tex_address_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1]));	
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_level);
-	color[0] = ((This->state_block.texture_stage_state[dwStage][D3DTSS_BORDERCOLOR - 1] >> 16) & 0xFF) / 255.0;
-	color[1] = ((This->state_block.texture_stage_state[dwStage][D3DTSS_BORDERCOLOR - 1] >>  8) & 0xFF) / 255.0;
-	color[2] = ((This->state_block.texture_stage_state[dwStage][D3DTSS_BORDERCOLOR - 1] >>  0) & 0xFF) / 255.0;
-	color[3] = ((This->state_block.texture_stage_state[dwStage][D3DTSS_BORDERCOLOR - 1] >> 24) & 0xFF) / 255.0;
-	glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
     }
-    LEAVE_GL();
     
     return DD_OK;
 }
@@ -2074,6 +1974,7 @@
     
     This->current_material = *lpMat;
 
+    ENTER_GL();
     glMaterialfv(GL_FRONT_AND_BACK,
 		 GL_DIFFUSE,
 		 (float *) &(This->current_material.u.diffuse));
@@ -2089,6 +1990,7 @@
     glMaterialf(GL_FRONT_AND_BACK,
 		GL_SHININESS,
 		This->current_material.u4.power); /* Not sure about this... */
+    LEAVE_GL();
 
     return DD_OK;
 }
@@ -2146,6 +2048,7 @@
     
     if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
 
+    ENTER_GL();
     if (bEnable) {
         if (((0x00000001 << dwLightIndex) & This->set_lights) == 0) {
 	    /* Set the default parameters.. */
@@ -2164,6 +2067,7 @@
         glDisable(GL_LIGHT0 + dwLightIndex);
 	This->active_lights &= ~(0x00000001 << dwLightIndex);
     }
+    LEAVE_GL();
 
     return DD_OK;
 }
@@ -2623,7 +2527,8 @@
     trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] =  1.0;
     trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0;           trans_mat[14] = -1.0;
     trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0;           trans_mat[15] =  1.0;
-    
+
+    ENTER_GL();
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
@@ -2637,12 +2542,14 @@
     glTranslatef(0.375, 0.375, 0);
     glMatrixMode(GL_PROJECTION);
     glLoadMatrixf(trans_mat);
+    LEAVE_GL();
 }
 
 void
 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
 		       D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
 {
+    ENTER_GL();
     if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
         glMatrixMode(GL_MODELVIEW);
 	glLoadMatrixf((float *) view_mat);
@@ -2745,6 +2652,7 @@
 	glMatrixMode(GL_PROJECTION);
 	glLoadMatrixf((float *) proj_mat);
     }
+    LEAVE_GL();
 }
 
 void
@@ -2913,8 +2821,6 @@
     RECT loc_rect;
     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
     GLint depth_test, alpha_test, cull_face, lighting, tex_env, blend, stencil_test, fog;
-    GLuint initial_texture;
-    GLint tex_state;
     int x, y;
     BOOLEAN initial = FALSE;
 
@@ -2928,7 +2834,9 @@
 
     TRACE(" flushing memory back to the frame-buffer (%ld,%ld) x (%ld,%ld).\n", loc_rect.top, loc_rect.left, loc_rect.right, loc_rect.bottom);
 
-    glGetIntegerv(GL_TEXTURE_BINDING_2D, &initial_texture);
+    /* This is a hack to prevent querying the current texture from GL */
+    gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001;
+
     if (gl_d3d_dev->unlock_tex == 0) {
         glGenTextures(1, &gl_d3d_dev->unlock_tex);
 	glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
@@ -2938,11 +2846,11 @@
     } else {
         glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
     }
+
     
     if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
 					  initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != D3D_OK) {
         ERR(" unsupported pixel format at frame buffer flush.\n");
-	glBindTexture(GL_TEXTURE_2D, initial_texture);
 	return;
     }
 	
@@ -2952,7 +2860,6 @@
     glGetIntegerv(GL_CULL_FACE, &cull_face);
     glGetIntegerv(GL_LIGHTING, &lighting);
     glGetIntegerv(GL_BLEND, &blend);
-    glGetIntegerv(GL_TEXTURE_2D, &tex_state);
     glGetIntegerv(GL_FOG, &fog);
     glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_env);
     glMatrixMode(GL_TEXTURE);
@@ -3013,8 +2920,6 @@
     if (cull_face != 0) glEnable(GL_CULL_FACE);
     if (blend != 0) glEnable(GL_BLEND);
     if (fog != 0) glEnable(GL_FOG);
-    glBindTexture(GL_TEXTURE_2D, initial_texture);
-    if (tex_state == 0) glDisable(GL_TEXTURE_2D);
     glDisable(GL_SCISSOR_TEST);
     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
     glPixelStorei(GL_UNPACK_SWAP_BYTES, FALSE);
--- dlls/ddraw_CVS/d3dtexture.c	Mon Jun  2 10:50:35 2003
+++ dlls/ddraw/d3dtexture.c	Mon Jun  2 17:53:04 2003
@@ -89,23 +89,169 @@
 
     FIXME("This is not supported yet... Expect some graphical glitches !!!\n");
 
-    /* GL and memory are in sync again ... */
+    /* GL and memory are in sync again ... 
+       No need to change the 'global' flag as it only handles the 'MEMORY_DIRTY' case.
+    */
     gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
     
     return DD_OK;
 }
 
+static GLenum
+convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState, D3DTEXTUREMIPFILTER dwMipState)
+{
+    GLenum gl_state;
+
+    if (dwMipState == D3DTFP_NONE) {
+        switch (dwMinState) {
+            case D3DTFN_POINT:  gl_state = GL_NEAREST; break;
+	    case D3DTFN_LINEAR: gl_state = GL_LINEAR;  break;
+	    default:            gl_state = GL_LINEAR;  break;
+	}
+    } else if (dwMipState == D3DTFP_POINT) {
+        switch (dwMinState) {
+            case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_NEAREST; break;
+	    case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
+	    default:            gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
+	}
+    } else {
+        switch (dwMinState) {
+            case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_LINEAR; break;
+	    case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
+	    default:            gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
+	}
+    }
+    return gl_state;
+}
+
+static GLenum
+convert_mag_filter_to_GL(D3DTEXTUREMAGFILTER dwState)
+{
+    GLenum gl_state;
+
+    switch (dwState) {
+        case D3DTFG_POINT:
+	    gl_state = GL_NEAREST;
+	    break;
+        case D3DTFG_LINEAR:
+	    gl_state = GL_LINEAR;
+	    break;
+        default:
+	    gl_state = GL_LINEAR;
+	    break;
+    }
+    return gl_state;
+}
+
+static GLenum
+convert_tex_address_to_GL(D3DTEXTUREADDRESS dwState)
+{
+    GLenum gl_state;
+    switch (dwState) {
+        case D3DTADDRESS_WRAP:   gl_state = GL_REPEAT; break;
+	case D3DTADDRESS_CLAMP:  gl_state = GL_CLAMP; break;
+	case D3DTADDRESS_BORDER: gl_state = GL_CLAMP_TO_EDGE; break;
+#if defined(GL_VERSION_1_4)
+	case D3DTADDRESS_MIRROR: gl_state = GL_MIRRORED_REPEAT; break;
+#elif defined(GL_ARB_texture_mirrored_repeat)
+	case D3DTADDRESS_MIRROR: gl_state = GL_MIRRORED_REPEAT_ARB; break;
+#endif
+	default:                 gl_state = GL_REPEAT; break;
+    }
+    return gl_state;
+}
+
 HRESULT
-gltex_upload_texture(IDirectDrawSurfaceImpl *surf_ptr) {
+gltex_upload_texture(IDirectDrawSurfaceImpl *surf_ptr, IDirect3DDeviceImpl *d3ddev, DWORD stage) {
     IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
-    GLuint tex_name = gl_surf_ptr->tex_name;
+    BOOLEAN changed = FALSE;
     
-    TRACE(" activating OpenGL texture id %d.\n", tex_name);
-    glBindTexture(GL_TEXTURE_2D, tex_name);
-
     if (surf_ptr->mipmap_level != 0) {
         WARN(" application activating a sub-level of the mipmapping chain (level %d) !\n", surf_ptr->mipmap_level);
     }
+
+    /* Now check if the texture parameters for this texture are still in-line with what D3D expect
+       us to do..
+
+       NOTE: there is no check for the situation where the same texture is bound to multiple stage
+             but with different parameters per stage.
+    */
+    if ((gl_surf_ptr->tex_parameters == NULL) ||
+	(gl_surf_ptr->tex_parameters[D3DTSS_MAXMIPLEVEL - D3DTSS_ADDRESSU] != 
+	 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1])) {
+	DWORD max_mip_level;
+	
+	if ((surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) == 0) {
+	    max_mip_level = 0;
+	} else {
+	    max_mip_level = surf_ptr->surface_desc.u2.dwMipMapCount - 1;
+	    if (d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] != 0) {
+		if (max_mip_level >= d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1]) {
+		    max_mip_level = d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] - 1;
+		}
+	    }
+	}
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_level);
+	changed = TRUE;
+    }
+    
+    if ((gl_surf_ptr->tex_parameters == NULL) ||
+	(gl_surf_ptr->tex_parameters[D3DTSS_MAGFILTER - D3DTSS_ADDRESSU] != 
+	 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAGFILTER - 1])) {
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
+			convert_mag_filter_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAGFILTER - 1]));
+	changed = TRUE;
+    }
+    if ((gl_surf_ptr->tex_parameters == NULL) ||
+	(gl_surf_ptr->tex_parameters[D3DTSS_MINFILTER - D3DTSS_ADDRESSU] != 
+	 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MINFILTER - 1]) ||
+	(gl_surf_ptr->tex_parameters[D3DTSS_MIPFILTER - D3DTSS_ADDRESSU] != 
+	 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MIPFILTER - 1])) {
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+			convert_min_filter_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_MINFILTER - 1],
+						 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MIPFILTER - 1]));
+	changed = TRUE;
+    }
+    if ((gl_surf_ptr->tex_parameters == NULL) ||
+	(gl_surf_ptr->tex_parameters[D3DTSS_ADDRESSU - D3DTSS_ADDRESSU] != 
+	 d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1])) {
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+			convert_tex_address_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1]));
+	changed = TRUE;
+    }
+    if ((gl_surf_ptr->tex_parameters == NULL) ||
+	(gl_surf_ptr->tex_parameters[D3DTSS_ADDRESSV - D3DTSS_ADDRESSU] != 
+	 d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSV - 1])) {
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+			convert_tex_address_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSV - 1]));	
+	changed = TRUE;
+    }
+    if ((gl_surf_ptr->tex_parameters == NULL) ||
+	(gl_surf_ptr->tex_parameters[D3DTSS_BORDERCOLOR - D3DTSS_ADDRESSU] != 
+	 d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1])) {
+	GLfloat color[4];
+	
+	color[0] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 16) & 0xFF) / 255.0;
+	color[1] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >>  8) & 0xFF) / 255.0;
+	color[2] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >>  0) & 0xFF) / 255.0;
+	color[3] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 24) & 0xFF) / 255.0;
+	glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
+	changed = TRUE;
+    }
+
+    if (changed == TRUE) {
+	if (gl_surf_ptr->tex_parameters == NULL) {
+	    gl_surf_ptr->tex_parameters = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+						    sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU));
+	}
+	memcpy(gl_surf_ptr->tex_parameters, &(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1]),
+	       sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU));
+    }
+
+    if (*(gl_surf_ptr->global_dirty_flag) != SURFACE_MEMORY_DIRTY) {
+	TRACE(" nothing to do - memory copy and GL state in synch for all texture levels.\n");
+	return DD_OK;
+    }
     
     while (surf_ptr != NULL) {
         IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
@@ -133,7 +279,9 @@
 	    surf_ptr = NULL;
 	}
     }
-
+    
+    *(gl_surf_ptr->global_dirty_flag) = SURFACE_MEMORY;
+    
     return DD_OK;
 }
 
@@ -164,6 +312,7 @@
     }
 
     glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
+    *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
     /* TODO: check color-keying on mipmapped surfaces... */
     
     return DD_OK;
@@ -277,6 +426,7 @@
 	    glBindTexture(GL_TEXTURE_2D, cur_tex);
 	    LEAVE_GL();
 	    
+	    /* The SURFACE_GL case is not handled by the 'global' dirty flag */
 	    gl_surf_ptr->dirty_flag = SURFACE_GL;
 	    
 	    return DD_OK;
@@ -353,6 +503,7 @@
     
     /* And set the dirty flag */
     glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
+    *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
     
     /* TODO: check palette on mipmapped surfaces...
        TODO: do we need to re-upload in case of usage of the paletted texture extension ? */
@@ -408,8 +559,10 @@
     glThis->unlock_update(This, pRect);
     
     /* Set the dirty flag according to the lock type */
-    if ((This->lastlocktype & DDLOCK_READONLY) == 0)
+    if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
         glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
+	*(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
+    }
 }
 
 HRESULT WINAPI
@@ -499,6 +652,7 @@
 
 		/* Set this texture as dirty */
 		gl_dst_ptr->dirty_flag = SURFACE_MEMORY_DIRTY;
+		*(gl_dst_ptr->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
 	    }
 	}
 
@@ -682,16 +836,19 @@
 	   to save those... */
 	surf->aux_blt = gltex_blt;
 	surf->aux_bltfast = gltex_bltfast;
-	
+
 	ENTER_GL();
 	if (surf->mipmap_level == 0) {
 	    glGenTextures(1, &(private->tex_name));
 	    if (private->tex_name == 0) ERR("Error at creation of OpenGL texture ID !\n");
 	    TRACE(" GL texture created for surface %p (private data at %p and GL id %d).\n", surf, private, private->tex_name);
+	    private->__global_dirty_flag = (at_creation == FALSE ? SURFACE_MEMORY_DIRTY : SURFACE_MEMORY);
+	    private->global_dirty_flag = &(private->__global_dirty_flag);
 	} else {
 	    private->tex_name = ((IDirect3DTextureGLImpl *) (main->tex_private))->tex_name;
 	    TRACE(" GL texture created for surface %p (private data at %p and GL id reusing id %d from surface %p (%p)).\n",
 		  surf, private, private->tex_name, main, main->tex_private);
+	    private->global_dirty_flag = &(((IDirect3DTextureGLImpl *) (main->tex_private))->__global_dirty_flag);
 	}
 	LEAVE_GL();
 
--- dlls/ddraw_CVS/mesa_private.h	Sun Jun  1 20:56:09 2003
+++ dlls/ddraw/mesa_private.h	Mon Jun  2 16:15:02 2003
@@ -68,6 +68,18 @@
     BOOLEAN initial_upload_done;
     SURFACE_STATE dirty_flag;
 
+    /* This is used to optimize dirty checking in case of mipmapping.
+       Note that a bitmap could have been used but it was not worth the pain as it will be very rare
+       to have only one mipmap level change...
+
+       The __global_dirty_flag will only be set for the main mipmap level.
+    */
+    SURFACE_STATE __global_dirty_flag;
+    SURFACE_STATE *global_dirty_flag;
+    
+    /* This is to optimize the 'per-texture' parameters. */
+    DWORD *tex_parameters;
+    
     /* Surface optimization */
     void *surface_ptr;
 
@@ -94,6 +106,9 @@
     
     GLXContext gl_context;
 
+    /* This stores the textures which are actually bound to the GL context */
+    IDirectDrawSurfaceImpl *current_bound_texture[MAX_TEXTURES];
+
     /* The last type of vertex drawn */
     GL_TRANSFORM_STATE transform_state;
 
@@ -139,7 +154,7 @@
 extern HRESULT d3ddevice_find(IDirectDrawImpl *d3d, LPD3DFINDDEVICESEARCH lpD3DDFS, LPD3DFINDDEVICERESULT lplpD3DDevice);
 
 /* Used to upload the texture */
-extern HRESULT gltex_upload_texture(IDirectDrawSurfaceImpl *This) ;
+extern HRESULT gltex_upload_texture(IDirectDrawSurfaceImpl *This, IDirect3DDeviceImpl *d3ddev, DWORD stage) ;
 
 /* Used to set-up our orthographic projection */
 extern void d3ddevice_set_ortho(IDirect3DDeviceImpl *This) ;


More information about the wine-patches mailing list