Cemu/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp
Exzap bc04662525 Latte+GL+VK: Improve handling of gfx pack texture overwrite format
Graphic packs can overwrite the format of a texture (e.g. for higher bitdepth to lessen banding) but the code for this wasn't correctly working anymore.

- Fixes overwrite format being ignored for texture views on Vulkan backend
- Fixes overwrite format not being used for texture views on OpenGL

Format aliasing is complicated enough as it is, even without overwrites, so this adds a new rule to make behavior more well defined: If two textures share memory but only one uses an overwrite format, then they are no longer synchronized and are considered separate textures.

Bonus fixes for OpenGL:
- Use fbo 0 instead of -1 as the default. This silences some warnings in debug output
- On OpenGL, bind new framebuffers on handle generation so they are considered created
2024-03-13 02:41:42 +01:00

122 lines
4.4 KiB
C++

#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
#include "config/LaunchSettings.h"
LatteTextureViewGL::LatteTextureViewGL(LatteTextureGL* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount, bool registerView, bool forceCreateNewTexId)
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format, registerView)
{
if (dim != texture->dim || format != texture->format ||
firstSlice != 0 || firstMip != 0 || mipCount != texture->mipLevels || sliceCount != texture->depth ||
forceCreateNewTexId)
{
LatteTextureGL::GenerateEmptyTextureFromGX2Dim(dim, glTexId, glTexTarget, false);
this->glInternalFormat = 0;
InitAliasView();
}
else
{
glTexId = texture->glId_texture;
glTexTarget = texture->glTexTarget;
glInternalFormat = texture->glInternalFormat;
}
// mark all sampler properties as undefined
samplerState.maxAniso = 0xFF;
samplerState.filterMin = 0xFFFFFFFF;
samplerState.filterMag = 0xFFFFFFFF;
samplerState.maxMipLevels = 0xFF;
samplerState.borderType = 0xFF;
samplerState.borderColor[0] = 9999.0f;
samplerState.borderColor[1] = 9999.0f;
samplerState.borderColor[2] = 9999.0f;
samplerState.borderColor[3] = 9999.0f;
samplerState.clampS = 0xFF;
samplerState.clampT = 0xFF;
samplerState.clampR = 0xFF;
samplerState.minLod = 0xFFFF;
samplerState.maxLod = 0xFFFF;
samplerState.lodBias = 0x7FFF;
samplerState.depthCompareMode = 0xFF;
samplerState.depthCompareFunc = 0xFF;
swizzleR = 0xFF;
swizzleG = 0xFF;
swizzleB = 0xFF;
swizzleA = 0xFF;
}
LatteTextureViewGL::~LatteTextureViewGL()
{
delete m_alternativeView;
((OpenGLRenderer*)g_renderer.get())->texture_notifyDelete(this);
glDeleteTextures(1, &glTexId);
}
void LatteTextureViewGL::InitAliasView()
{
const auto texture = (LatteTextureGL*)baseTexture;
// compute internal format
if(texture->overwriteInfo.hasFormatOverwrite)
{
cemu_assert_debug(format == texture->format);
glInternalFormat = texture->glInternalFormat; // for format overwrite no aliasing is allowed and thus we always inherit the internal format of the base texture
}
else if (baseTexture->isDepth)
{
// depth is handled differently
cemu_assert(format == texture->format); // is depth alias with different format intended?
glInternalFormat = texture->glInternalFormat;
}
else
{
LatteTextureGL::FormatInfoGL glFormatInfo;
LatteTextureGL::GetOpenGLFormatInfo(baseTexture->isDepth, format, dim, &glFormatInfo);
glInternalFormat = glFormatInfo.glInternalFormat;
}
catchOpenGLError();
if (firstMip >= texture->maxPossibleMipLevels)
{
cemuLog_logDebug(LogType::Force, "InitAliasView(): Out of bounds mip level requested");
glTextureView(glTexId, glTexTarget, texture->glId_texture, glInternalFormat, texture->maxPossibleMipLevels - 1, numMip, firstSlice, this->numSlice);
}
else
glTextureView(glTexId, glTexTarget, texture->glId_texture, glInternalFormat, firstMip, numMip, firstSlice, numSlice);
catchOpenGLError();
if (glTextureParameteri)
{
glTextureParameteri(glTexId, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(glTexId, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(glTexId, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(glTexId, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameteri(glTexId, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTextureParameteri(glTexId, GL_TEXTURE_COMPARE_MODE, GL_NONE);
}
else
{
// todo - fallback for when DSA isn't supported
}
// set debug name
bool useGLDebugNames = false;
#ifdef CEMU_DEBUG_ASSERT
useGLDebugNames = true;
#endif
if (LaunchSettings::NSightModeEnabled())
useGLDebugNames = true;
if (useGLDebugNames)
{
char textureDebugLabel[512];
sprintf(textureDebugLabel, "%08x_f%04x_p%04x_viewFMT%04x%s_org%d", baseTexture->physAddress, (uint32)baseTexture->format, baseTexture->pitch, (uint32)this->format, baseTexture->isDepth?"_d":"", texture->glId_texture);
glObjectLabel(GL_TEXTURE, glTexId, -1, textureDebugLabel);
}
}
LatteTextureViewGL* LatteTextureViewGL::GetAlternativeView()
{
if (!m_alternativeView)
m_alternativeView = new LatteTextureViewGL((LatteTextureGL*)baseTexture, dim, format, firstMip, numMip, firstSlice, numSlice, false, true);
return m_alternativeView;
}