Add partial conditional rendering support

Disabled for cases where the results come from queries rn, however still functional for cases like AC which don't use it with queries.
This commit is contained in:
Billy Laws 2023-03-21 22:39:02 +00:00
parent a2798a9184
commit c440575a56
3 changed files with 80 additions and 8 deletions

View File

@ -616,6 +616,7 @@ namespace skyline::gpu::interconnect {
slot->nodes.splice(slot->nodes.end(), slot->pendingPostRenderPassNodes); slot->nodes.splice(slot->nodes.end(), slot->pendingPostRenderPassNodes);
{ {
slot->WaitReady(); slot->WaitReady();

View File

@ -62,6 +62,47 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
beginMethodTopology : type::ConvertPrimitiveTopologyToDrawTopology(*registers.primitiveTopology); beginMethodTopology : type::ConvertPrimitiveTopologyToDrawTopology(*registers.primitiveTopology);
} }
bool Maxwell3D::CheckRenderEnable() {
if (registers.renderEnableOverride->mode == Registers::RenderEnableOverride::Mode::AlwaysRender)
return true;
else if (registers.renderEnableOverride->mode == Registers::RenderEnableOverride::Mode::NeverRender)
return false;
switch (registers.renderEnable->mode) {
case Registers::RenderEnable::Mode::True:
return true;
case Registers::RenderEnable::Mode::False:
return false;
case Registers::RenderEnable::Mode::Conditional:
// TODO: Use indirect draws to emulate conditional rendering with queries, for now just ignore such cases as they would decrease performance anyway by forcing a CPU sync
if (interconnect.QueryPresentAtAddress(u64{registers.renderEnable->offset}))
return true;
return channelCtx.asCtx->gmmu.Read<u32>(registers.renderEnable->offset) != 0;
case Registers::RenderEnable::Mode::RenderIfEqual:
// TODO: See above
if (interconnect.QueryPresentAtAddress(u64{registers.renderEnable->offset}) ||
interconnect.QueryPresentAtAddress(u64{registers.renderEnable->offset + 16}))
return true;
return channelCtx.asCtx->gmmu.Read<u32>(registers.renderEnable->offset) ==
channelCtx.asCtx->gmmu.Read<u32>(registers.renderEnable->offset + 16);
case Registers::RenderEnable::Mode::RenderIfNotEqual:
// TODO: See above
if (interconnect.QueryPresentAtAddress(u64{registers.renderEnable->offset}) ||
interconnect.QueryPresentAtAddress(u64{registers.renderEnable->offset + 16}))
return true;
return channelCtx.asCtx->gmmu.Read<u32>(registers.renderEnable->offset) !=
channelCtx.asCtx->gmmu.Read<u32>(registers.renderEnable->offset + 16);
}
return true;
}
Maxwell3D::Maxwell3D(const DeviceState &state, ChannelContext &channelCtx, MacroState &macroState) Maxwell3D::Maxwell3D(const DeviceState &state, ChannelContext &channelCtx, MacroState &macroState)
: MacroEngineBase{macroState}, : MacroEngineBase{macroState},
syncpoints{state.soc->host1x.syncpoints}, syncpoints{state.soc->host1x.syncpoints},
@ -76,7 +117,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
__attribute__((always_inline)) void Maxwell3D::FlushDeferredDraw() { __attribute__((always_inline)) void Maxwell3D::FlushDeferredDraw() {
if (batchEnableState.drawActive) { if (batchEnableState.drawActive) {
batchEnableState.drawActive = false; batchEnableState.drawActive = false;
interconnect.Draw(deferredDraw.drawTopology, *registers.streamOutputEnable, deferredDraw.indexed, deferredDraw.drawCount, deferredDraw.drawFirst, deferredDraw.instanceCount, deferredDraw.drawBaseVertex, deferredDraw.drawBaseInstance); if (CheckRenderEnable())
interconnect.Draw(deferredDraw.drawTopology, *registers.streamOutputEnable, deferredDraw.indexed, deferredDraw.drawCount, deferredDraw.drawFirst, deferredDraw.instanceCount, deferredDraw.drawBaseVertex, deferredDraw.drawBaseInstance);
deferredDraw.instanceCount = 1; deferredDraw.instanceCount = 1;
} }
} }
@ -229,7 +271,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
}) })
ENGINE_CASE(clearSurface, { ENGINE_CASE(clearSurface, {
interconnect.Clear(clearSurface); if (CheckRenderEnable())
interconnect.Clear(clearSurface);
}) })
ENGINE_CASE(begin, { ENGINE_CASE(begin, {
@ -489,23 +532,23 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
auto topology{static_cast<type::DrawTopology>(drawTopology)}; auto topology{static_cast<type::DrawTopology>(drawTopology)};
registers.globalBaseInstanceIndex = globalBaseInstanceIndex; registers.globalBaseInstanceIndex = globalBaseInstanceIndex;
registers.vertexArrayStart = vertexArrayStart; registers.vertexArrayStart = vertexArrayStart;
if (CheckRenderEnable())
interconnect.Draw(topology, *registers.streamOutputEnable, false, vertexArrayCount, vertexArrayStart, instanceCount, 0, globalBaseInstanceIndex); interconnect.Draw(topology, *registers.streamOutputEnable, false, vertexArrayCount, vertexArrayStart, instanceCount, 0, globalBaseInstanceIndex);
registers.globalBaseInstanceIndex = 0; registers.globalBaseInstanceIndex = 0;
} }
void Maxwell3D::DrawIndexedInstanced(u32 drawTopology, u32 indexBufferCount, u32 instanceCount, u32 globalBaseVertexIndex, u32 indexBufferFirst, u32 globalBaseInstanceIndex) { void Maxwell3D::DrawIndexedInstanced(u32 drawTopology, u32 indexBufferCount, u32 instanceCount, u32 globalBaseVertexIndex, u32 indexBufferFirst, u32 globalBaseInstanceIndex) {
FlushEngineState(); FlushEngineState();
auto topology{static_cast<type::DrawTopology>(drawTopology)}; auto topology{static_cast<type::DrawTopology>(drawTopology)};
interconnect.Draw(topology, *registers.streamOutputEnable, true, indexBufferCount, indexBufferFirst, instanceCount, globalBaseVertexIndex, globalBaseInstanceIndex); if (CheckRenderEnable())
interconnect.Draw(topology, *registers.streamOutputEnable, true, indexBufferCount, indexBufferFirst, instanceCount, globalBaseVertexIndex, globalBaseInstanceIndex);
} }
void Maxwell3D::DrawIndexedIndirect(u32 drawTopology, span<u8> indirectBuffer, u32 count, u32 stride) { void Maxwell3D::DrawIndexedIndirect(u32 drawTopology, span<u8> indirectBuffer, u32 count, u32 stride) {
FlushEngineState(); FlushEngineState();
auto topology{static_cast<type::DrawTopology>(drawTopology)}; auto topology{static_cast<type::DrawTopology>(drawTopology)};
interconnect.DrawIndirect(topology, *registers.streamOutputEnable, true, indirectBuffer, count, stride); if (CheckRenderEnable())
interconnect.DrawIndirect(topology, *registers.streamOutputEnable, true, indirectBuffer, count, stride);
} }
} }

View File

@ -69,6 +69,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
} }
} deferredDraw{}; } deferredDraw{};
bool CheckRenderEnable();
type::DrawTopology ApplyTopologyOverride(type::DrawTopology beginMethodTopology); type::DrawTopology ApplyTopologyOverride(type::DrawTopology beginMethodTopology);
void FlushDeferredDraw(); void FlushDeferredDraw();
@ -268,6 +270,19 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
Register<0x54F, type::MultisampleControl> multisampleControl; Register<0x54F, type::MultisampleControl> multisampleControl;
struct RenderEnable {
enum class Mode : u32 {
False = 0,
True = 1,
Conditional = 2,
RenderIfEqual = 3,
RenderIfNotEqual = 4,
};
Address offset;
Mode mode;
};
Register<0x554, RenderEnable> renderEnable;
Register<0x557, TexSamplerPool> texSamplerPool; Register<0x557, TexSamplerPool> texSamplerPool;
Register<0x55B, float> slopeScaleDepthBias; Register<0x55B, float> slopeScaleDepthBias;
@ -375,6 +390,19 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
Register<0x64B, u32> viewportScaleOffsetEnable; Register<0x64B, u32> viewportScaleOffsetEnable;
Register<0x64F, type::ViewportClipControl> viewportClipControl; Register<0x64F, type::ViewportClipControl> viewportClipControl;
struct RenderEnableOverride {
enum class Mode : u8 {
UseRenderEnable = 0,
AlwaysRender = 1,
NeverRender = 2,
};
Mode mode : 2;
u32 _pad_ : 30;
};
Register<0x651, RenderEnableOverride> renderEnableOverride;
Register<0x652, type::PrimitiveTopologyControl> primitiveTopologyControl; Register<0x652, type::PrimitiveTopologyControl> primitiveTopologyControl;
Register<0x65C, type::PrimitiveTopology> primitiveTopology; Register<0x65C, type::PrimitiveTopology> primitiveTopology;