From 485e2cc2548a3cbbc0e8b3ec8806ceba8d0f6547 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 9 Mar 2016 05:25:18 +0000 Subject: [PATCH] OpenGL Renderer: - Textures can now be automatically upscaled using the xBRZ filter. Textures can be upscaled to 2x or 4x. - Textures can now be smoothed using a deposterization filter. This can be helpful in smoothing some of the hard color banding that sometimes occurs with xBRZ. --- desmume/src/NDSSystem.h | 4 + desmume/src/OGLRender.cpp | 72 +++++++++-- desmume/src/OGLRender_3_2.cpp | 35 ++++- desmume/src/filter/xbrz.cpp | 44 +++++-- desmume/src/filter/xbrz.h | 5 +- desmume/src/gfx3d.cpp | 1 + desmume/src/render3D.cpp | 232 ++++++++++++++++++++++++++++++++++ desmume/src/render3D.h | 9 ++ 8 files changed, 375 insertions(+), 27 deletions(-) diff --git a/desmume/src/NDSSystem.h b/desmume/src/NDSSystem.h index 53232c971..3b071e7a0 100644 --- a/desmume/src/NDSSystem.h +++ b/desmume/src/NDSSystem.h @@ -483,6 +483,8 @@ extern struct TCommonSettings { , GFX3D_LineHack(true) , GFX3D_Zelda_Shadow_Depth_Hack(0) , GFX3D_Renderer_Multisample(false) + , GFX3D_Renderer_TextureDeposterize(false) + , GFX3D_Renderer_TextureScalingFactor(1) // Possible values: 1, 2, 4 , GFX3D_TXTHack(false) , GFX3D_PrescaleHD(1) , jit_max_block_size(100) @@ -543,6 +545,8 @@ extern struct TCommonSettings { bool GFX3D_LineHack; int GFX3D_Zelda_Shadow_Depth_Hack; bool GFX3D_Renderer_Multisample; + bool GFX3D_Renderer_TextureDeposterize; + int GFX3D_Renderer_TextureScalingFactor; bool GFX3D_TXTHack; //may not want this on OSX port diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 8ed4840a8..d4397f22c 100644 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -2880,7 +2880,6 @@ Render3DError OpenGLRenderer_1_2::SetupTexture(const POLY &thePoly, bool enableT glEnable(GL_TEXTURE_2D); } - // texCacheUnit.TexCache_SetTexture(format, texpal); TexCacheItem *newTexture = TexCache_SetTexture(TexFormat_32bpp, thePoly.texParam, thePoly.texPalette); if(newTexture != this->currTexture) { @@ -2899,15 +2898,42 @@ Render3DError OpenGLRenderer_1_2::SetupTexture(const POLY &thePoly, bool enableT OGLRef.freeTextureIDs.pop(); glBindTexture(GL_TEXTURE_2D, (GLuint)this->currTexture->texid); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (params.enableRepeatS ? (params.enableMirroredRepeatS ? OGLRef.stateTexMirroredRepeat : GL_REPEAT) : GL_CLAMP_TO_EDGE)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (params.enableRepeatT ? (params.enableMirroredRepeatT ? OGLRef.stateTexMirroredRepeat : GL_REPEAT) : GL_CLAMP_TO_EDGE)); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - this->currTexture->sizeX, this->currTexture->sizeY, 0, - GL_RGBA, GL_UNSIGNED_BYTE, this->currTexture->decoded); + u32 *textureSrc = (u32 *)currTexture->decoded; + size_t texWidth = currTexture->sizeX; + size_t texHeight = currTexture->sizeY; + + if (this->_textureDeposterizeBuffer != NULL) + { + this->TextureDeposterize(textureSrc, texWidth, texHeight); + textureSrc = this->_textureDeposterizeBuffer; + } + + switch (this->_textureScalingFactor) + { + case 2: + { + this->TextureUpscale<2>(textureSrc, texWidth, texHeight); + textureSrc = this->_textureUpscaleBuffer; + break; + } + + case 4: + { + this->TextureUpscale<4>(textureSrc, texWidth, texHeight); + textureSrc = this->_textureUpscaleBuffer; + break; + } + + default: + break; + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } else { @@ -4393,7 +4419,6 @@ Render3DError OpenGLRenderer_2_0::SetupTexture(const POLY &thePoly, bool enableT glUniform1i(OGLRef.uniformPolyEnableTexture, GL_TRUE); - // texCacheUnit.TexCache_SetTexture(format, texpal); TexCacheItem *newTexture = TexCache_SetTexture(TexFormat_32bpp, thePoly.texParam, thePoly.texPalette); if(newTexture != this->currTexture) { @@ -4412,15 +4437,42 @@ Render3DError OpenGLRenderer_2_0::SetupTexture(const POLY &thePoly, bool enableT OGLRef.freeTextureIDs.pop(); glBindTexture(GL_TEXTURE_2D, (GLuint)this->currTexture->texid); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (params.enableRepeatS ? (params.enableMirroredRepeatS ? GL_MIRRORED_REPEAT : GL_REPEAT) : GL_CLAMP_TO_EDGE)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (params.enableRepeatT ? (params.enableMirroredRepeatT ? GL_MIRRORED_REPEAT : GL_REPEAT) : GL_CLAMP_TO_EDGE)); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - this->currTexture->sizeX, this->currTexture->sizeY, 0, - GL_RGBA, GL_UNSIGNED_BYTE, this->currTexture->decoded); + u32 *textureSrc = (u32 *)currTexture->decoded; + size_t texWidth = currTexture->sizeX; + size_t texHeight = currTexture->sizeY; + + if (this->_textureDeposterizeBuffer != NULL) + { + this->TextureDeposterize(textureSrc, texWidth, texHeight); + textureSrc = this->_textureDeposterizeBuffer; + } + + switch (this->_textureScalingFactor) + { + case 2: + { + this->TextureUpscale<2>(textureSrc, texWidth, texHeight); + textureSrc = this->_textureUpscaleBuffer; + break; + } + + case 4: + { + this->TextureUpscale<4>(textureSrc, texWidth, texHeight); + textureSrc = this->_textureUpscaleBuffer; + break; + } + + default: + break; + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } else { diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 6ead38eaa..3d874c6e6 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -1671,15 +1671,42 @@ Render3DError OpenGLRenderer_3_2::SetupTexture(const POLY &thePoly, bool enableT OGLRef.freeTextureIDs.pop(); glBindTexture(GL_TEXTURE_2D, (GLuint)this->currTexture->texid); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (params.enableRepeatS ? (params.enableMirroredRepeatS ? GL_MIRRORED_REPEAT : GL_REPEAT) : GL_CLAMP_TO_EDGE)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (params.enableRepeatT ? (params.enableMirroredRepeatT ? GL_MIRRORED_REPEAT : GL_REPEAT) : GL_CLAMP_TO_EDGE)); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - this->currTexture->sizeX, this->currTexture->sizeY, 0, - GL_RGBA, GL_UNSIGNED_BYTE, this->currTexture->decoded); + u32 *textureSrc = (u32 *)currTexture->decoded; + size_t texWidth = currTexture->sizeX; + size_t texHeight = currTexture->sizeY; + + if (this->_textureDeposterizeBuffer != NULL) + { + this->TextureDeposterize(textureSrc, texWidth, texHeight); + textureSrc = this->_textureDeposterizeBuffer; + } + + switch (this->_textureScalingFactor) + { + case 2: + { + this->TextureUpscale<2>(textureSrc, texWidth, texHeight); + textureSrc = this->_textureUpscaleBuffer; + break; + } + + case 4: + { + this->TextureUpscale<4>(textureSrc, texWidth, texHeight); + textureSrc = this->_textureUpscaleBuffer; + break; + } + + default: + break; + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } else { diff --git a/desmume/src/filter/xbrz.cpp b/desmume/src/filter/xbrz.cpp index af5b08cda..b434ac1ca 100644 --- a/desmume/src/filter/xbrz.cpp +++ b/desmume/src/filter/xbrz.cpp @@ -43,6 +43,8 @@ #define COLOR_MASK_G 0x0000FF00 #define COLOR_MASK_B 0x000000FF +#define USE_DESMUME_TEXTURE_UPSCALE_ALPHA_BLEND + namespace { template inline @@ -87,8 +89,27 @@ uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) //find intermediate c const unsigned int weightFront = getAlpha(pixFront) * M; const unsigned int weightBack = getAlpha(pixBack) * (N - M); const unsigned int weightSum = weightFront + weightBack; + +#ifdef USE_DESMUME_TEXTURE_UPSCALE_ALPHA_BLEND if (weightSum == 0) + { + return (pixFront & 0x00FFFFFF); + } + else if (weightFront == 0) + { + return pixBack; + } + else if (weightBack == 0) + { + return pixFront; + } +#else + if (weightSum == 0) + { return 0; + } +#endif + /* auto calcColor = [=](unsigned char colFront, unsigned char colBack) { @@ -1165,13 +1186,13 @@ struct ColorGradientARGB }; } - -void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, ColorFormat colFmt, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) +template +void xbrz::scale(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) { - switch (colFmt) + switch (FORMAT) { case ColorFormatARGB: - switch (factor) + switch (SCALEFACTOR) { case 2: return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); @@ -1187,7 +1208,7 @@ void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth break; case ColorFormatRGB: - switch (factor) + switch (SCALEFACTOR) { case 2: return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); @@ -1294,25 +1315,28 @@ void xbrz::nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight void Render2xBRZ(SSurface Src, SSurface Dst) { - xbrz::scale(2, (const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height, xbrz::ColorFormatRGB); + xbrz::scale<2, xbrz::ColorFormatRGB>((const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height); } void Render3xBRZ(SSurface Src, SSurface Dst) { - xbrz::scale(3, (const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height, xbrz::ColorFormatRGB); + xbrz::scale<3, xbrz::ColorFormatRGB>((const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height); } void Render4xBRZ(SSurface Src, SSurface Dst) { - xbrz::scale(4, (const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height, xbrz::ColorFormatRGB); + xbrz::scale<4, xbrz::ColorFormatRGB>((const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height); } void Render5xBRZ(SSurface Src, SSurface Dst) { - xbrz::scale(5, (const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height, xbrz::ColorFormatRGB); + xbrz::scale<5, xbrz::ColorFormatRGB>((const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height); } void Render6xBRZ(SSurface Src, SSurface Dst) { - xbrz::scale(6, (const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height, xbrz::ColorFormatRGB); + xbrz::scale<6, xbrz::ColorFormatRGB>((const uint32_t *)Src.Surface, (uint32_t *)Dst.Surface, Src.Width, Src.Height); } + +template void xbrz::scale<2, xbrz::ColorFormatARGB>(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast); +template void xbrz::scale<4, xbrz::ColorFormatARGB>(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast); diff --git a/desmume/src/filter/xbrz.h b/desmume/src/filter/xbrz.h index a92d14dbb..97338e70f 100644 --- a/desmume/src/filter/xbrz.h +++ b/desmume/src/filter/xbrz.h @@ -83,9 +83,8 @@ struct ScalerCfg double newTestAttribute_; //unused; test new parameters }; -void scale(size_t factor, //valid range: 2 - 6 - const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, - ColorFormat colFmt, +template //valid range: 2 - 6 +void scale(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const ScalerCfg& cfg = ScalerCfg(), int yFirst = 0, int yLast = std::numeric_limits::max()); //slice of source image diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index 4b9980d98..1a702a670 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -2329,6 +2329,7 @@ void gfx3d_VBlankEndSignal(bool skipFrame) GPU->GetEventHandler()->DidRender3DBegin(); CurrentRenderer->SetRenderNeedsFinish(true); + CurrentRenderer->SetTextureProcessingProperties(CommonSettings.GFX3D_Renderer_TextureDeposterize, CommonSettings.GFX3D_Renderer_TextureScalingFactor); CurrentRenderer->Render(gfx3d); } diff --git a/desmume/src/render3D.cpp b/desmume/src/render3D.cpp index b1cad7f89..90d4bb34b 100644 --- a/desmume/src/render3D.cpp +++ b/desmume/src/render3D.cpp @@ -33,7 +33,9 @@ #include "gfx3d.h" #include "MMU.h" #include "texcache.h" +#include "./filter/xbrz.h" +#define TEXTURE_DEPOSTERIZE_THRESHOLD 21 // Possible values are [0-255], where lower a value prevents blending and a higher value allows for more blending static CACHE_ALIGN u32 dsDepthToD24_LUT[32768] = {0}; int cur3DCore = GPU3D_NULL; @@ -128,6 +130,55 @@ void Render3DBaseDestroy() } } +static u32 TextureDeposterize_InterpLTE(const u32 pixA, const u32 pixB, const u32 threshold) +{ + const u32 aB = (pixB & 0xFF000000) >> 24; + if (aB == 0) + { + return pixA; + } + + const u32 rA = (pixA & 0x000000FF); + const u32 gA = (pixA & 0x0000FF00) >> 8; + const u32 bA = (pixA & 0x00FF0000) >> 16; + const u32 aA = (pixA & 0xFF000000) >> 24; + + const u32 rB = (pixB & 0x000000FF); + const u32 gB = (pixB & 0x0000FF00) >> 8; + const u32 bB = (pixB & 0x00FF0000) >> 16; + + const u32 rC = ( (rB - rA <= threshold) || (rA - rB <= threshold) ) ? ( ((rA+rB)>>1) ) : rA; + const u32 gC = ( (gB - gA <= threshold) || (gA - gB <= threshold) ) ? ( ((gA+gB)>>1) ) : gA; + const u32 bC = ( (bB - bA <= threshold) || (bA - bB <= threshold) ) ? ( ((bA+bB)>>1) ) : bA; + const u32 aC = ( (bB - aA <= threshold) || (aA - aB <= threshold) ) ? ( ((aA+aB)>>1) ) : aA; + + return (rC | (gC << 8) | (bC << 16) | (aC << 24)); +} + +static u32 TextureDeposterize_Blend(const u32 pixA, const u32 pixB, const u32 weightA, const u32 weightB) +{ + const u32 aB = (pixB & 0xFF000000) >> 24; + if (aB == 0) + { + return pixA; + } + + const u32 weightSum = weightA + weightB; + + const u32 rbA = pixA & 0x00FF00FF; + const u32 gA = pixA & 0x0000FF00; + const u32 aA = (pixA & 0xFF000000) >> 24; + + const u32 rbB = pixB & 0x00FF00FF; + const u32 gB = pixB & 0x0000FF00; + + const u32 rbC = ( ((rbA * weightA) + (rbB * weightB)) / weightSum ) & 0x00FF00FF; + const u32 gC = ( (( gA * weightA) + ( gB * weightB)) / weightSum ) & 0x0000FF00; + const u32 aC = ( (( aA * weightA) + ( aB * weightB)) / weightSum ) << 24; + + return (rbC | gC | aC); +} + FragmentAttributesBuffer::FragmentAttributesBuffer(size_t newCount) { count = newCount; @@ -236,6 +287,10 @@ Render3D::Render3D() _willFlushFramebufferRGBA6665 = true; _willFlushFramebufferRGBA5551 = true; + _textureScalingFactor = 1; + _textureDeposterizeBuffer = NULL; + _textureUpscaleBuffer = NULL; + Reset(); } @@ -311,6 +366,180 @@ void Render3D::SetRenderNeedsFinish(const bool renderNeedsFinish) this->_renderNeedsFinish = renderNeedsFinish; } +void Render3D::SetTextureProcessingProperties(bool willDeposterize, size_t scalingFactor) +{ + const bool isScaleValid = ( (scalingFactor == 2) || (scalingFactor == 4) ); + const size_t newScalingFactor = (isScaleValid) ? scalingFactor : 1; + bool needTexCacheReset = false; + + if ( willDeposterize && (this->_textureDeposterizeBuffer == NULL) ) + { + // 1024x1024 texels is the largest possible texture size. + // We need two buffers, one for each deposterize stage. + const size_t bufferSize = 1024 * 1024 * 2 * sizeof(u32); + this->_textureDeposterizeBuffer = (u32 *)malloc_alignedCacheLine(bufferSize); + memset(this->_textureDeposterizeBuffer, 0, bufferSize); + + needTexCacheReset = true; + } + else if ( !willDeposterize && (this->_textureDeposterizeBuffer != NULL) ) + { + free_aligned(this->_textureDeposterizeBuffer); + this->_textureDeposterizeBuffer = NULL; + + needTexCacheReset = true; + } + + if (newScalingFactor != this->_textureScalingFactor) + { + u32 *oldTextureBuffer = this->_textureUpscaleBuffer; + u32 *newTextureBuffer = (u32 *)malloc_alignedCacheLine( (1024 * newScalingFactor) * (1024 * newScalingFactor) * sizeof(u32) ); + this->_textureScalingFactor = newScalingFactor; + this->_textureUpscaleBuffer = newTextureBuffer; + free_aligned(oldTextureBuffer); + + needTexCacheReset = true; + } + + if (needTexCacheReset) + { + TexCache_Reset(); + } +} + +Render3DError Render3D::TextureDeposterize(const u32 *src, const size_t srcTexWidth, const size_t srcTexHeight) +{ + //---------------------------------------\n\ + // Input Pixel Mapping: 06|07|08 + // 05|00|01 + // 04|03|02 + // + // Output Pixel Mapping: 00 + + const int w = srcTexWidth; + const int h = srcTexHeight; + + u32 color[9]; + u32 blend[9]; + u32 *dst = this->_textureDeposterizeBuffer + (1024 * 1024); + u32 *finalDst = this->_textureDeposterizeBuffer; + + size_t i = 0; + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++, i++) + { + if ((src[i] & 0xFF000000) == 0) + { + dst[i] = src[i]; + continue; + } + + color[0] = src[i]; + color[1] = (x < w-1) ? src[i+1] : src[i]; + color[2] = ((x < w-1) && (y < h-1)) ? src[i+w+1] : src[i]; + color[3] = (y < h-1) ? src[i+w] : src[i]; + color[4] = ((x > 0) && (y < h-1)) ? src[i+w-1] : src[i]; + color[5] = (x > 0) ? src[i-1] : src[i]; + color[6] = ((x > 0) && (y > 0)) ? src[i-w-1] : src[i]; + color[7] = (y > 0) ? src[i-w] : src[i]; + color[8] = ((x < w-1) && (y > 0)) ? src[i-w+1] : src[i]; + + blend[0] = color[0]; + blend[1] = TextureDeposterize_InterpLTE(color[0], color[1], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[2] = TextureDeposterize_InterpLTE(color[0], color[2], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[3] = TextureDeposterize_InterpLTE(color[0], color[3], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[4] = TextureDeposterize_InterpLTE(color[0], color[4], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[5] = TextureDeposterize_InterpLTE(color[0], color[5], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[6] = TextureDeposterize_InterpLTE(color[0], color[6], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[7] = TextureDeposterize_InterpLTE(color[0], color[7], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[8] = TextureDeposterize_InterpLTE(color[0], color[8], TEXTURE_DEPOSTERIZE_THRESHOLD); + + dst[i] = TextureDeposterize_Blend(TextureDeposterize_Blend(TextureDeposterize_Blend(TextureDeposterize_Blend(blend[0], blend[5], 1, 7), + TextureDeposterize_Blend(blend[0], blend[1], 1, 7), + 1, 1), + TextureDeposterize_Blend(TextureDeposterize_Blend(blend[0], blend[7], 1, 7), + TextureDeposterize_Blend(blend[0], blend[3], 1, 7), + 1, 1), + 1, 1), + TextureDeposterize_Blend(TextureDeposterize_Blend(TextureDeposterize_Blend(blend[0], blend[6], 7, 9), + TextureDeposterize_Blend(blend[0], blend[2], 7, 9), + 1, 1), + TextureDeposterize_Blend(TextureDeposterize_Blend(blend[0], blend[8], 7, 9), + TextureDeposterize_Blend(blend[0], blend[4], 7, 9), + 1, 1), + 1, 1), + 3, 1); + } + } + + i = 0; + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++, i++) + { + if ((src[i] & 0xFF000000) == 0) + { + finalDst[i] = src[i]; + continue; + } + + color[0] = dst[i]; + color[1] = (x < w-1) ? dst[i+1] : dst[i]; + color[2] = ((x < w-1) && (y < h-1)) ? dst[i+w+1] : dst[i]; + color[3] = (y < h-1) ? dst[i+w] : dst[i]; + color[4] = ((x > 0) && (y < h-1)) ? dst[i+w-1] : dst[i]; + color[5] = (x > 0) ? dst[i-1] : dst[i]; + color[6] = ((x > 0) && (y > 0)) ? dst[i-w-1] : dst[i]; + color[7] = (y > 0) ? dst[i-w] : dst[i]; + color[8] = ((x < w-1) && (y > 0)) ? dst[i-w+1] : dst[i]; + + blend[0] = color[0]; + blend[1] = TextureDeposterize_InterpLTE(color[0], color[1], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[2] = TextureDeposterize_InterpLTE(color[0], color[2], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[3] = TextureDeposterize_InterpLTE(color[0], color[3], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[4] = TextureDeposterize_InterpLTE(color[0], color[4], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[5] = TextureDeposterize_InterpLTE(color[0], color[5], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[6] = TextureDeposterize_InterpLTE(color[0], color[6], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[7] = TextureDeposterize_InterpLTE(color[0], color[7], TEXTURE_DEPOSTERIZE_THRESHOLD); + blend[8] = TextureDeposterize_InterpLTE(color[0], color[8], TEXTURE_DEPOSTERIZE_THRESHOLD); + + finalDst[i] = TextureDeposterize_Blend(TextureDeposterize_Blend(TextureDeposterize_Blend(TextureDeposterize_Blend(blend[0], blend[5], 1, 7), + TextureDeposterize_Blend(blend[0], blend[1], 1, 7), + 1, 1), + TextureDeposterize_Blend(TextureDeposterize_Blend(blend[0], blend[7], 1, 7), + TextureDeposterize_Blend(blend[0], blend[3], 1, 7), + 1, 1), + 1, 1), + TextureDeposterize_Blend(TextureDeposterize_Blend(TextureDeposterize_Blend(blend[0], blend[6], 7, 9), + TextureDeposterize_Blend(blend[0], blend[2], 7, 9), + 1, 1), + TextureDeposterize_Blend(TextureDeposterize_Blend(blend[0], blend[8], 7, 9), + TextureDeposterize_Blend(blend[0], blend[4], 7, 9), + 1, 1), + 1, 1), + 3, 1); + } + } + + return RENDER3DERROR_NOERR; +} + +template +Render3DError Render3D::TextureUpscale(const u32 *src, size_t &outTexWidth, size_t &outTexHeight) +{ + if ( (SCALEFACTOR != 2) && (SCALEFACTOR != 4) ) + { + return RENDER3DERROR_NOERR; + } + + xbrz::scale(src, this->_textureUpscaleBuffer, outTexWidth, outTexHeight); + + outTexWidth *= SCALEFACTOR; + outTexHeight *= SCALEFACTOR; + return RENDER3DERROR_NOERR; +} + Render3DError Render3D::BeginRender(const GFX3D &engine) { return RENDER3DERROR_NOERR; @@ -745,3 +974,6 @@ Render3DError Render3D_SSE2::ClearFramebuffer(const GFX3D_State &renderState) } #endif // ENABLE_SSE2 + +template Render3DError Render3D::TextureUpscale<2>(const u32 *src, size_t &outTexWidth, size_t &outTexHeight); +template Render3DError Render3D::TextureUpscale<4>(const u32 *src, size_t &outTexWidth, size_t &outTexHeight); diff --git a/desmume/src/render3D.h b/desmume/src/render3D.h index dc63c279b..df1c0ba27 100644 --- a/desmume/src/render3D.h +++ b/desmume/src/render3D.h @@ -113,11 +113,18 @@ protected: bool _willFlushFramebufferRGBA6665; bool _willFlushFramebufferRGBA5551; + size_t _textureScalingFactor; + u32 *_textureDeposterizeBuffer; + u32 *_textureUpscaleBuffer; + CACHE_ALIGN u16 clearImageColor16Buffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; CACHE_ALIGN u32 clearImageDepthBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; CACHE_ALIGN u8 clearImageFogBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; CACHE_ALIGN u8 clearImagePolyIDBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; + Render3DError TextureDeposterize(const u32 *src, const size_t srcTexWidth, const size_t srcTexHeight); + template Render3DError TextureUpscale(const u32 *src, size_t &outTexWidth, size_t &outTexHeight); + virtual Render3DError BeginRender(const GFX3D &engine); virtual Render3DError RenderGeometry(const GFX3D_State &renderState, const POLYLIST *polyList, const INDEXLIST *indexList); virtual Render3DError RenderEdgeMarking(const u16 *colorTable, const bool useAntialias); @@ -166,6 +173,8 @@ public: bool GetRenderNeedsFinish() const; void SetRenderNeedsFinish(const bool renderNeedsFinish); + + void SetTextureProcessingProperties(bool willDeposterize, size_t scalingFactor); }; #ifdef ENABLE_SSE2