Merge pull request #8379 from unknownbrackets/clut-render-prep

Refactor some of texcache for clut render changes
This commit is contained in:
Henrik Rydgård 2016-01-04 09:43:15 +01:00
commit d4ad1a6645
6 changed files with 281 additions and 187 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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;
}

View file

@ -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:

View file

@ -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;

View file

@ -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_) {