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.
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 11b5707..354f214 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -716,7 +716,7 @@
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 @@
} 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 c40b314..b9c0be9 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -284,8 +284,13 @@
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 @@
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 @@
} 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 @@
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 @@
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 e6c7b31..e437aa2 100644
--- a/dlls/wined3d/wined3d_main.c
+++ b/dlls/wined3d/wined3d_main.c
@@ -113,24 +113,24 @@
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 @@
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 @@
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 4b2c781..84edf86 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -110,21 +110,26 @@
/**
* 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;