From e31bc6cea427d8ae22d9ac0b9213c475c0ed6cc7 Mon Sep 17 00:00:00 2001 From: Oliver Stieber Date: Wed, 3 Aug 2005 19:49:05 +0000 Subject: [PATCH] Moved support for non power 2 texture to hardware. Fix for the texture state separation patches, ApplyTextureStates is now called instead of being commented out. --- dlls/wined3d/basetexture.c | 2 +- dlls/wined3d/cubetexture.c | 31 +++++++++++++ dlls/wined3d/device.c | 85 ++++++++++++++++++++++------------ dlls/wined3d/drawprim.c | 29 +++--------- dlls/wined3d/texture.c | 37 ++++++++++++++- dlls/wined3d/utils.c | 3 -- dlls/wined3d/wined3d_private.h | 5 ++ 7 files changed, 133 insertions(+), 59 deletions(-) diff --git a/dlls/wined3d/basetexture.c b/dlls/wined3d/basetexture.c index d309ec6a48..b8732eb668 100644 --- a/dlls/wined3d/basetexture.c +++ b/dlls/wined3d/basetexture.c @@ -287,7 +287,7 @@ HRESULT WINAPI IWineD3DBaseTextureImpl_BindTexture(IWineD3DBaseTexture *iface) { } glBindTexture(textureDimensions, This->baseTexture.textureName); checkGLcall("glBindTexture"); - if (isNewTexture || (TRUE && This->baseTexture.levels >1)) { + if (isNewTexture) { /* For a new texture we have to set the textures levels after binding the texture, * in theory this is all we should ever have to dom, but because ATI's drivers are broken we * also need to set the texture dimensins before the texture is is set */ diff --git a/dlls/wined3d/cubetexture.c b/dlls/wined3d/cubetexture.c index 9571ffda36..e659a9f63b 100644 --- a/dlls/wined3d/cubetexture.c +++ b/dlls/wined3d/cubetexture.c @@ -220,7 +220,38 @@ UINT WINAPI IWineD3DCubeTextureImpl_GetTextureDimensions(IWineD3DCubeTexture *if void WINAPI IWineD3DCubeTextureImpl_ApplyStateChanges(IWineD3DCubeTexture *iface, const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1], const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + float matrix[16]; IWineD3DBaseTextureImpl_ApplyStateChanges((IWineD3DBaseTexture *)iface, textureStates, samplerStates); + + + /* Apply non-power2 mappings and texture offsets so long as the texture coords aren't projected or generated */ + if(This->pow2scalingFactor != 1.0f) { + if((textureStates[WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) == D3DTSS_TCI_PASSTHRU && (~textureStates[WINED3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) { + glMatrixMode(GL_TEXTURE); + memset(matrix, 0 , sizeof(matrix)); + + matrix[0] = This->pow2scalingFactor; + matrix[5] = This->pow2scalingFactor; + matrix[10] = This->pow2scalingFactor; +#if 0 /* Translation fixup is no longer required (here for reminder) */ + matrix[12] = -0.25f / (float)This->edgeLength; + matrix[13] = -0.75f / (float)This->edgeLength; + matrix[14] = -0.25f / (float)This->edgeLength; +#endif + TRACE("(%p) Setup Matrix:\n", This); + TRACE(" %f %f %f %f\n", matrix[0], matrix[1], matrix[2], matrix[3]); + TRACE(" %f %f %f %f\n", matrix[4], matrix[5], matrix[6], matrix[7]); + TRACE(" %f %f %f %f\n", matrix[8], matrix[9], matrix[10], matrix[11]); + TRACE(" %f %f %f %f\n", matrix[12], matrix[13], matrix[14], matrix[15]); + TRACE("\n"); + glMultMatrixf(matrix); + } else { + /* I don't expect nonpower 2 textures to be used with generated texture coordinates, but if they are present a fixme. */ + FIXME("Non-power2 texture being used with generated texture coords\n"); + } + } + } diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index b8d27ac1c7..6ae06bf471 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -615,13 +615,13 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Wid *********************************/ if (Format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */ - Size = ((max(Width,4) * D3DFmtGetBpp(This, Format)) * max(Height,4)) >> 1; + Size = ((max(pow2Width,4) * D3DFmtGetBpp(This, Format)) * max(pow2Height,4)) >> 1; } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) { - Size = ((max(Width,4) * D3DFmtGetBpp(This, Format)) * max(Height,4)); + Size = ((max(pow2Width,4) * D3DFmtGetBpp(This, Format)) * max(pow2Height,4)); } else { - Size = (Width * D3DFmtGetBpp(This, Format)) * Height; + Size = (pow2Width * D3DFmtGetBpp(This, Format)) * pow2Height; } /** Create the and initilise surface resource **/ @@ -652,11 +652,6 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Wid /** TODO: change this into a texture transform matrix so that it's processed in hardware **/ - /* Precalculated scaling for 'faked' non power of two texture coords */ - object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width)); - object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height)); - TRACE(" xf(%f) yf(%f) \n", object->pow2scalingFactorX, object->pow2scalingFactorY); - TRACE("Pool %d %d %d %d",Pool, D3DPOOL_DEFAULT, D3DPOOL_MANAGED, D3DPOOL_SYSTEMMEM); /** Quick lockable sanity check TODO: remove this after surfaces, usage and locablility have been debugged properly @@ -716,6 +711,9 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Wid UINT tmpW; UINT tmpH; HRESULT hr; + unsigned int pow2Width = Width; + unsigned int pow2Height = Height; + TRACE("(%p), Width(%d) Height(%d) Levels(%d) Usage(%ld) .... \n", This, Width, Height, Levels, Usage); @@ -723,7 +721,19 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Wid D3DINITILIZEBASETEXTURE(object->baseTexture); object->width = Width; object->height = Height; - + + /** Non-power2 support **/ + /* Find the nearest pow2 match */ + pow2Width = pow2Height = 1; + while (pow2Width < Width) pow2Width <<= 1; + while (pow2Height < Height) pow2Height <<= 1; + + /** FIXME: add support for real non-power-two if it's provided by the video card **/ + /* Precalculated scaling for 'faked' non power of two texture coords */ + object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width)); + object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height)); + TRACE(" xf(%f) yf(%f) \n", object->pow2scalingFactorX, object->pow2scalingFactorY); + /* Calculate levels for mip mapping */ if (Levels == 0) { TRACE("calculating levels %d\n", object->baseTexture.levels); @@ -820,8 +830,11 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface, /* Create the volume */ D3DCB_CreateVolume(This->parent, Width, Height, Depth, Format, Pool, Usage, (IWineD3DVolume **)&object->volumes[i], pSharedHandle); + + /* Set it's container to this object */ IWineD3DVolume_SetContainer(object->volumes[i], (IUnknown *)object); + /* calcualte the next mipmap level */ tmpW = max(1, tmpW >> 1); tmpH = max(1, tmpH >> 1); tmpD = max(1, tmpD >> 1); @@ -856,8 +869,9 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, object->lockable = TRUE; object->locked = FALSE; memset(&object->lockedBox, 0, sizeof(D3DBOX)); - object->dirty = FALSE; - return IWineD3DVolume_CleanDirtyBox((IWineD3DVolume *) object); + object->dirty = TRUE; + + return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL); } HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, @@ -867,29 +881,40 @@ HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT HANDLE* pSharedHandle, IUnknown *parent, D3DCB_CREATESURFACEFN D3DCB_CreateSurface) { - IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/ - unsigned int i,j; - UINT tmpW; - HRESULT hr; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/ + unsigned int i,j; + UINT tmpW; + HRESULT hr; + unsigned int pow2EdgeLength = EdgeLength; - D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, D3DRTYPE_CUBETEXTURE, 0); - D3DINITILIZEBASETEXTURE(object->baseTexture); + D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, D3DRTYPE_CUBETEXTURE, 0); + D3DINITILIZEBASETEXTURE(object->baseTexture); - TRACE("(%p) Create Cube Texture \n", This); + TRACE("(%p) Create Cube Texture \n", This); - object->edgeLength = EdgeLength; + object->edgeLength = EdgeLength; - /* Calculate levels for mip mapping */ - if (Levels == 0) { - object->baseTexture.levels++; - tmpW = EdgeLength; - while (tmpW > 1) { - tmpW = max(1, tmpW / 2); - object->baseTexture.levels++; - } - TRACE("Calculated levels = %d\n", object->baseTexture.levels); - } + /** Non-power2 support **/ + + /* Find the nearest pow2 match */ + pow2EdgeLength = 1; + while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1; + + /* TODO: support for native non-power 2 */ + /* Precalculated scaling for 'faked' non power of two texture coords */ + object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength); + + /* Calculate levels for mip mapping */ + if (Levels == 0) { + object->baseTexture.levels++; + tmpW = EdgeLength; + while (tmpW > 1) { + tmpW = max(1, tmpW / 2); + object->baseTexture.levels++; + } + TRACE("Calculated levels = %d\n", object->baseTexture.levels); + } /* Generate all the surfaces */ tmpW = EdgeLength; diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index fef99feaba..5b3feac942 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -1216,12 +1216,6 @@ static void drawStridedSlow(IWineD3DDevice *iface, Direct3DVertexStridedData *sd } } - /* crude support for non-power2 textures */ - if (((IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)This->stateBlock->textures[textureNo])->surfaces[0])->nonpow2) { - t *= ((IWineD3DSurfaceImpl *)((IWineD3DTextureImpl *)This->stateBlock->textures[textureNo])->surfaces[0])->pow2scalingFactorY; - s *= ((IWineD3DSurfaceImpl *)((IWineD3DTextureImpl *)This->stateBlock->textures[textureNo])->surfaces[0])->pow2scalingFactorX; - } - switch (coordsToUse) { /* Supply the provided texture coords */ case D3DTTFF_COUNT1: VTRACE(("tex:%d, s=%f\n", textureNo, s)); @@ -1578,9 +1572,9 @@ void inline drawPrimitiveTraceDataLocations(Direct3DVertexStridedData *dataLocat } -/* loads any dirty textures and returns true if any of the textures are nonpower2 */ -BOOL inline drawPrimitiveUploadDirtyTextures(IWineD3DDeviceImpl* This) { - BOOL nonPower2 = FALSE; +/* uploads textures and setup texture states ready for rendering */ +void inline drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) { + unsigned int i; /** * OK, here we clear down any old junk iect in the context @@ -1606,14 +1600,6 @@ BOOL inline drawPrimitiveUploadDirtyTextures(IWineD3DDeviceImpl* This) { /* don't bother with textures that have a colorop of disable */ if (This->stateBlock->textureState[i][WINED3DTSS_COLOROP] != D3DTOP_DISABLE) { if (This->stateBlock->textures[i] != NULL) { - /* check to see if any of the texturs are non-power2 */ - if (IWineD3DResourceImpl_GetType((IWineD3DResource *)This->stateBlock->textures[i]) == D3DRTYPE_TEXTURE) { - IWineD3DSurface *surface; - IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[i], 0, &surface); - if (((IWineD3DSurfaceImpl *)surface)->nonpow2) { - nonPower2 = TRUE; - } - } glDisable(GL_TEXTURE_1D); This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]); @@ -1642,9 +1628,9 @@ BOOL inline drawPrimitiveUploadDirtyTextures(IWineD3DDeviceImpl* This) { IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]); IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, REAPPLY_ALPHAOP); /* this is a stub function representing the state blocks being seperated here we are only updating the texture state changes, other objects and units get updated when they change (or need to be updated), e.g. states that relate to a context member line the texture unit are only updated when the context needs updating */ -#if 0 /* TODO: move the setting of states over to base texture */ + /* Tell the abse texture to sync it's states */ IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]); -#endif + } /* Bind a default texture if no texture has been set, but colour-op is enabled */ else { @@ -1677,7 +1663,6 @@ BOOL inline drawPrimitiveUploadDirtyTextures(IWineD3DDeviceImpl* This) { } - return nonPower2; } /* Routine common to the draw primitive and draw indexed primitive routines */ @@ -1702,7 +1687,6 @@ void drawPrimitive(IWineD3DDevice *iface, BOOL isLightingOn = FALSE; Direct3DVertexStridedData dataLocations; int useHW = FALSE; - BOOL nonPower2 = FALSE; /* set to true if any surfaces are non-power2 so that drawslow is used. */ if (This->stateBlock->vertexDecl == NULL) { /* Work out what the FVF should look like */ @@ -1795,7 +1779,7 @@ void drawPrimitive(IWineD3DDevice *iface, /* Now initialize the materials state */ init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL)); - nonPower2 = drawPrimitiveUploadDirtyTextures(This); + drawPrimitiveUploadTextures(This); /* Now draw the graphics to the screen */ if (useVertexShaderFunction) { @@ -1820,7 +1804,6 @@ void drawPrimitive(IWineD3DDevice *iface, } else if ((dataLocations.u.s.pSize.lpData != NULL) || (dataLocations.u.s.diffuse.lpData != NULL) - || nonPower2 /*|| (dataLocations.u.s.blendWeights.lpData != NULL)*/) { /* Fixme, Ideally, only use the per-vertex code for software HAL diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 54db30599c..b40c655718 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -23,7 +23,7 @@ #include "config.h" #include "wined3d_private.h" -WINE_DEFAULT_DEBUG_CHANNEL(d3d); +WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture); #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info /* ******************************************* @@ -70,8 +70,9 @@ ULONG WINAPI IWineD3DTextureImpl_Release(IWineD3DTexture *iface) { IUnknown_Release(surfaceParent); } } - + TRACE("(%p) : cleaning up base texture \n", This); IWineD3DBaseTextureImpl_CleanUp((IWineD3DBaseTexture *)iface); + /* free the object */ HeapFree(GetProcessHeap(), 0, This); } return ref; @@ -202,7 +203,39 @@ UINT WINAPI IWineD3DTextureImpl_GetTextureDimensions(IWineD3DTexture *iface) { void WINAPI IWineD3DTextureImpl_ApplyStateChanges(IWineD3DTexture *iface, const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1], const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + float matrix[16]; IWineD3DBaseTextureImpl_ApplyStateChanges((IWineD3DBaseTexture *)iface, textureStates, samplerStates); + + /** non-power2 fixups using texture matrix **/ + if(This->pow2scalingFactorX != 1.0f || This->pow2scalingFactorY != 1.0f) { + /* Apply non-power2 mappings and texture offsets so long as the texture coords aren't projected or generated */ + if(((textureStates[WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) == D3DTSS_TCI_PASSTHRU) && + (~textureStates[WINED3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) { + glMatrixMode(GL_TEXTURE); + memset(matrix, 0 , sizeof(matrix)); + matrix[0] = This->pow2scalingFactorX; + matrix[5] = This->pow2scalingFactorY; +#if 0 /* this isn't needed any more, I changed the translation in drawprim.c to 0.9/width instead of 1/width and everything lines up ok. left here as a reminder */ + matrix[12] = -0.25f / (float)This->width; + matrix[13] = -0.75f / (float)This->height; +#endif + matrix[10] = 1; + matrix[15] = 1; + TRACE("(%p) Setup Matrix:\n", This); + TRACE(" %f %f %f %f\n", matrix[0], matrix[1], matrix[2], matrix[3]); + TRACE(" %f %f %f %f\n", matrix[4], matrix[5], matrix[6], matrix[7]); + TRACE(" %f %f %f %f\n", matrix[8], matrix[9], matrix[10], matrix[11]); + TRACE(" %f %f %f %f\n", matrix[12], matrix[13], matrix[14], matrix[15]); + TRACE("\n"); + + glMultMatrixf(matrix); + } else { + /* I don't expect nonpower 2 textures to be used with generated texture coordinates, but if they are present a fixme. */ + FIXME("Non-power2 texture being used with generated texture coords\n"); + } + } + } /* ******************************************* diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 701fd17361..6c18fbcd00 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -1484,9 +1484,6 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords) if (flags & D3DTTFF_PROJECTED) { switch (flags & ~D3DTTFF_PROJECTED) { - case D3DTTFF_COUNT1: - mat[9] = 0; - break; case D3DTTFF_COUNT2: mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13]; mat[1] = mat[5] = mat[9] = mat[13] = 0; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index f22a6fa7ff..bebec04897 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -690,6 +690,8 @@ typedef struct IWineD3DTextureImpl UINT width; UINT height; + float pow2scalingFactorX; + float pow2scalingFactorY; } IWineD3DTextureImpl; @@ -709,6 +711,7 @@ typedef struct IWineD3DCubeTextureImpl IWineD3DSurface *surfaces[6][MAX_LEVELS]; UINT edgeLength; + float pow2scalingFactor; } IWineD3DCubeTextureImpl; @@ -790,9 +793,11 @@ struct IWineD3DSurfaceImpl UINT pow2Height; UINT pow2Size; +#if 0 /* precalculated x and y scalings for texture coords */ float pow2scalingFactorX; /* = (Width / pow2Width ) */ float pow2scalingFactorY; /* = (Height / pow2Height) */ +#endif BOOL lockable; BOOL discard;