diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 30207f1c90..215730f6c6 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -19,6 +19,7 @@ #include "Common/MemoryUtil.h" #include "Core/Config.h" #include "Core/Reporting.h" +#include "Core/System.h" #include "GPU/Common/FramebufferCommon.h" #include "GPU/Common/TextureCacheCommon.h" #include "GPU/Common/TextureDecoder.h" @@ -164,6 +165,46 @@ void TextureCacheCommon::NotifyFramebuffer(u32 address, VirtualFramebuffer *fram } } +void TextureCacheCommon::NotifyConfigChanged() { + int scaleFactor; + + // 0 means automatic texture scaling, up to 5x, based on resolution. + if (g_Config.iTexScalingLevel == 0) { + scaleFactor = g_Config.iInternalResolution; + // Automatic resolution too? Okay. + if (scaleFactor == 0) { + if (!g_Config.IsPortrait()) { + scaleFactor = (PSP_CoreParameter().pixelWidth + 479) / 480; + } else { + scaleFactor = (PSP_CoreParameter().pixelHeight + 479) / 480; + } + } + + // Mobile devices don't get the higher scale factors, too expensive. Very rough way to decide though... + if (!gstate_c.Supports(GPU_IS_MOBILE)) { + scaleFactor = std::min(5, scaleFactor); + } else { + scaleFactor = std::min(3, scaleFactor); + } + } else { + scaleFactor = g_Config.iTexScalingLevel; + } + + if (!gstate_c.Supports(GPU_SUPPORTS_OES_TEXTURE_NPOT)) { + // Reduce the scale factor to a power of two (e.g. 2 or 4) if textures must be a power of two. + while ((scaleFactor & (scaleFactor - 1)) != 0) { + --scaleFactor; + } + } + + // Just in case, small display with auto resolution or something. + if (scaleFactor <= 0) { + scaleFactor = 1; + } + + standardScaleFactor_ = scaleFactor; +} + void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { clutTotalBytes_ = loadBytes; clutRenderAddress_ = 0xFFFFFFFF; diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 847a1c2917..8376093561 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -45,6 +45,7 @@ public: // FramebufferManager keeps TextureCache updated about what regions of memory are being rendered to. void NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg); + void NotifyConfigChanged(); int AttachedDrawingHeight(); @@ -154,6 +155,7 @@ protected: u32 clutTotalBytes_; u32 clutMaxBytes_; u32 clutRenderAddress_; + int standardScaleFactor_; }; inline bool TextureCacheCommon::TexCacheEntry::Matches(u16 dim2, u8 format2, u8 maxLevel2) { diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index e0a230bc08..46bb33e3d9 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -444,6 +444,7 @@ DIRECTX9_GPU::DIRECTX9_GPU() // Some of our defaults are different from hw defaults, let's assert them. // We restore each frame anyway, but here is convenient for tests. dxstate.Restore(); + textureCache_.NotifyConfigChanged(); } void DIRECTX9_GPU::UpdateCmdInfo() { @@ -537,6 +538,7 @@ void DIRECTX9_GPU::BeginFrameInternal() { if (resized_) { UpdateCmdInfo(); transformDraw_.Resized(); + textureCache_.NotifyConfigChanged(); resized_ = false; } diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 5354f7c271..117e878115 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -804,6 +804,125 @@ void TextureCacheDX9::ApplyTexture() { nextTexture_ = nullptr; } +class TextureShaderApplierDX9 { +public: + struct Pos { + Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { + } + Pos() { + } + + float x; + float y; + float z; + }; + struct UV { + UV(float u_, float v_) : u(u_), v(v_) { + } + UV() { + } + + float u; + float v; + }; + + struct PosUV { + Pos pos; + UV uv; + }; + + TextureShaderApplierDX9(LPDIRECT3DPIXELSHADER9 pshader, float bufferW, float bufferH, int renderW, int renderH, float xoff, float yoff) + : pshader_(pshader), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) { + static const Pos pos[4] = { + {-1, 1, 0}, + { 1, 1, 0}, + { 1, -1, 0}, + {-1, -1, 0}, + }; + static const UV uv[4] = { + {0, 0}, + {1, 0}, + {1, 1}, + {0, 1}, + }; + + for (int i = 0; i < 4; ++i) { + verts_[i].pos = pos[i]; + verts_[i].pos.x += xoff; + verts_[i].pos.y += yoff; + verts_[i].uv = uv[i]; + } + } + + void ApplyBounds(const KnownVertexBounds &bounds, u32 uoff, u32 voff, float xoff, float yoff) { + // If min is not < max, then we don't have values (wasn't set during decode.) + if (bounds.minV < bounds.maxV) { + const float invWidth = 1.0f / bufferW_; + const float invHeight = 1.0f / bufferH_; + // Inverse of half = double. + const float invHalfWidth = invWidth * 2.0f; + const float invHalfHeight = invHeight * 2.0f; + + const int u1 = bounds.minU + uoff; + const int v1 = bounds.minV + voff; + const int u2 = bounds.maxU + uoff; + const int v2 = bounds.maxV + voff; + + const float left = u1 * invHalfWidth - 1.0f + xoff; + const float right = u2 * invHalfWidth - 1.0f + xoff; + const float top = v1 * invHalfHeight - 1.0f + yoff; + const float bottom = v2 * invHalfHeight - 1.0f + yoff; + // Points are: BL, BR, TR, TL. + verts_[0].pos = Pos(left, bottom, -1.0f); + verts_[1].pos = Pos(right, bottom, -1.0f); + verts_[2].pos = Pos(right, top, -1.0f); + verts_[3].pos = Pos(left, top, -1.0f); + + // And also the UVs, same order. + const float uvleft = u1 * invWidth; + const float uvright = u2 * invWidth; + const float uvtop = v1 * invHeight; + const float uvbottom = v2 * invHeight; + verts_[0].uv = UV(uvleft, uvbottom); + verts_[1].uv = UV(uvright, uvbottom); + verts_[2].uv = UV(uvright, uvtop); + verts_[3].uv = UV(uvleft, uvtop); + } + } + + void Use(LPDIRECT3DVERTEXSHADER9 vshader) { + pD3Ddevice->SetPixelShader(pshader_); + pD3Ddevice->SetVertexShader(vshader); + pD3Ddevice->SetVertexDeclaration(pFramebufferVertexDecl); + } + + void Shade() { + pD3Ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + pD3Ddevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + pD3Ddevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); + pD3Ddevice->SetRenderState(D3DRS_ZENABLE, FALSE); + pD3Ddevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + pD3Ddevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + pD3Ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + DXSetViewport(0, 0, renderW_, renderH_); + HRESULT hr = pD3Ddevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts_, (3 + 2) * sizeof(float)); + if (FAILED(hr)) { + ERROR_LOG_REPORT(G3D, "Depal render failed: %08x", hr); + } + + dxstate.Restore(); + } + +protected: + LPDIRECT3DPIXELSHADER9 pshader_; + PosUV verts_[4]; + float bufferW_; + float bufferH_; + int renderW_; + int renderH_; +}; + void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { LPDIRECT3DPIXELSHADER9 pshader = nullptr; const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); @@ -816,75 +935,15 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame FBO_DX9 *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, FBO_8888); fbo_bind_as_render_target(depalFBO); + shaderManager_->DirtyLastShader(); float xoff = -0.5f / framebuffer->renderWidth; float yoff = 0.5f / framebuffer->renderHeight; - struct Pos { - Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { - } - float x; - float y; - float z; - }; - struct UV { - UV(float u_, float v_) : u(u_), v(v_) { - } - float u; - float v; - }; + TextureShaderApplierDX9 shaderApply(pshader, framebuffer->bufferWidth, framebuffer->bufferHeight, framebuffer->renderWidth, framebuffer->renderHeight, xoff, yoff); + shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset, xoff, yoff); + shaderApply.Use(depalShaderCache_->GetDepalettizeVertexShader()); - struct PosUV { - Pos pos; - UV uv; - }; - - PosUV verts[4] = { - { { -1 + xoff, 1 + yoff, -1 }, { 0, 0 } }, - { { 1 + xoff, 1 + yoff, -1 }, { 1, 0 } }, - { { 1 + xoff, -1 + yoff, -1 }, { 1, 1 } }, - { { -1 + xoff, -1 + yoff, -1 }, { 0, 1 } }, - }; - - // If min is not < max, then we don't have values (wasn't set during decode.) - if (gstate_c.vertBounds.minV < gstate_c.vertBounds.maxV) { - const float invWidth = 1.0f / (float)framebuffer->bufferWidth; - const float invHeight = 1.0f / (float)framebuffer->bufferHeight; - // Inverse of half = double. - const float invHalfWidth = invWidth * 2.0f; - const float invHalfHeight = invHeight * 2.0f; - - const int u1 = gstate_c.vertBounds.minU + gstate_c.curTextureXOffset; - const int v1 = gstate_c.vertBounds.minV + gstate_c.curTextureYOffset; - const int u2 = gstate_c.vertBounds.maxU + gstate_c.curTextureXOffset; - const int v2 = gstate_c.vertBounds.maxV + gstate_c.curTextureYOffset; - - const float left = u1 * invHalfWidth - 1.0f + xoff; - const float right = u2 * invHalfWidth - 1.0f + xoff; - const float top = v1 * invHalfHeight - 1.0f + yoff; - const float bottom = v2 * invHalfHeight - 1.0f + yoff; - // Points are: BL, BR, TR, TL. - verts[0].pos = Pos(left, bottom, -1.0f); - verts[1].pos = Pos(right, bottom, -1.0f); - verts[2].pos = Pos(right, top, -1.0f); - verts[3].pos = Pos(left, top, -1.0f); - - // And also the UVs, same order. - const float uvleft = u1 * invWidth; - const float uvright = u2 * invWidth; - const float uvtop = v1 * invHeight; // TODO: Seems we should ditch the "1.0f - " - const float uvbottom = v2 * invHeight; - verts[0].uv = UV(uvleft, uvbottom); - verts[1].uv = UV(uvright, uvbottom); - verts[2].uv = UV(uvright, uvtop); - verts[3].uv = UV(uvleft, uvtop); - } - - shaderManager_->DirtyLastShader(); - - pD3Ddevice->SetPixelShader(pshader); - pD3Ddevice->SetVertexShader(depalShaderCache_->GetDepalettizeVertexShader()); - pD3Ddevice->SetVertexDeclaration(pFramebufferVertexDecl); pD3Ddevice->SetTexture(1, clutTexture); pD3Ddevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); pD3Ddevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); @@ -895,30 +954,14 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame pD3Ddevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); pD3Ddevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - pD3Ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - pD3Ddevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); - pD3Ddevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); - pD3Ddevice->SetRenderState(D3DRS_ZENABLE, FALSE); - pD3Ddevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); - pD3Ddevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - pD3Ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + shaderApply.Shade(); - DXSetViewport(0, 0, framebuffer->renderWidth, framebuffer->renderHeight); - HRESULT hr = pD3Ddevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, (3 + 2) * sizeof(float)); - if (FAILED(hr)) { - ERROR_LOG_REPORT(G3D, "Depal render failed: %08x", hr); - } - - framebufferManager_->RebindFramebuffer(); fbo_bind_color_as_texture(depalFBO, 0); - dxstate.Restore(); - dxstate.viewport.restore(); - - framebufferManager_->RebindFramebuffer(); } else { framebufferManager_->BindFramebufferColor(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); } + framebufferManager_->RebindFramebuffer(); SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight); lastBoundTexture = INVALID_TEX; @@ -1145,7 +1188,7 @@ void TextureCacheDX9::SetTexture(bool force) { } } - if (match && (entry->status & TexCacheEntry::STATUS_TO_SCALE) && g_Config.iTexScalingLevel != 1 && texelsScaledThisFrame_ < TEXCACHE_MAX_TEXELS_SCALED) { + if (match && (entry->status & TexCacheEntry::STATUS_TO_SCALE) && standardScaleFactor_ != 1 && texelsScaledThisFrame_ < TEXCACHE_MAX_TEXELS_SCALED) { if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) == 0) { // INFO_LOG(G3D, "Reloading texture to do the scaling we skipped.."); match = false; @@ -1172,7 +1215,7 @@ void TextureCacheDX9::SetTexture(bool force) { gpuStats.numTextureInvalidations++; DEBUG_LOG(G3D, "Texture different or overwritten, reloading at %08x: %s", texaddr, reason); if (doDelete) { - if (entry->maxLevel == maxLevel && entry->dim == gstate.getTextureDimension(0) && entry->format == format && g_Config.iTexScalingLevel == 1) { + if (entry->maxLevel == maxLevel && entry->dim == gstate.getTextureDimension(0) && entry->format == format && standardScaleFactor_ == 1) { // Actually, if size and number of levels match, let's try to avoid deleting and recreating. // Instead, let's use glTexSubImage to replace the images. replaceImages = true; @@ -1291,21 +1334,7 @@ void TextureCacheDX9::SetTexture(bool force) { // If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient. D3DFORMAT dstFmt = GetDestFormat(format, gstate.getClutPaletteFormat()); - int scaleFactor; - // Auto-texture scale upto 5x rendering resolution - if (g_Config.iTexScalingLevel == 0) { - scaleFactor = g_Config.iInternalResolution; - if (scaleFactor == 0) { - scaleFactor = (PSP_CoreParameter().renderWidth + 479) / 480; - } - - scaleFactor = std::min(4, scaleFactor); - if (scaleFactor == 3) { - scaleFactor = 2; - } - } else { - scaleFactor = g_Config.iTexScalingLevel; - } + int scaleFactor = standardScaleFactor_; // Rachet down scale factor in low-memory mode. if (lowMemoryMode_) { @@ -1585,7 +1614,7 @@ void *TextureCacheDX9::DecodeTextureLevel(GETextureFormat format, GEPaletteForma ERROR_LOG_REPORT(G3D, "NO finalbuf! Will crash!"); } - if (!(g_Config.iTexScalingLevel == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) && w != bufw) { + if (!(standardScaleFactor_ == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) && w != bufw) { int pixelSize; switch (dstFmt) { case D3DFMT_A4R4G4B4: diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index 152d14a6be..e849dc9ef9 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -454,8 +454,9 @@ GLES_GPU::GLES_GPU(GraphicsContext *ctx) // Some of our defaults are different from hw defaults, let's assert them. // We restore each frame anyway, but here is convenient for tests. - transformDraw_.RestoreVAO(); glstate.Restore(); + transformDraw_.RestoreVAO(); + textureCache_.NotifyConfigChanged(); } GLES_GPU::~GLES_GPU() { @@ -715,6 +716,7 @@ void GLES_GPU::BeginFrameInternal() { CheckGPUFeatures(); UpdateCmdInfo(); transformDraw_.Resized(); + textureCache_.NotifyConfigChanged(); } UpdateVsyncInterval(resized_); resized_ = false; diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 16b0b39f56..4d7e77ab52 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -879,101 +879,101 @@ void TextureCache::ApplyTexture() { nextTexture_ = nullptr; } -void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { - DepalShader *depal = nullptr; - const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); - if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { - depal = depalShaderCache_->GetDepalettizeShader(clutFormat, framebuffer->drawnFormat); - } - if (depal) { - GLuint clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); - FBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, FBO_8888); - fbo_bind_as_render_target(depalFBO); +class TextureShaderApplier { +public: + struct Pos { + Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { + } + Pos() { + } - struct Pos { - Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { - } - float x; - float y; - float z; - }; - struct UV { - UV(float u_, float v_) : u(u_), v(v_) { - } - float u; - float v; - }; + float x; + float y; + float z; + }; + struct UV { + UV(float u_, float v_) : u(u_), v(v_) { + } + UV() { + } - Pos pos[4] = { + float u; + float v; + }; + + TextureShaderApplier(DepalShader *shader, float bufferW, float bufferH, int renderW, int renderH) + : shader_(shader), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) { + static const Pos pos[4] = { {-1, -1, -1}, { 1, -1, -1}, { 1, 1, -1}, {-1, 1, -1}, }; - UV uv[4] = { + memcpy(pos_, pos, sizeof(pos_)); + + static const UV uv[4] = { {0, 0}, {1, 0}, {1, 1}, {0, 1}, }; - static const GLubyte indices[4] = { 0, 1, 3, 2 }; + memcpy(uv_, uv, sizeof(uv_)); + } + void ApplyBounds(const KnownVertexBounds &bounds, u32 uoff, u32 voff) { // If min is not < max, then we don't have values (wasn't set during decode.) - if (gstate_c.vertBounds.minV < gstate_c.vertBounds.maxV) { - const float invWidth = 1.0f / (float)framebuffer->bufferWidth; - const float invHeight = 1.0f / (float)framebuffer->bufferHeight; + if (bounds.minV < bounds.maxV) { + const float invWidth = 1.0f / bufferW_; + const float invHeight = 1.0f / bufferH_; // Inverse of half = double. const float invHalfWidth = invWidth * 2.0f; const float invHalfHeight = invHeight * 2.0f; - const int u1 = gstate_c.vertBounds.minU + gstate_c.curTextureXOffset; - const int v1 = gstate_c.vertBounds.minV + gstate_c.curTextureYOffset; - const int u2 = gstate_c.vertBounds.maxU + gstate_c.curTextureXOffset; - const int v2 = gstate_c.vertBounds.maxV + gstate_c.curTextureYOffset; + const int u1 = bounds.minU + uoff; + const int v1 = bounds.minV + voff; + const int u2 = bounds.maxU + uoff; + const int v2 = bounds.maxV + voff; const float left = u1 * invHalfWidth - 1.0f; const float right = u2 * invHalfWidth - 1.0f; const float top = v1 * invHalfHeight - 1.0f; const float bottom = v2 * invHalfHeight - 1.0f; // Points are: BL, BR, TR, TL. - pos[0] = Pos(left, bottom, -1.0f); - pos[1] = Pos(right, bottom, -1.0f); - pos[2] = Pos(right, top, -1.0f); - pos[3] = Pos(left, top, -1.0f); + pos_[0] = Pos(left, bottom, -1.0f); + pos_[1] = Pos(right, bottom, -1.0f); + pos_[2] = Pos(right, top, -1.0f); + pos_[3] = Pos(left, top, -1.0f); // And also the UVs, same order. const float uvleft = u1 * invWidth; const float uvright = u2 * invWidth; const float uvtop = v1 * invHeight; const float uvbottom = v2 * invHeight; - uv[0] = UV(uvleft, uvbottom); - uv[1] = UV(uvright, uvbottom); - uv[2] = UV(uvright, uvtop); - uv[3] = UV(uvleft, uvtop); + uv_[0] = UV(uvleft, uvbottom); + uv_[1] = UV(uvright, uvbottom); + uv_[2] = UV(uvright, uvtop); + uv_[3] = UV(uvleft, uvtop); } + } - shaderManager_->DirtyLastShader(); - - glUseProgram(depal->program); + void Use(TransformDrawEngine *transformDraw) { + glUseProgram(shader_->program); // Restore will rebind all of the state below. if (gstate_c.Supports(GPU_SUPPORTS_VAO)) { - transformDraw_->BindBuffer(pos, sizeof(pos), uv, sizeof(uv)); - transformDraw_->BindElementBuffer(indices, sizeof(indices)); + static const GLubyte indices[4] = { 0, 1, 3, 2 }; + transformDraw->BindBuffer(pos_, sizeof(pos_), uv_, sizeof(uv_)); + transformDraw->BindElementBuffer(indices, sizeof(indices)); } else { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - glEnableVertexAttribArray(depal->a_position); - glEnableVertexAttribArray(depal->a_texcoord0); + glEnableVertexAttribArray(shader_->a_position); + glEnableVertexAttribArray(shader_->a_texcoord0); + } - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, clutTexture); - glActiveTexture(GL_TEXTURE0); - - framebufferManager_->BindFramebufferColor(GL_TEXTURE0, gstate.getFrameBufRawAddress(), framebuffer, BINDFBCOLOR_SKIP_COPY); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + void Shade() { + static const GLubyte indices[4] = { 0, 1, 3, 2 }; glstate.blend.force(false); glstate.colorMask.force(true, true, true, true); @@ -984,22 +984,60 @@ void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuf #if !defined(USING_GLES2) glstate.colorLogicOp.force(false); #endif - glViewport(0, 0, framebuffer->renderWidth, framebuffer->renderHeight); + glViewport(0, 0, renderW_, renderH_); if (gstate_c.Supports(GPU_SUPPORTS_VAO)) { - glVertexAttribPointer(depal->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0); - glVertexAttribPointer(depal->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (void *)sizeof(pos)); + glVertexAttribPointer(shader_->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0); + glVertexAttribPointer(shader_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (void *)sizeof(pos_)); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, 0); } else { - glVertexAttribPointer(depal->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos); - glVertexAttribPointer(depal->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, uv); + glVertexAttribPointer(shader_->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos_); + glVertexAttribPointer(shader_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, uv_); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices); } - glDisableVertexAttribArray(depal->a_position); - glDisableVertexAttribArray(depal->a_texcoord0); + glDisableVertexAttribArray(shader_->a_position); + glDisableVertexAttribArray(shader_->a_texcoord0); + + glstate.Restore(); + } + +protected: + DepalShader *shader_; + Pos pos_[4]; + UV uv_[4]; + float bufferW_; + float bufferH_; + int renderW_; + int renderH_; +}; + +void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { + DepalShader *depal = nullptr; + const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); + if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { + depal = depalShaderCache_->GetDepalettizeShader(clutFormat, framebuffer->drawnFormat); + } + if (depal) { + GLuint clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); + FBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, FBO_8888); + fbo_bind_as_render_target(depalFBO); + shaderManager_->DirtyLastShader(); + + TextureShaderApplier shaderApply(depal, framebuffer->bufferWidth, framebuffer->bufferHeight, framebuffer->renderWidth, framebuffer->renderHeight); + shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset); + shaderApply.Use(transformDraw_); + + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, clutTexture); + glActiveTexture(GL_TEXTURE0); + + framebufferManager_->BindFramebufferColor(GL_TEXTURE0, gstate.getFrameBufRawAddress(), framebuffer, BINDFBCOLOR_SKIP_COPY); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + shaderApply.Shade(); fbo_bind_color_as_texture(depalFBO, 0); - glstate.Restore(); } else { framebufferManager_->BindFramebufferColor(GL_TEXTURE0, gstate.getFrameBufRawAddress(), framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); } @@ -1230,7 +1268,7 @@ void TextureCache::SetTexture(bool force) { } } - if (match && (entry->status & TexCacheEntry::STATUS_TO_SCALE) && g_Config.iTexScalingLevel != 1 && texelsScaledThisFrame_ < TEXCACHE_MAX_TEXELS_SCALED) { + if (match && (entry->status & TexCacheEntry::STATUS_TO_SCALE) && standardScaleFactor_ != 1 && texelsScaledThisFrame_ < TEXCACHE_MAX_TEXELS_SCALED) { if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) == 0) { // INFO_LOG(G3D, "Reloading texture to do the scaling we skipped.."); match = false; @@ -1255,7 +1293,7 @@ void TextureCache::SetTexture(bool force) { gpuStats.numTextureInvalidations++; DEBUG_LOG(G3D, "Texture different or overwritten, reloading at %08x: %s", texaddr, reason); if (doDelete) { - if (entry->maxLevel == maxLevel && entry->dim == gstate.getTextureDimension(0) && entry->format == format && g_Config.iTexScalingLevel == 1) { + if (entry->maxLevel == maxLevel && entry->dim == gstate.getTextureDimension(0) && entry->format == format && standardScaleFactor_ == 1) { // Actually, if size and number of levels match, let's try to avoid deleting and recreating. // Instead, let's use glTexSubImage to replace the images. replaceImages = true; @@ -1380,27 +1418,7 @@ void TextureCache::SetTexture(bool force) { // If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient. GLenum dstFmt = GetDestFormat(format, gstate.getClutPaletteFormat()); - int scaleFactor; - // Auto-texture scale upto 5x rendering resolution - if (g_Config.iTexScalingLevel == 0) { - scaleFactor = g_Config.iInternalResolution; - if (scaleFactor == 0) { - scaleFactor = (PSP_CoreParameter().renderWidth + 479) / 480; - } - - // Mobile devices don't get the higher scale factors, too expensive. Very rough way to decide though... - if (!gstate_c.Supports(GPU_IS_MOBILE)) { - bool supportNpot = gstate_c.Supports(GPU_SUPPORTS_OES_TEXTURE_NPOT); - scaleFactor = std::min(supportNpot ? 5 : 4, scaleFactor); - if (!supportNpot && scaleFactor == 3) { - scaleFactor = 2; - } - } else { - scaleFactor = std::min(gstate_c.Supports(GPU_SUPPORTS_OES_TEXTURE_NPOT) ? 3 : 2, scaleFactor); - } - } else { - scaleFactor = g_Config.iTexScalingLevel; - } + int scaleFactor = standardScaleFactor_; // Rachet down scale factor in low-memory mode. if (lowMemoryMode_) {