From a25dfc47b4a2bf58f05c48e764eadc49be56cef8 Mon Sep 17 00:00:00 2001 From: Rodolfo Osvaldo Bogado Date: Wed, 14 Apr 2010 13:57:16 +0000 Subject: [PATCH] fixed xfb bumping introduced by my last commit. implemented loading of native mips, see sms water :). git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5366 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/Atomic_Win32.h | 4 + .../Plugin_VideoDX9/Src/D3DTexture.cpp | 9 +-- .../Plugins/Plugin_VideoDX9/Src/D3DTexture.h | 4 +- Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 12 +-- .../Plugin_VideoDX9/Src/TextureCache.cpp | 40 ++++++++-- .../Plugin_VideoDX9/Src/TextureCache.h | 2 +- .../Plugin_VideoDX9/Src/VertexManager.cpp | 4 +- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 2 +- .../Plugin_VideoOGL/Src/TextureMngr.cpp | 76 ++++++++++++++++--- .../Plugins/Plugin_VideoOGL/Src/TextureMngr.h | 3 +- 10 files changed, 123 insertions(+), 33 deletions(-) diff --git a/Source/Core/Common/Src/Atomic_Win32.h b/Source/Core/Common/Src/Atomic_Win32.h index 4c2a9ec085..70d2f1c4a2 100644 --- a/Source/Core/Common/Src/Atomic_Win32.h +++ b/Source/Core/Common/Src/Atomic_Win32.h @@ -55,6 +55,10 @@ inline void AtomicIncrement(volatile u32& target) { InterlockedIncrement((volatile LONG*)&target); } +inline void AtomicDecrement(volatile u32& target) { + InterlockedDecrement((volatile LONG*)&target); +} + inline u32 AtomicLoad(volatile u32& src) { return src; // 32-bit reads are always atomic. } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DTexture.cpp b/Source/Plugins/Plugin_VideoDX9/Src/D3DTexture.cpp index dd26739cbb..712ea5c6eb 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DTexture.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DTexture.cpp @@ -21,7 +21,7 @@ namespace D3D { -LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b) +LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int levels) { u32* pBuffer = (u32*)buffer; LPDIRECT3DTEXTURE9 pTexture; @@ -38,8 +38,8 @@ LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int HRESULT hr; // TODO(ector): Allow mipmaps for non-pow textures on newer cards? // TODO(ector): Use the game-specified mipmaps? - if (!isPow2) - hr = dev->CreateTexture(width, height, 1, 0, fmt, D3DPOOL_MANAGED, &pTexture, NULL); + if (levels > 0) + hr = dev->CreateTexture(width, height, levels, 0, fmt, D3DPOOL_MANAGED, &pTexture, NULL); else hr = dev->CreateTexture(width, height, 0, D3DUSAGE_AUTOGENMIPMAP, fmt, D3DPOOL_MANAGED, &pTexture, NULL); @@ -148,10 +148,9 @@ LPDIRECT3DTEXTURE9 CreateOnlyTexture2D(const int width, const int height, D3DFOR return pTexture; } -void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b) +void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int level) { u32* pBuffer = (u32*)buffer; - int level = 0; D3DLOCKED_RECT Lock; pTexture->LockRect(level, &Lock, NULL, 0); u32* pIn = pBuffer; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DTexture.h b/Source/Plugins/Plugin_VideoDX9/Src/D3DTexture.h index c1dbb13289..c9c139a218 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DTexture.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DTexture.h @@ -21,8 +21,8 @@ namespace D3D { - LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt = D3DFMT_A8R8G8B8, bool swap_r_b = false); - void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b); + LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt = D3DFMT_A8R8G8B8, bool swap_r_b = false, int levels = 1); + void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int level = 0); LPDIRECT3DTEXTURE9 CreateRenderTarget(const int width, const int height); LPDIRECT3DSURFACE9 CreateDepthStencilSurface(const int width, const int height); LPDIRECT3DTEXTURE9 CreateOnlyTexture2D(const int width, const int height, D3DFORMAT fmt); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index 088a7c380b..4fc041afae 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -1015,6 +1015,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) // EFB is copied to XFB. In this way, flickering is reduced in games // and seems to also give more FPS in ZTP + if (field == FIELD_LOWER) xfbAddr -= fbWidth * 2; u32 xfbCount = 0; const XFBSource** xfbSourceList = FBManager.GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); if (!xfbSourceList || xfbCount == 0) @@ -1389,6 +1390,7 @@ void Renderer::SetSamplerState(int stage, int texindex) { const FourTexUnits &tex = bpmem.tex[texindex]; const TexMode0 &tm0 = tex.texMode0[stage]; + const TexMode1 &tm1 = tex.texMode1[stage]; D3DTEXTUREFILTERTYPE min, mag, mip; if (g_ActiveConfig.bForceFiltering) @@ -1399,7 +1401,7 @@ void Renderer::SetSamplerState(int stage, int texindex) { min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT; mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT; - mip = d3dMipFilters[tm0.min_filter & 3]; + mip = (tm0.min_filter == 8)?D3DTEXF_NONE:d3dMipFilters[tm0.min_filter & 3]; } if (texindex) stage += 4; @@ -1415,11 +1417,9 @@ void Renderer::SetSamplerState(int stage, int texindex) D3D::SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]); D3D::SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]); - //wip - //dev->SetSamplerState(stage,D3DSAMP_MIPMAPLODBIAS,tm0.lod_bias/4.0f); - //char temp[256]; - //sprintf(temp,"lod %f",tm0.lod_bias/4.0f); - //g_VideoInitialize.pLog(temp); + //just a test but it seems to work + D3D::SetSamplerState(stage,D3DSAMP_MIPMAPLODBIAS,tm0.lod_bias/2.0f); + D3D::SetSamplerState(stage,D3DSAMP_MAXMIPLEVEL,tm1.min_lod>>4); } void Renderer::SetInterlacingMode() diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp index 4b15d4dbae..ff42bc6656 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp @@ -136,7 +136,7 @@ void TextureCache::Cleanup() } } -TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, int height, int tex_format, int tlutaddr, int tlutfmt) +TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, int height, int tex_format, int tlutaddr, int tlutfmt,bool UseNativeMips, int maxlevel) { if (address == 0) return NULL; @@ -144,6 +144,7 @@ TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, u8 *ptr = g_VideoInitialize.pGetMemoryPointer(address); int bsw = TexDecoder_GetBlockWidthInTexels(tex_format) - 1; //TexelSizeInNibbles(format)*width*height/16; int bsh = TexDecoder_GetBlockHeightInTexels(tex_format) - 1; //TexelSizeInNibbles(format)*width*height/16; + int bsdepth = TexDecoder_GetTexelSizeInNibbles(tex_format); int expandedWidth = (width + bsw) & (~bsw); int expandedHeight = (height + bsh) & (~bsh); @@ -279,12 +280,41 @@ TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, entry.addr = address; entry.size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, tex_format); entry.isRenderTarget = false; - entry.isNonPow2 = false;//((width & (width - 1)) || (height & (height - 1))); - if (!skip_texture_create) { - entry.texture = D3D::CreateTexture2D((BYTE*)temp, width, height, expandedWidth, d3d_fmt, swap_r_b); - } else { + bool isPow2 = !((width & (width - 1)) || (height & (height - 1))); + entry.isNonPow2 = false; + int TexLevels = (width > height)?width:height; + TexLevels = (isPow2 && UseNativeMips) ? (int)(log((double)TexLevels)/log((double)2)) + 1 : (isPow2?0:1); + if(TexLevels > maxlevel && maxlevel > 0) + TexLevels = maxlevel; + if (!skip_texture_create) + { + entry.texture = D3D::CreateTexture2D((BYTE*)temp, width, height, expandedWidth, d3d_fmt, swap_r_b,TexLevels); + } + else + { D3D::ReplaceTexture2D(entry.texture, (BYTE*)temp, width, height, expandedWidth, d3d_fmt, swap_r_b); } + if(TexLevels > 1 && pcfmt != PC_TEX_FMT_NONE) + { + int level = 1; + int mipWidth = (width + 1) >> 1; + int mipHeight = (height + 1) >> 1; + ptr += entry.size_in_bytes; + while((mipHeight || mipWidth) && (level < TexLevels)) + { + u32 currentWidth = (mipWidth > 0)? mipWidth : 1; + u32 currentHeight = (mipHeight > 0)? mipHeight : 1; + expandedWidth = (currentWidth + bsw) & (~bsw); + expandedHeight = (currentHeight + bsh) & (~bsh); + TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt); + D3D::ReplaceTexture2D(entry.texture, (BYTE*)temp, currentWidth, currentHeight, expandedWidth, d3d_fmt, swap_r_b,level); + u32 size = (max(mipWidth, bsw) * max(mipHeight, bsh) * bsdepth) >> 1; + ptr += size; + mipWidth >>= 1; + mipHeight >>= 1; + level++; + } + } entry.frameCount = frameCount; entry.w = width; entry.h = height; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h index 806524d2bf..649533dbcc 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h @@ -82,7 +82,7 @@ public: static void Shutdown(); static void Invalidate(bool shutdown); static void InvalidateRange(u32 start_address, u32 size); - static TCacheEntry *Load(int stage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt); + static TCacheEntry *Load(int stage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt,bool UseNativeMips, int maxlevel); static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle &source_rect); }; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp index 825d9b463d..64b39efcc5 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp @@ -249,7 +249,9 @@ void Flush() (tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5, tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, - tex.texTlut[i&3].tlut_format); + tex.texTlut[i&3].tlut_format, + (tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8), + (tex.texMode1[i&3].max_lod >> 4)); if (tentry) { PixelShaderManager::SetTexDims(i, tentry->w, tentry->h, 0, 0); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 8a135aa559..3c84023f48 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -795,7 +795,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) g_VideoInitialize.pCopiedToXFB(false); return; } - + if (field == FIELD_LOWER) xfbAddr -= fbWidth * 2; u32 xfbCount = 0; const XFBSource** xfbSourceList = g_framebufferManager.GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); if (!xfbSourceList) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp index 2a2be10dec..4ca701c35f 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp @@ -103,9 +103,10 @@ bool TextureMngr::TCacheEntry::IntersectsMemoryRange(u32 range_address, u32 rang return true; } -void TextureMngr::TCacheEntry::SetTextureParameters(TexMode0 &newmode) +void TextureMngr::TCacheEntry::SetTextureParameters(TexMode0 &newmode,TexMode1 &newmode1) { mode = newmode; + mode1 = newmode1; if (isRectangle) { // very limited! @@ -130,6 +131,10 @@ void TextureMngr::TCacheEntry::SetTextureParameters(TexMode0 &newmode) if (g_ActiveConfig.bForceFiltering && newmode.min_filter < 4) newmode.min_filter += 4; // take equivalent forced linear glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod >> 4); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod >> 4); + //glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (newmode.lod_bias/2.0f)); + } else glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, @@ -251,9 +256,15 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width return NULL; TexMode0 &tm0 = bpmem.tex[texstage > 3].texMode0[texstage & 3]; + TexMode1 &tm1 = bpmem.tex[texstage > 3].texMode1[texstage & 3]; + + bool UseNativeMips = (tm0.min_filter & 3) && (tm0.min_filter != 8); + int maxlevel = (tm1.max_lod >> 4); + u8 *ptr = g_VideoInitialize.pGetMemoryPointer(address); int bsw = TexDecoder_GetBlockWidthInTexels(tex_format) - 1; int bsh = TexDecoder_GetBlockHeightInTexels(tex_format) - 1; + int bsdepth = TexDecoder_GetTexelSizeInNibbles(tex_format); int expandedWidth = (width + bsw) & (~bsw); int expandedHeight = (height + bsh) & (~bsh); @@ -303,8 +314,8 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width // entry.isRectangle ? TextureMngr::EnableTex2D(texstage) : TextureMngr::EnableTexRECT(texstage); glBindTexture(entry.isRectangle ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, entry.texture); GL_REPORT_ERRORD(); - if (entry.mode.hex != tm0.hex) - entry.SetTextureParameters(tm0); + if (entry.mode.hex != tm0.hex || entry.mode1.hex != tm1.hex) + entry.SetTextureParameters(tm0,tm1); //DebugLog("%cC addr: %08x | fmt: %i | e.hash: %08x | w:%04i h:%04i", g_ActiveConfig.bSafeTextureCache ? 'S' : 'U' // , address, tex_format, entry.hash, width, height); return &entry; @@ -318,8 +329,8 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width { glBindTexture(entry.isRectangle ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, entry.texture); GL_REPORT_ERRORD(); - if (entry.mode.hex != tm0.hex) - entry.SetTextureParameters(tm0); + if (entry.mode.hex != tm0.hex || entry.mode1.hex != tm1.hex) + entry.SetTextureParameters(tm0,tm1); skip_texture_create = true; } else @@ -380,14 +391,20 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width glBindTexture(target, entry.texture); } + bool isPow2 = !((width & (width - 1)) || (height & (height - 1))); + int TexLevels = (width > height)?width:height; + TexLevels = (isPow2 && UseNativeMips) ? (int)(log((double)TexLevels)/log((double)2)) + 1 : (isPow2?0:1); + if(TexLevels > maxlevel && maxlevel > 0) + TexLevels = maxlevel; + int gl_format; + int gl_iformat; + int gl_type; + entry.bHaveMipMaps = UseNativeMips; if (dfmt != PC_TEX_FMT_DXT1) { if (expandedWidth != width) glPixelStorei(GL_UNPACK_ROW_LENGTH, expandedWidth); - int gl_format; - int gl_iformat; - int gl_type; switch (dfmt) { default: @@ -429,6 +446,7 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width gl_type = GL_UNSIGNED_SHORT_5_6_5; break; } + //generate mipmaps even if we use native mips to suport textures with less levels bool GenerateMipmaps = !entry.isRectangle && ((tm0.min_filter & 3) == 1 || (tm0.min_filter & 3) == 2); if (GenerateMipmaps) { @@ -464,13 +482,49 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width width, height, 0, expandedWidth*expandedHeight/2, temp); } } - + if(TexLevels > 1 && dfmt != PC_TEX_FMT_NONE) + { + int level = 1; + int mipWidth = (width + 1) >> 1; + int mipHeight = (height + 1) >> 1; + ptr += entry.size_in_bytes; + while((mipHeight || mipWidth)) + { + u32 currentWidth = (mipWidth > 0)? mipWidth : 1; + u32 currentHeight = (mipHeight > 0)? mipHeight : 1; + expandedWidth = (currentWidth + bsw) & (~bsw); + expandedHeight = (currentHeight + bsh) & (~bsh); + if(level < TexLevels) + { + TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt); + } + //ugly hack but it seems to work + //complete the level not defined in hardware with pixels of the top levels + //this is not a problem as the level are filtered by lod min and max value + if (dfmt != PC_TEX_FMT_DXT1) + { + if (expandedWidth != currentWidth) + glPixelStorei(GL_UNPACK_ROW_LENGTH, expandedWidth); + glTexImage2D(target, level, gl_iformat, currentWidth, currentHeight, 0, gl_format, gl_type, temp); + if (expandedWidth != currentWidth) // reset + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + else + { + glCompressedTexImage2D(target, level, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, currentWidth, currentHeight, 0, expandedWidth*expandedHeight/2, temp); + } + u32 size = (max(mipWidth, bsw) * max(mipHeight, bsh) * bsdepth) >> 1; + ptr += size; + mipWidth >>= 1; + mipHeight >>= 1; + level++; + } + } entry.frameCount = frameCount; entry.w = width; entry.h = height; entry.fmt = FullFormat; - entry.SetTextureParameters(tm0); - + entry.SetTextureParameters(tm0,tm1); if (g_ActiveConfig.bDumpTextures) // dump texture to file { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h index d10f384b71..e5f698508b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h @@ -38,6 +38,7 @@ public: u32 paletteHash; u32 oldpixel; // used for simple cleanup TexMode0 mode; // current filter and clamp modes that texture is set to + TexMode1 mode1; // current filter and clamp modes that texture is set to int frameCount; int w, h, fmt; @@ -49,7 +50,7 @@ public: bool isRectangle; // if nonpow2, use GL_TEXTURE_2D, else GL_TEXTURE_RECTANGLE_NV bool bHaveMipMaps; - void SetTextureParameters(TexMode0& newmode); + void SetTextureParameters(TexMode0& newmode,TexMode1 &newmode1); void Destroy(bool shutdown); void ConvertFromRenderTarget(u32 taddr, int twidth, int theight, int tformat, int tlutaddr, int tlutfmt); bool IntersectsMemoryRange(u32 range_address, u32 range_size);