mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-01-07 15:48:15 +01:00
end render pass if attachment is being read
This commit is contained in:
parent
4f7288d937
commit
3d0055af6a
@ -29,7 +29,7 @@ std::map<Latte::E_GX2SURFFMT, MetalPixelFormatInfo> MTL_COLOR_FORMAT_TABLE = {
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM, {MTL::PixelFormatRGBA16Snorm, MetalDataType::FLOAT, 8}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_UINT, {MTL::PixelFormatRGB10A2Uint, MetalDataType::UINT, 4}},
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SINT, {MTL::PixelFormatRGBA16Sint, MetalDataType::INT, 8}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB, {MTL::PixelFormatRGBA8Unorm_sRGB, MetalDataType::FLOAT, 4}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB, {MTL::PixelFormatRGB10A2Unorm, MetalDataType::FLOAT, 4}}, // TODO: sRGB?
|
||||
{Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM, {MTL::PixelFormatBGR10A2Unorm, MetalDataType::FLOAT, 4}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::A2_B10_G10_R10_UINT, {MTL::PixelFormatRGB10A2Uint, MetalDataType::UINT, 4}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R16_UNORM, {MTL::PixelFormatR16Unorm, MetalDataType::FLOAT, 2}},
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "Cafe/HW/Latte/Core/LatteIndices.h"
|
||||
#include "Cemu/Logging/CemuDebugLogging.h"
|
||||
#include "Common/precompiled.h"
|
||||
#include "HW/Latte/Core/LatteConst.h"
|
||||
#include "HW/Latte/Renderer/Metal/MetalCommon.h"
|
||||
#include "Metal/MTLDevice.hpp"
|
||||
#include "Metal/MTLRenderCommandEncoder.hpp"
|
||||
@ -816,6 +817,28 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||
|
||||
auto& encoderState = m_state.m_encoderState;
|
||||
|
||||
// Shaders
|
||||
LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();
|
||||
LatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();
|
||||
LatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();
|
||||
if (!vertexShader)
|
||||
{
|
||||
debug_printf("no vertex function, skipping draw\n");
|
||||
return;
|
||||
}
|
||||
const auto fetchShader = LatteSHRC_GetActiveFetchShader();
|
||||
|
||||
// Check if we need to end the render pass
|
||||
// Fragment shader is most likely to require a render pass flush, so check for it first
|
||||
bool endRenderPass = CheckIfRenderPassNeedsFlush(pixelShader);
|
||||
if (!endRenderPass)
|
||||
endRenderPass = CheckIfRenderPassNeedsFlush(vertexShader);
|
||||
if (!endRenderPass && geometryShader)
|
||||
endRenderPass = CheckIfRenderPassNeedsFlush(geometryShader);
|
||||
|
||||
if (endRenderPass)
|
||||
EndEncoding();
|
||||
|
||||
// Render pass
|
||||
auto renderCommandEncoder = GetRenderCommandEncoder();
|
||||
|
||||
@ -824,23 +847,10 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||
auto mtlPrimitiveType = GetMtlPrimitiveType(primitiveMode);
|
||||
bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS);
|
||||
|
||||
// Shaders
|
||||
LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();
|
||||
LatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();
|
||||
LatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();
|
||||
if (!vertexShader)
|
||||
{
|
||||
debug_printf("no vertex function, skipping draw\n");
|
||||
return;
|
||||
}
|
||||
const auto fetchShader = LatteSHRC_GetActiveFetchShader();
|
||||
|
||||
bool usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect);
|
||||
bool usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect);
|
||||
|
||||
// Depth stencil state
|
||||
// TODO: implement this somehow
|
||||
//auto depthControl = LatteGPUState.contextNew.DB_DEPTH_CONTROL;
|
||||
|
||||
// TODO
|
||||
// Disable depth write when there is no depth attachment
|
||||
//if (!m_state.m_lastUsedFBO->depthBuffer.texture)
|
||||
// depthControl.set_Z_WRITE_ENABLE(false);
|
||||
@ -1103,6 +1113,8 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
|
||||
}
|
||||
}
|
||||
|
||||
m_state.m_isFirstDrawInRenderPass = false;
|
||||
|
||||
LatteStreamout_FinishDrawcall(false);
|
||||
|
||||
LatteGPUState.drawCallCounter++;
|
||||
@ -1235,6 +1247,7 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecr
|
||||
|
||||
// Update state
|
||||
m_state.m_lastUsedFBO = m_state.m_activeFBO;
|
||||
m_state.m_isFirstDrawInRenderPass = true;
|
||||
|
||||
auto renderCommandEncoder = commandBuffer->renderCommandEncoder(m_state.m_activeFBO->GetRenderPassDescriptor());
|
||||
#ifdef CEMU_DEBUG_ASSERT
|
||||
@ -1358,6 +1371,53 @@ bool MetalRenderer::AcquireNextDrawable(bool mainWindow)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetalRenderer::CheckIfRenderPassNeedsFlush(LatteDecompilerShader* shader)
|
||||
{
|
||||
sint32 textureCount = shader->resourceMapping.getTextureCount();
|
||||
for (int i = 0; i < textureCount; ++i)
|
||||
{
|
||||
const auto relative_textureUnit = shader->resourceMapping.getTextureUnitFromBindingPoint(i);
|
||||
auto hostTextureUnit = relative_textureUnit;
|
||||
auto textureDim = shader->textureUnitDim[relative_textureUnit];
|
||||
auto texUnitRegIndex = hostTextureUnit * 7;
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
hostTextureUnit += LATTE_CEMU_VS_TEX_UNIT_BASE;
|
||||
texUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS;
|
||||
break;
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
hostTextureUnit += LATTE_CEMU_PS_TEX_UNIT_BASE;
|
||||
texUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS;
|
||||
break;
|
||||
case LatteConst::ShaderType::Geometry:
|
||||
hostTextureUnit += LATTE_CEMU_GS_TEX_UNIT_BASE;
|
||||
texUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
auto textureView = m_state.m_textures[hostTextureUnit];
|
||||
if (!textureView)
|
||||
continue;
|
||||
|
||||
LatteTexture* baseTexture = textureView->baseTexture;
|
||||
if (!m_state.m_isFirstDrawInRenderPass)
|
||||
{
|
||||
// If the texture is also used in the current render pass, we need to end the render pass to "flush" the texture
|
||||
for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)
|
||||
{
|
||||
auto colorTarget = m_state.m_activeFBO->colorBuffer[i].texture;
|
||||
if (colorTarget && colorTarget->baseTexture == baseTexture)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader, bool usesGeometryShader)
|
||||
{
|
||||
auto mtlShaderType = GetMtlShaderType(shader->shaderType, usesGeometryShader);
|
||||
|
@ -127,6 +127,7 @@ struct MetalState
|
||||
bool m_usesSRGB = false;
|
||||
|
||||
bool m_skipDrawSequence = false;
|
||||
bool m_isFirstDrawInRenderPass = true;
|
||||
|
||||
class CachedFBOMtl* m_activeFBO = nullptr;
|
||||
// If the FBO changes, but it's the same FBO as the last one with some omitted attachments, this FBO doesn't change'
|
||||
@ -385,6 +386,7 @@ public:
|
||||
|
||||
bool AcquireNextDrawable(bool mainWindow);
|
||||
|
||||
bool CheckIfRenderPassNeedsFlush(LatteDecompilerShader* shader);
|
||||
void BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader, bool usesGeometryShader);
|
||||
|
||||
void ClearColorTextureInternal(MTL::Texture* mtlTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a);
|
||||
|
Loading…
Reference in New Issue
Block a user