Note that this gives us about a 40 % increase in performance in the 'low details' setting of Adventure/3DMark2000 in my case (but pretty marginal in the middle and high level settings). Note also that there are pretty big graphical corruptions in 3DMark2000 due to this patch (whereas it works fine in most other games I tested like Sacrifice, SystemShock2, ...). Will fix the corruptions later :-) Lionel Changelog: - add support for multi-texturing -- Lionel Ulmer - http://www.bbrox.org/
--- dlls/ddraw_CVS/d3ddevice/mesa.c Sun Aug 3 08:07:02 2003 +++ dlls/ddraw/d3ddevice/mesa.c Sun Aug 17 14:37:42 2003 @@ -102,6 +102,10 @@ IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev; DWORD opt_bitmap = 0x00000000; + if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) { + GL_extensions.glActiveTexture(GL_TEXTURE0_WINE); + gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE; + } if (gl_d3d_dev->unlock_tex == 0) { glGenTextures(1, &gl_d3d_dev->unlock_tex); glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex); @@ -128,6 +132,15 @@ if ((gl_d3d_dev->current_bound_texture[0] == NULL) || (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE)) glEnable(GL_TEXTURE_2D); + if (gl_d3d_dev->current_bound_texture[1] != NULL) { + if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) { + GL_extensions.glActiveTexture(GL_TEXTURE1_WINE); + gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE; + } + /* 'unbound' texture level 1 in that case to disable multi-texturing */ + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + } glEnable(GL_SCISSOR_TEST); if ((d3d_dev->active_viewport.dvMinZ != 0.0) || (d3d_dev->active_viewport.dvMaxZ != 1.0)) { @@ -201,6 +214,7 @@ /* This is a hack to prevent querying the current texture from GL. Basically, at the next DrawPrimitive call, this will bind the correct texture to this stage. */ gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001; + gl_d3d_dev->current_bound_texture[1] = (IDirectDrawSurfaceImpl *) 0x00000000; if (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE) glDisable(GL_TEXTURE_2D); } @@ -1201,8 +1215,11 @@ glTexCoord2fv(coords); } inline static void handle_textures(D3DVALUE *coords, int tex_stage) { - /* For the moment, draw only the first texture.. */ - if (tex_stage == 0) glTexCoord2fv(coords); + if (GL_extensions.glMultiTexCoord2fv) { + GL_extensions.glMultiTexCoord2fv(GL_TEXTURE0_WINE + tex_stage, coords); + } else { + if (tex_stage == 0) glTexCoord2fv(coords); + } } static void draw_primitive_strided(IDirect3DDeviceImpl *This, @@ -1244,6 +1261,13 @@ /* Compute the number of active texture stages and set the various texture parameters */ num_active_stages = draw_primitive_handle_textures(This); + /* And restore to handle '0' in the case we use glTexCorrd calls */ + if (glThis->current_active_tex_unit != GL_TEXTURE0_WINE) { + GL_extensions.glActiveTexture(GL_TEXTURE0_WINE); + glThis->current_active_tex_unit = GL_TEXTURE0_WINE; + } + + draw_primitive_handle_GL_state(This, (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ, vertex_lighted); @@ -1668,11 +1692,21 @@ IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This; const char *type; DWORD prev_state; + GLenum unit; TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState); - if (dwStage > 0) return DD_OK; /* We nothing in this case for now */ + if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) || + ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) { + return DD_OK; + } + unit = GL_TEXTURE0_WINE + dwStage; + if (unit != glThis->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + glThis->current_active_tex_unit = unit; + } + switch (d3dTexStageStateType) { #define GEN_CASE(a) case a: type = #a; break GEN_CASE(D3DTSS_COLOROP); @@ -1801,12 +1835,12 @@ default: value = "UNKNOWN"; } - if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE) && (dwStage == 0)) { + if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE)) { glDisable(GL_TEXTURE_2D); TRACE(" disabling 2D texturing.\n"); } else { /* Re-enable texturing */ - if ((dwStage == 0) && (This->current_texture[0] != NULL)) { + if (This->current_texture[0] != NULL) { glEnable(GL_TEXTURE_2D); TRACE(" enabling 2D texturing.\n"); } @@ -2046,16 +2080,32 @@ for (stage = 0; stage < MAX_TEXTURES; stage++) { IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage]; + GLenum unit; /* 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); + + unit = GL_TEXTURE0_WINE + stage; + if (unit != glThis->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + glThis->current_active_tex_unit = unit; + } glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); + + if (stage == 0) { + glDisable(GL_TEXTURE_2D); + } } else { GLenum tex_name = ((IDirect3DTextureGLImpl *) surf_ptr->tex_private)->tex_name; + unit = GL_TEXTURE0_WINE + stage; + if (unit != glThis->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + glThis->current_active_tex_unit = unit; + } + if (glThis->current_bound_texture[stage] == NULL) { if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) { TRACE(" enabling 2D texturing and"); @@ -2096,8 +2146,14 @@ ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface); TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2); - - if (dwStage > 0) return DD_OK; + + if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) || + ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) { + if (lpTexture2 != NULL) { + WARN(" setting a texture to a non-supported texture stage !\n"); + } + return DD_OK; + } if (This->current_texture[dwStage] != NULL) { IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7)); @@ -3254,25 +3310,29 @@ { ENTER_GL(); for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) { + GLenum unit = GL_TEXTURE0_WINE + tex_stage; if (matrices & tex_mat) { if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) { - if (tex_stage == 0) { - /* No multi-texturing support for now ... */ - glMatrixMode(GL_TEXTURE); - glLoadMatrixf((float *) This->tex_mat[tex_stage]); - if (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE))) { - This->tex_mat_is_identity[tex_stage] = FALSE; - } else { - This->tex_mat_is_identity[tex_stage] = TRUE; + int is_identity = (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE)) != 0); + + if (This->tex_mat_is_identity[tex_stage] != is_identity) { + if (glThis->current_active_tex_unit != unit) { + GL_extensions.glActiveTexture(unit); + glThis->current_active_tex_unit = unit; } + glMatrixMode(GL_TEXTURE); + glLoadMatrixf((float *) This->tex_mat[tex_stage]); } + This->tex_mat_is_identity[tex_stage] = is_identity; } else { - if (tex_stage == 0) { - if (This->tex_mat_is_identity[tex_stage] == FALSE) { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - This->tex_mat_is_identity[tex_stage] = TRUE; + if (This->tex_mat_is_identity[tex_stage] == FALSE) { + if (glThis->current_active_tex_unit != unit) { + GL_extensions.glActiveTexture(unit); + glThis->current_active_tex_unit = unit; } + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + This->tex_mat_is_identity[tex_stage] = TRUE; } } } @@ -3729,6 +3789,10 @@ glDisable(GL_FOG); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); gl_object->current_tex_env = GL_REPLACE; + gl_object->current_active_tex_unit = GL_TEXTURE0_WINE; + if (GL_extensions.glActiveTexture != NULL) { + GL_extensions.glActiveTexture(GL_TEXTURE0_WINE); + } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDrawBuffer(buffer); @@ -3809,7 +3873,7 @@ GLint max_clip_planes; /* Fill first all the fields with default values which will be overriden later on with - corrent one from the GL code + correct ones from the GL code */ opengl_device_caps.dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY | @@ -3834,10 +3898,18 @@ opengl_device_caps.dvExtentsAdjust = 0.0; opengl_device_caps.dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP | D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO; - opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1; - opengl_device_caps.dwTextureOpCaps = 0; - opengl_device_caps.wMaxTextureBlendStages = 1; - opengl_device_caps.wMaxSimultaneousTextures = 1; + opengl_device_caps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE4X | + D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED2X | D3DTEXOPCAPS_ADDSIGNED | + D3DTEXOPCAPS_BLENDDIFFUSEALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHA | D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDCURRENTALPHA; + if (GL_extensions.max_texture_units != 0) { + opengl_device_caps.wMaxTextureBlendStages = GL_extensions.max_texture_units; + opengl_device_caps.wMaxSimultaneousTextures = GL_extensions.max_texture_units; + opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | GL_extensions.max_texture_units; + } else { + opengl_device_caps.wMaxTextureBlendStages = 1; + opengl_device_caps.wMaxSimultaneousTextures = 1; + opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1; + } opengl_device_caps.dwMaxActiveLights = 16; opengl_device_caps.dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */ opengl_device_caps.deviceGUID = IID_IDirect3DTnLHalDevice; @@ -3939,17 +4011,36 @@ */ if ((strstr(glExtensions, "GL_ARB_texture_mirrored_repeat")) || (strstr(glExtensions, "GL_IBM_texture_mirrored_repeat")) || - ((major >= 1) && (minor >= 4))) { + (major > 1) || + ((major == 1) && (minor >= 4))) { TRACE(" - mirrored repeat\n"); GL_extensions.mirrored_repeat = TRUE; } /* Texture LOD Bias : - - GL_EXT_texture_lod_bias + - GL_EXT_texture_lod_bias */ if (strstr(glExtensions, "GL_EXT_texture_lod_bias")) { TRACE(" - texture lod bias\n"); GL_extensions.mipmap_lodbias = TRUE; + } + + /* For all subsequent extensions, we need glXGetProcAddress */ + if (pglXGetProcAddressARB != NULL) { + /* Multi-texturing : + - GL_ARB_multitexture + - GL >= 1.2.1 + */ + if ((strstr(glExtensions, "GL_ARB_multitexture")) || + (major > 1) || + ((major == 1) && (minor > 2)) || + ((major == 1) && (minor == 2) && (patch >= 1))) { + glGetIntegerv(GL_MAX_TEXTURE_UNITS_WINE, &(GL_extensions.max_texture_units)); + TRACE(" - multi-texturing (%d stages)\n", GL_extensions.max_texture_units); + /* We query the ARB version to be the most portable we can... */ + GL_extensions.glActiveTexture = pglXGetProcAddressARB("glActiveTextureARB"); + GL_extensions.glMultiTexCoord2fv = pglXGetProcAddressARB("glMultiTexCoord2fv"); + } } /* Fill the D3D capabilities according to what GL tells us... */ --- dlls/ddraw_CVS/d3dtexture.c Sat Aug 2 18:03:07 2003 +++ dlls/ddraw/d3dtexture.c Sun Aug 17 14:42:06 2003 @@ -162,7 +162,9 @@ HRESULT gltex_upload_texture(IDirectDrawSurfaceImpl *surf_ptr, IDirect3DDeviceImpl *d3ddev, DWORD stage) { IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private; + IDirect3DDeviceGLImpl *gl_d3ddev = (IDirect3DDeviceGLImpl *) d3ddev; BOOLEAN changed = FALSE; + GLenum unit = GL_TEXTURE0_WINE + stage; if (surf_ptr->mipmap_level != 0) { WARN(" application activating a sub-level of the mipmapping chain (level %d) !\n", surf_ptr->mipmap_level); @@ -189,6 +191,10 @@ } } } + if (unit != gl_d3ddev->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + gl_d3ddev->current_active_tex_unit = unit; + } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_level); changed = TRUE; } @@ -196,6 +202,10 @@ 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])) { + if (unit != gl_d3ddev->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + gl_d3ddev->current_active_tex_unit = unit; + } 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; @@ -205,6 +215,10 @@ 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])) { + if (unit != gl_d3ddev->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + gl_d3ddev->current_active_tex_unit = unit; + } 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])); @@ -213,6 +227,10 @@ 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])) { + if (unit != gl_d3ddev->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + gl_d3ddev->current_active_tex_unit = unit; + } 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; @@ -220,6 +238,10 @@ 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])) { + if (unit != gl_d3ddev->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + gl_d3ddev->current_active_tex_unit = unit; + } 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; @@ -233,6 +255,10 @@ 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; + if (unit != gl_d3ddev->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + gl_d3ddev->current_active_tex_unit = unit; + } glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); changed = TRUE; } @@ -265,6 +291,11 @@ snoop_texture(surf_ptr); } + if (unit != gl_d3ddev->current_active_tex_unit) { + GL_extensions.glActiveTexture(unit); + gl_d3ddev->current_active_tex_unit = unit; + } + if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format), gl_surf_ptr->initial_upload_done == FALSE, TRUE, 0, 0) == DD_OK) { upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr)); --- dlls/ddraw_CVS/main.c Fri Aug 1 21:38:18 2003 +++ dlls/ddraw/main.c Thu Aug 14 23:11:38 2003 @@ -83,7 +83,7 @@ { char *glname = SONAME_LIBGL; BOOL ret_value; - + gl_handle = wine_dlopen(glname, RTLD_NOW, NULL, 0); if (!gl_handle) { WARN("Wine cannot find the OpenGL graphics library (%s).\n",glname); --- dlls/ddraw_CVS/mesa_private.h Sun Aug 3 08:07:02 2003 +++ dlls/ddraw/mesa_private.h Sat Aug 16 18:22:27 2003 @@ -143,6 +143,7 @@ D3DVALUE prev_clear_Z; BOOLEAN depth_mask, depth_test, alpha_test, stencil_test, cull_face, lighting, blending, fogging; GLenum current_tex_env; + GLenum current_active_tex_unit; } IDirect3DDeviceGLImpl; /* This is for the OpenGL additions... */ @@ -162,7 +163,12 @@ typedef struct { /* Mirrored Repeat */ BOOLEAN mirrored_repeat; + /* Mipmap lod-bias */ BOOLEAN mipmap_lodbias; + /* Multi-texturing */ + GLint max_texture_units; + void (*glActiveTexture)(GLenum texture); + void (*glMultiTexCoord2fv)(GLenum target, const GLfloat *v); } GL_EXTENSIONS_LIST; extern GL_EXTENSIONS_LIST GL_extensions; --- dlls/ddraw_CVS/gl_private.h Sun Aug 3 08:07:02 2003 +++ dlls/ddraw/gl_private.h Sat Aug 16 20:12:14 2003 @@ -57,6 +57,15 @@ #define GL_MIRRORED_REPEAT_WINE 0x8370 #define GL_TEXTURE_FILTER_CONTROL_WINE 0x8500 #define GL_TEXTURE_LOD_BIAS_WINE 0x8501 +#define GL_TEXTURE0_WINE 0x84C0 +#define GL_TEXTURE1_WINE 0x84C1 +#define GL_TEXTURE2_WINE 0x84C2 +#define GL_TEXTURE3_WINE 0x84C3 +#define GL_TEXTURE4_WINE 0x84C4 +#define GL_TEXTURE5_WINE 0x84C5 +#define GL_TEXTURE6_WINE 0x84C6 +#define GL_TEXTURE7_WINE 0x84C7 +#define GL_MAX_TEXTURE_UNITS_WINE 0x84E2 #ifndef GLPRIVATE_NO_REDEFINE