mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #8379 from unknownbrackets/clut-render-prep
Refactor some of texcache for clut render changes
This commit is contained in:
commit
d4ad1a6645
6 changed files with 281 additions and 187 deletions
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_) {
|
||||
|
|
Loading…
Add table
Reference in a new issue