From 9e6957bbdcdb0d39704184eb6b60b35c14914dc8 Mon Sep 17 00:00:00 2001 From: Oliver Stieber Date: Fri, 23 Sep 2005 11:08:03 +0000 Subject: [PATCH] Optionally repack nonpower 2 textures to the expected span length when a textures is locked. This is necessary for buggy games like Warhammer 40k that don't work with the odd span sizes produce by default nonpower 2 support. --- dlls/wined3d/device.c | 32 ++++++++++---- dlls/wined3d/surface.c | 79 +++++++++++++++++++++++++++++++--- dlls/wined3d/wined3d_main.c | 67 +++++++++++++++++----------- dlls/wined3d/wined3d_private.h | 19 +++++--- 4 files changed, 149 insertions(+), 48 deletions(-) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 11b5707d485..354f214084c 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -716,7 +716,7 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Wid Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) { Size = ((max(pow2Width,4) * D3DFmtGetBpp(This, Format)) * max(pow2Height,4)); } else { - Size = (pow2Width * D3DFmtGetBpp(This, Format)) * pow2Height; + Size = (pow2Width * D3DFmtGetBpp(This, Format)) * pow2Height; } /** Create the and initilise surface resource **/ @@ -5161,21 +5161,35 @@ HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3 } else { - /* some applications cannot handle odd pitches returned by soft non-power2, so we have - to repack the data from pow2Width/Height to expected Width,Height, this makes the - data returned by GetData non-power2 width/height with hardware non-power2 - pow2Width/height are set to surface width height, repacking isn't needed so it - doesn't matter which function gets called. */ - glTexSubImage2D(glDescription->target + if (NP2_REPACK == wined3d_settings.nonpower2_mode) { + /* some applications cannot handle odd pitches returned by soft non-power2, so we have + to repack the data from pow2Width/Height to expected Width,Height, this makes the + data returned by GetData non-power2 width/height with hardware non-power2 + pow2Width/height are set to surface width height, repacking isn't needed so it + doesn't matter which function gets called. */ + glTexSubImage2D(glDescription->target + ,glDescription->level + ,destLeft + ,destTop + ,srcWidth + ,srcHeight + ,glDescription->glFormat + ,glDescription->glType + ,IWineD3DSurface_GetData(pSourceSurface) + ); + } else { + /* not repacked, the data returned by IWineD3DSurface_GetData is pow2Width x pow2Height */ + glTexSubImage2D(glDescription->target ,glDescription->level ,destLeft ,destTop - ,srcWidth - ,srcHeight + ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Width + ,((IWineD3DSurfaceImpl *)pSourceSurface)->pow2Height ,glDescription->glFormat ,glDescription->glType ,IWineD3DSurface_GetData(pSourceSurface) ); + } } } diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index c40b314a0fd..b9c0be9bc09 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -284,8 +284,13 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RE else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */ pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 4; - else - pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */ + else { + if (NP2_REPACK == wined3d_settings.nonpower2_mode) { + pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */ + } else { + pLockedRect->Pitch = This->bytesPerPixel * This->pow2Width; + } + } if (NULL == pRect) { pLockedRect->pBits = This->resource.allocatedMemory; @@ -355,6 +360,65 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RE This->glDescription.glType, This->resource.allocatedMemory); vcheckGLcall("glGetTexImage"); + if (NP2_REPACK == wined3d_settings.nonpower2_mode) { + /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing + the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to + repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width. + + Were doing this... + + instead of boxing the texture : + |<-texture width ->| -->pow2width| /\ + |111111111111111111| | | + |222 Texture 222222| boxed empty | texture height + |3333 Data 33333333| | | + |444444444444444444| | \/ + ----------------------------------- | + | boxed empty | boxed empty | pow2height + | | | \/ + ----------------------------------- + + + were repacking the data to the expected texture width + + |<-texture width ->| -->pow2width| /\ + |111111111111111111222222222222222| | + |222333333333333333333444444444444| texture height + |444444 | | + | | \/ + | | | + | empty | pow2height + | | \/ + ----------------------------------- + + == is the same as + + |<-texture width ->| /\ + |111111111111111111| + |222222222222222222|texture height + |333333333333333333| + |444444444444444444| \/ + -------------------- + + this also means that any references to allocatedMemory should work with the data as if were a standard texture with a non-power2 width instead of texture boxed up to be a power2 texture. + + internally the texture is still stored in a boxed format so any references to textureName will get a boxed texture with width pow2width and not a texture of width currentDesc.Width. + */ + if (This->nonpow2) { + BYTE* dataa, *datab; + int pitcha = 0, pitchb = 0; + int y; + pitcha = This->bytesPerPixel * This->currentDesc.Width; + pitchb = This->bytesPerPixel * This->pow2Width; + datab = dataa = This->resource.allocatedMemory; + FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb); + for (y = 1 ; y < This->currentDesc.Height; y++) { + dataa += pitcha; /* skip the first row */ + datab += pitchb; + memcpy(dataa, datab, pitcha); + } + } + } } LEAVE_GL(); } else { /* Nothing to do */ @@ -945,7 +1009,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) { } else { /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */ - if (This->nonpow2 == TRUE) { + if (NP2_REPACK == wined3d_settings.nonpower2_mode && This->nonpow2 == TRUE) { + TRACE("non power of two support\n"); ENTER_GL(); @@ -997,8 +1062,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) { This->glDescription.level, debug_d3dformat(This->resource.format), This->glDescription.glFormatInternal, - This->currentDesc.Width, - This->currentDesc.Height, + This->pow2Width, + This->pow2Height, 0, This->glDescription.glFormat, This->glDescription.glType, @@ -1008,8 +1073,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) { glTexImage2D(This->glDescription.target, This->glDescription.level, This->glDescription.glFormatInternal, - This->currentDesc.Width, - This->currentDesc.Height, + This->pow2Width, + This->pow2Height, 0 /* border */, This->glDescription.glFormat, This->glDescription.glType, diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index e6c7b3136f6..e437aa2d15b 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -113,24 +113,24 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) len = GetModuleFileNameA( 0, buffer, MAX_PATH ); if (len && len < MAX_PATH) { - HKEY tmpkey; - /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */ - if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey )) - { - char *p, *appname = buffer; - if ((p = strrchr( appname, '/' ))) appname = p + 1; - if ((p = strrchr( appname, '\\' ))) appname = p + 1; - strcat( appname, "\\Direct3D" ); - TRACE("appname = [%s] \n", appname); - if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; - RegCloseKey( tmpkey ); - } + HKEY tmpkey; + /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */ + if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey )) + { + char *p, *appname = buffer; + if ((p = strrchr( appname, '/' ))) appname = p + 1; + if ((p = strrchr( appname, '\\' ))) appname = p + 1; + strcat( appname, "\\Direct3D" ); + TRACE("appname = [%s] \n", appname); + if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; + RegCloseKey( tmpkey ); + } } if ( 0 != hkey || 0 != appkey ) { - if ( !get_config_key( hkey, appkey, "VertexShaderMode", buffer, size) ) - { + if ( !get_config_key( hkey, appkey, "VertexShaderMode", buffer, size) ) + { if (!strcmp(buffer,"none")) { TRACE("Disable vertex shaders\n"); @@ -141,33 +141,48 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) TRACE("Force SW vertex shaders\n"); wined3d_settings.vs_mode = VS_SW; } - } - if ( !get_config_key( hkey, appkey, "PixelShaderMode", buffer, size) ) - { + } + if ( !get_config_key( hkey, appkey, "PixelShaderMode", buffer, size) ) + { if (!strcmp(buffer,"enabled")) { TRACE("Allow pixel shaders\n"); wined3d_settings.ps_mode = PS_HW; } - if (!strcmp(buffer,"disabled")) + if (!strcmp(buffer,"disabled")) { TRACE("Disable pixel shaders\n"); wined3d_settings.ps_mode = PS_NONE; } - } - if ( !get_config_key( hkey, appkey, "VertexBufferMode", buffer, size) ) - { + } + if ( !get_config_key( hkey, appkey, "VertexBufferMode", buffer, size) ) + { if (!strcmp(buffer,"none")) { TRACE("Disable Vertex Buffer Hardware support\n"); - wined3d_settings.vbo_mode = VS_NONE; + wined3d_settings.vbo_mode = VBO_NONE; } else if (!strcmp(buffer,"hardware")) { - TRACE("Allow Vertex Buffer Hardware support\n"); - wined3d_settings.vbo_mode = VS_HW; + TRACE("Allow Vertex Buffer Hardware support\n"); + wined3d_settings.vbo_mode = VBO_HW; } - } + } + if ( !get_config_key( hkey, appkey, "Nonpower2Mode", buffer, size) ) + { + if (!strcmp(buffer,"none")) + { + TRACE("Using default non-power2 textures\n"); + wined3d_settings.nonpower2_mode = NP2_NONE; + + } + else if (!strcmp(buffer,"repack")) + { + TRACE("Repacking non-power2 textre\n"); + wined3d_settings.nonpower2_mode = NP2_REPACK; + } + /* There will be a couple of other choices for nonpow2, they are: TextureRecrangle and OpenGL 2 */ + } } if (wined3d_settings.vs_mode == VS_HW) TRACE("Allow HW vertex shaders\n"); @@ -175,6 +190,8 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) TRACE("Disable pixel shaders\n"); if (wined3d_settings.vbo_mode == VBO_NONE) TRACE("Disable Vertex Buffer Hardware support\n"); + if (wined3d_settings.nonpower2_mode == NP2_REPACK) + TRACE("Repacking non-power2 textures\n"); if (appkey) RegCloseKey( appkey ); if (hkey) RegCloseKey( hkey ); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 4b2c781b6d5..84edf86c008 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -110,21 +110,26 @@ UINT static const glTypeLookup[D3DDECLTYPE_UNUSED][5] = { /** * Settings */ -#define VS_NONE 0 -#define VS_HW 1 -#define VS_SW 2 +#define VS_NONE 0 +#define VS_HW 1 +#define VS_SW 2 -#define PS_NONE 0 -#define PS_HW 1 +#define PS_NONE 0 +#define PS_HW 1 -#define VBO_NONE 0 -#define VBO_HW 1 +#define VBO_NONE 0 +#define VBO_HW 1 + +#define NP2_NONE 0 +#define NP2_REPACK 1 typedef struct wined3d_settings_s { /* vertex and pixel shader modes */ int vs_mode; int ps_mode; int vbo_mode; +/* nonpower 2 function */ + int nonpower2_mode; } wined3d_settings_t; extern wined3d_settings_t wined3d_settings;