mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-29 12:34:17 +01:00
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
This commit is contained in:
parent
8bc444bb97
commit
bc04662525
@ -434,6 +434,11 @@ void LatteTexture_SyncSlice(LatteTexture* srcTexture, sint32 srcSliceIndex, sint
|
|||||||
sint32 dstWidth = dstTexture->width;
|
sint32 dstWidth = dstTexture->width;
|
||||||
sint32 dstHeight = dstTexture->height;
|
sint32 dstHeight = dstTexture->height;
|
||||||
|
|
||||||
|
if(srcTexture->overwriteInfo.hasFormatOverwrite != dstTexture->overwriteInfo.hasFormatOverwrite)
|
||||||
|
return; // dont sync: format overwrite state needs to match. Not strictly necessary but it simplifies logic down the road
|
||||||
|
else if(srcTexture->overwriteInfo.hasFormatOverwrite && srcTexture->overwriteInfo.format != dstTexture->overwriteInfo.format)
|
||||||
|
return; // both are overwritten but with different formats
|
||||||
|
|
||||||
if (srcMipIndex == 0 && dstMipIndex == 0 && (srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED || srcTexture->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THIN1) && srcTexture->height > dstTexture->height && (srcTexture->height % dstTexture->height) == 0)
|
if (srcMipIndex == 0 && dstMipIndex == 0 && (srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED || srcTexture->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THIN1) && srcTexture->height > dstTexture->height && (srcTexture->height % dstTexture->height) == 0)
|
||||||
{
|
{
|
||||||
bool isMatch = srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED;
|
bool isMatch = srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED;
|
||||||
@ -816,6 +821,12 @@ VIEWCOMPATIBILITY LatteTexture_CanTextureBeRepresentedAsView(LatteTexture* baseT
|
|||||||
{
|
{
|
||||||
relativeMipIndex = 0;
|
relativeMipIndex = 0;
|
||||||
relativeSliceIndex = 0;
|
relativeSliceIndex = 0;
|
||||||
|
if (baseTexture->overwriteInfo.hasFormatOverwrite)
|
||||||
|
{
|
||||||
|
// if the base format is overwritten, then we only allow aliasing if the view format matches the base format
|
||||||
|
if (baseTexture->format != format)
|
||||||
|
return VIEW_NOT_COMPATIBLE;
|
||||||
|
}
|
||||||
if (LatteTexture_IsFormatViewCompatible(baseTexture->format, format) == false)
|
if (LatteTexture_IsFormatViewCompatible(baseTexture->format, format) == false)
|
||||||
return VIEW_NOT_COMPATIBLE;
|
return VIEW_NOT_COMPATIBLE;
|
||||||
if (baseTexture->physAddress == physAddr && baseTexture->pitch == pitch)
|
if (baseTexture->physAddress == physAddr && baseTexture->pitch == pitch)
|
||||||
|
@ -26,7 +26,7 @@ LatteTextureGL::LatteTextureGL(Latte::E_DIM dim, MPTR physAddress, MPTR physMipA
|
|||||||
GenerateEmptyTextureFromGX2Dim(dim, this->glId_texture, this->glTexTarget, true);
|
GenerateEmptyTextureFromGX2Dim(dim, this->glId_texture, this->glTexTarget, true);
|
||||||
// set format info
|
// set format info
|
||||||
FormatInfoGL glFormatInfo;
|
FormatInfoGL glFormatInfo;
|
||||||
GetOpenGLFormatInfo(isDepth, format, dim, &glFormatInfo);
|
GetOpenGLFormatInfo(isDepth, overwriteInfo.hasFormatOverwrite ? (Latte::E_GX2SURFFMT)overwriteInfo.format : format, dim, &glFormatInfo);
|
||||||
this->glInternalFormat = glFormatInfo.glInternalFormat;
|
this->glInternalFormat = glFormatInfo.glInternalFormat;
|
||||||
this->isAlternativeFormat = glFormatInfo.isUsingAlternativeFormat;
|
this->isAlternativeFormat = glFormatInfo.isUsingAlternativeFormat;
|
||||||
this->hasStencil = glFormatInfo.hasStencil; // todo - should get this from the GX2 format?
|
this->hasStencil = glFormatInfo.hasStencil; // todo - should get this from the GX2 format?
|
||||||
|
@ -55,12 +55,16 @@ LatteTextureViewGL::~LatteTextureViewGL()
|
|||||||
void LatteTextureViewGL::InitAliasView()
|
void LatteTextureViewGL::InitAliasView()
|
||||||
{
|
{
|
||||||
const auto texture = (LatteTextureGL*)baseTexture;
|
const auto texture = (LatteTextureGL*)baseTexture;
|
||||||
// get internal format
|
// compute internal format
|
||||||
if (baseTexture->isDepth)
|
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
|
// depth is handled differently
|
||||||
cemuLog_logDebug(LogType::Force, "Creating depth view");
|
cemu_assert(format == texture->format); // is depth alias with different format intended?
|
||||||
cemu_assert(format == texture->format); // todo
|
|
||||||
glInternalFormat = texture->glInternalFormat;
|
glInternalFormat = texture->glInternalFormat;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -73,7 +77,7 @@ void LatteTextureViewGL::InitAliasView()
|
|||||||
catchOpenGLError();
|
catchOpenGLError();
|
||||||
if (firstMip >= texture->maxPossibleMipLevels)
|
if (firstMip >= texture->maxPossibleMipLevels)
|
||||||
{
|
{
|
||||||
cemuLog_logDebug(LogType::Force, "_createNewView: Out of bounds mip level requested");
|
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);
|
glTextureView(glTexId, glTexTarget, texture->glId_texture, glInternalFormat, texture->maxPossibleMipLevels - 1, numMip, firstSlice, this->numSlice);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -330,13 +330,14 @@ void OpenGLRenderer::Initialize()
|
|||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
// create framebuffer for fast clearing (avoid glClearTexSubImage on Nvidia)
|
// create framebuffer for fast clearing (avoid glClearTexSubImage on Nvidia)
|
||||||
if (this->m_vendor == GfxVendor::Nvidia || glClearTexSubImage == nullptr)
|
if (glCreateFramebuffers)
|
||||||
{
|
|
||||||
// generate framebuffer
|
|
||||||
if (glCreateFramebuffers && false)
|
|
||||||
glCreateFramebuffers(1, &glRendererState.clearFBO);
|
glCreateFramebuffers(1, &glRendererState.clearFBO);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
glGenFramebuffers(1, &glRendererState.clearFBO);
|
glGenFramebuffers(1, &glRendererState.clearFBO);
|
||||||
|
// bind to initialize
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER_EXT, glRendererState.clearFBO);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_init();
|
draw_init();
|
||||||
@ -425,9 +426,12 @@ void _glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GL
|
|||||||
return;
|
return;
|
||||||
if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "Dithering is enabled"))
|
if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "Dithering is enabled"))
|
||||||
return;
|
return;
|
||||||
|
if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "Blending is enabled, but is not supported for integer framebuffers"))
|
||||||
|
return;
|
||||||
if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "does not have a defined base level"))
|
if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "does not have a defined base level"))
|
||||||
return;
|
return;
|
||||||
|
if(LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "has depth comparisons disabled, with a texture object"))
|
||||||
|
return;
|
||||||
|
|
||||||
cemuLog_log(LogType::Force, "GLDEBUG: {}", message);
|
cemuLog_log(LogType::Force, "GLDEBUG: {}", message);
|
||||||
|
|
||||||
@ -670,7 +674,10 @@ void OpenGLRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo)
|
|||||||
{
|
{
|
||||||
auto cfboGL = (CachedFBOGL*)cfbo;
|
auto cfboGL = (CachedFBOGL*)cfbo;
|
||||||
if (prevBoundFBO == cfboGL->glId_fbo)
|
if (prevBoundFBO == cfboGL->glId_fbo)
|
||||||
prevBoundFBO = -1;
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||||
|
prevBoundFBO = 0;
|
||||||
|
}
|
||||||
glDeleteFramebuffers(1, &cfboGL->glId_fbo);
|
glDeleteFramebuffers(1, &cfboGL->glId_fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1013,9 +1020,6 @@ void OpenGLRenderer::texture_reserveTextureOnGPU(LatteTexture* hostTextureGeneri
|
|||||||
effectiveBaseHeight = hostTexture->overwriteInfo.height;
|
effectiveBaseHeight = hostTexture->overwriteInfo.height;
|
||||||
effectiveBaseDepth = hostTexture->overwriteInfo.depth;
|
effectiveBaseDepth = hostTexture->overwriteInfo.depth;
|
||||||
}
|
}
|
||||||
// get format info
|
|
||||||
LatteTextureGL::FormatInfoGL glFormatInfo;
|
|
||||||
LatteTextureGL::GetOpenGLFormatInfo(hostTexture->isDepth, hostTexture->overwriteInfo.hasFormatOverwrite ? (Latte::E_GX2SURFFMT)hostTexture->overwriteInfo.format : hostTexture->format, hostTexture->dim, &glFormatInfo);
|
|
||||||
// calculate mip count
|
// calculate mip count
|
||||||
sint32 mipLevels = std::min(hostTexture->mipLevels, hostTexture->maxPossibleMipLevels);
|
sint32 mipLevels = std::min(hostTexture->mipLevels, hostTexture->maxPossibleMipLevels);
|
||||||
mipLevels = std::max(mipLevels, 1);
|
mipLevels = std::max(mipLevels, 1);
|
||||||
@ -1023,25 +1027,25 @@ void OpenGLRenderer::texture_reserveTextureOnGPU(LatteTexture* hostTextureGeneri
|
|||||||
if (hostTexture->dim == Latte::E_DIM::DIM_2D || hostTexture->dim == Latte::E_DIM::DIM_2D_MSAA)
|
if (hostTexture->dim == Latte::E_DIM::DIM_2D || hostTexture->dim == Latte::E_DIM::DIM_2D_MSAA)
|
||||||
{
|
{
|
||||||
cemu_assert_debug(effectiveBaseDepth == 1);
|
cemu_assert_debug(effectiveBaseDepth == 1);
|
||||||
glTextureStorage2DWrapper(GL_TEXTURE_2D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight);
|
glTextureStorage2DWrapper(GL_TEXTURE_2D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight);
|
||||||
}
|
}
|
||||||
else if (hostTexture->dim == Latte::E_DIM::DIM_1D)
|
else if (hostTexture->dim == Latte::E_DIM::DIM_1D)
|
||||||
{
|
{
|
||||||
cemu_assert_debug(effectiveBaseHeight == 1);
|
cemu_assert_debug(effectiveBaseHeight == 1);
|
||||||
cemu_assert_debug(effectiveBaseDepth == 1);
|
cemu_assert_debug(effectiveBaseDepth == 1);
|
||||||
glTextureStorage1DWrapper(GL_TEXTURE_1D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth);
|
glTextureStorage1DWrapper(GL_TEXTURE_1D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth);
|
||||||
}
|
}
|
||||||
else if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA)
|
else if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA)
|
||||||
{
|
{
|
||||||
glTextureStorage3DWrapper(GL_TEXTURE_2D_ARRAY, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));
|
glTextureStorage3DWrapper(GL_TEXTURE_2D_ARRAY, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));
|
||||||
}
|
}
|
||||||
else if (hostTexture->dim == Latte::E_DIM::DIM_3D)
|
else if (hostTexture->dim == Latte::E_DIM::DIM_3D)
|
||||||
{
|
{
|
||||||
glTextureStorage3DWrapper(GL_TEXTURE_3D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));
|
glTextureStorage3DWrapper(GL_TEXTURE_3D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));
|
||||||
}
|
}
|
||||||
else if (hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP)
|
else if (hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP)
|
||||||
{
|
{
|
||||||
glTextureStorage3DWrapper(GL_TEXTURE_CUBE_MAP_ARRAY, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, effectiveBaseDepth);
|
glTextureStorage3DWrapper(GL_TEXTURE_CUBE_MAP_ARRAY, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, effectiveBaseDepth);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1279,7 +1283,6 @@ void OpenGLRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip,
|
|||||||
{
|
{
|
||||||
auto srcGL = (LatteTextureGL*)src;
|
auto srcGL = (LatteTextureGL*)src;
|
||||||
auto dstGL = (LatteTextureGL*)dst;
|
auto dstGL = (LatteTextureGL*)dst;
|
||||||
|
|
||||||
if ((srcGL->isAlternativeFormat || dstGL->isAlternativeFormat) && (srcGL->glInternalFormat != dstGL->glInternalFormat))
|
if ((srcGL->isAlternativeFormat || dstGL->isAlternativeFormat) && (srcGL->glInternalFormat != dstGL->glInternalFormat))
|
||||||
{
|
{
|
||||||
if (srcGL->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT && dstGL->format == Latte::E_GX2SURFFMT::BC4_UNORM)
|
if (srcGL->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT && dstGL->format == Latte::E_GX2SURFFMT::BC4_UNORM)
|
||||||
|
@ -195,7 +195,7 @@ private:
|
|||||||
GLuint glStreamoutCacheRingBuffer;
|
GLuint glStreamoutCacheRingBuffer;
|
||||||
|
|
||||||
// cfbo
|
// cfbo
|
||||||
GLuint prevBoundFBO = -1;
|
GLuint prevBoundFBO = 0;
|
||||||
GLuint glId_fbo = 0;
|
GLuint glId_fbo = 0;
|
||||||
|
|
||||||
// renderstate
|
// renderstate
|
||||||
|
@ -57,7 +57,12 @@ uint32 LatteTextureVk_AdjustTextureCompSel(Latte::E_GX2SURFFMT format, uint32 co
|
|||||||
LatteTextureViewVk::LatteTextureViewVk(VkDevice device, LatteTextureVk* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
|
LatteTextureViewVk::LatteTextureViewVk(VkDevice device, LatteTextureVk* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
|
||||||
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_device(device)
|
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_device(device)
|
||||||
{
|
{
|
||||||
if (dim != texture->dim || format != texture->format)
|
if(texture->overwriteInfo.hasFormatOverwrite)
|
||||||
|
{
|
||||||
|
cemu_assert_debug(format == texture->format); // if format overwrite is used, the texture is no longer taking part in aliasing and the format of any view has to match
|
||||||
|
m_format = texture->GetFormat();
|
||||||
|
}
|
||||||
|
else if (dim != texture->dim || format != texture->format)
|
||||||
{
|
{
|
||||||
VulkanRenderer::FormatInfoVK texFormatInfo;
|
VulkanRenderer::FormatInfoVK texFormatInfo;
|
||||||
VulkanRenderer::GetInstance()->GetTextureFormatInfoVK(format, texture->isDepth, dim, 0, 0, &texFormatInfo);
|
VulkanRenderer::GetInstance()->GetTextureFormatInfoVK(format, texture->isDepth, dim, 0, 0, &texFormatInfo);
|
||||||
|
Loading…
Reference in New Issue
Block a user