From 0a5f78c7276d7141f26a6b870943986100354128 Mon Sep 17 00:00:00 2001 From: nmzik Date: Tue, 21 Jul 2026 07:20:55 +0200 Subject: [PATCH] graphics: refactoring #2 --- .../command_processor/commandProcessor.h | 62 +- .../guest_gpu/command_processor/pm4Dispatch.h | 248 +- .../command_processor/pm4Handlers.cpp | 866 +++--- src/graphics/guest_gpu/graphicsRun.cpp | 65 +- src/graphics/guest_gpu/tile.cpp | 192 +- src/graphics/guest_gpu/tile.h | 24 +- src/graphics/host_gpu/gpuTiler.cpp | 229 +- src/graphics/host_gpu/gpuTiler.h | 8 +- src/graphics/host_gpu/graphicContext.h | 17 + src/graphics/host_gpu/hostMemory.cpp | 15 +- src/graphics/host_gpu/hostMemory.h | 4 +- src/graphics/host_gpu/objects/label.cpp | 91 +- src/graphics/host_gpu/objects/label.h | 7 +- .../host_gpu/objects/textureCommon.cpp | 153 +- src/graphics/host_gpu/objects/textureCommon.h | 12 +- .../host_gpu/renderer/bufferCache.cpp | 253 +- src/graphics/host_gpu/renderer/bufferCache.h | 30 +- .../host_gpu/renderer/colorRenderTarget.cpp | 103 +- .../host_gpu/renderer/colorRenderTarget.h | 10 +- src/graphics/host_gpu/renderer/context.cpp | 136 +- src/graphics/host_gpu/renderer/debug.cpp | 22 +- src/graphics/host_gpu/renderer/debug.h | 8 +- .../host_gpu/renderer/depthRenderTarget.cpp | 166 +- .../host_gpu/renderer/depthRenderTarget.h | 22 +- .../host_gpu/renderer/descriptorCache.cpp | 48 +- .../host_gpu/renderer/descriptorCache.h | 16 +- .../host_gpu/renderer/descriptors.cpp | 239 +- .../host_gpu/renderer/dummyTextureCache.cpp | 37 +- .../host_gpu/renderer/dummyTextureCache.h | 4 +- .../host_gpu/renderer/framebufferCache.cpp | 126 +- .../host_gpu/renderer/framebufferCache.h | 11 +- src/graphics/host_gpu/renderer/gdsBuffer.cpp | 29 +- src/graphics/host_gpu/renderer/gdsBuffer.h | 13 +- .../host_gpu/renderer/gpuResourceManager.cpp | 25 +- .../host_gpu/renderer/gpuResourceManager.h | 10 +- src/graphics/host_gpu/renderer/image.cpp | 174 +- src/graphics/host_gpu/renderer/image.h | 27 +- src/graphics/host_gpu/renderer/imageInfo.h | 143 +- src/graphics/host_gpu/renderer/imageView.cpp | 295 +-- src/graphics/host_gpu/renderer/imageView.h | 10 +- .../host_gpu/renderer/pipelineCache.cpp | 91 +- .../host_gpu/renderer/pipelineCache.h | 51 +- src/graphics/host_gpu/renderer/render.h | 54 +- .../host_gpu/renderer/renderCompute.cpp | 121 +- .../host_gpu/renderer/renderContext.cpp | 38 +- .../host_gpu/renderer/renderContext.h | 27 +- src/graphics/host_gpu/renderer/renderDraw.cpp | 487 ++-- .../renderer/renderTargetBarriers.cpp | 111 +- .../host_gpu/renderer/renderTargetBarriers.h | 8 +- .../host_gpu/renderer/samplerCache.cpp | 3 +- src/graphics/host_gpu/renderer/samplerCache.h | 7 +- .../host_gpu/renderer/shaderSubgroup.cpp | 26 +- .../host_gpu/renderer/shaderSubgroup.h | 17 +- src/graphics/host_gpu/renderer/shaders.cpp | 473 ++-- .../host_gpu/renderer/streamBuffer.cpp | 37 +- src/graphics/host_gpu/renderer/streamBuffer.h | 10 +- src/graphics/host_gpu/renderer/sync.cpp | 101 +- src/graphics/host_gpu/renderer/sync.h | 34 +- .../host_gpu/renderer/textureCache.cpp | 608 ++--- src/graphics/host_gpu/renderer/textureCache.h | 115 +- src/graphics/host_gpu/renderer/tiler.cpp | 57 +- src/graphics/host_gpu/renderer/tiler.h | 14 +- src/graphics/host_gpu/transfer.cpp | 483 ++-- src/graphics/host_gpu/transfer.h | 68 +- src/graphics/host_gpu/vma.cpp | 147 +- src/graphics/host_gpu/vma.h | 21 +- src/graphics/presentation/displayBuffer.h | 6 +- src/graphics/presentation/videoOut.cpp | 167 +- src/graphics/presentation/window.h | 8 +- .../presentation/window/swapchain.cpp | 163 +- .../presentation/window/vulkanWindow.cpp | 241 +- src/graphics/presentation/window/window.cpp | 352 ++- .../presentation/window/windowInternal.h | 6 +- src/graphics/rt/hardware.cpp | 25 +- src/graphics/rt/hardware.h | 14 +- .../shader/recompiler/BindingLayout.cpp | 87 +- .../shader/recompiler/BindingLayout.h | 2 +- src/graphics/shader/recompiler/ExportOps.cpp | 40 +- src/graphics/shader/recompiler/ExportOps.h | 2 +- src/graphics/shader/recompiler/ImageOps.cpp | 46 +- src/graphics/shader/recompiler/ImageOps.h | 2 +- src/graphics/shader/recompiler/MemoryOps.cpp | 228 +- src/graphics/shader/recompiler/MemoryOps.h | 10 +- .../recompiler/ResourceMaterialization.cpp | 39 +- .../recompiler/ResourceMaterialization.h | 4 +- .../shader/recompiler/ResourceTracking.cpp | 108 +- .../shader/recompiler/ResourceTracking.h | 2 +- .../shader/recompiler/ScalarAluOps.cpp | 162 +- src/graphics/shader/recompiler/ScalarAluOps.h | 10 +- .../shader/recompiler/ScalarProvenance.cpp | 217 +- .../shader/recompiler/ScalarProvenance.h | 2 +- src/graphics/shader/recompiler/ShaderCFG.cpp | 508 ++-- src/graphics/shader/recompiler/ShaderCFG.h | 4 +- .../shader/recompiler/ShaderDecoder.cpp | 188 +- .../shader/recompiler/ShaderDecoder.h | 14 +- src/graphics/shader/recompiler/ShaderIR.h | 2 +- .../recompiler/ShaderInfoCollection.cpp | 48 +- .../shader/recompiler/ShaderInfoCollection.h | 2 +- .../shader/recompiler/ShaderRecompiler.cpp | 61 +- .../shader/recompiler/ShaderRecompiler.h | 2 +- .../shader/recompiler/SpirvBuilder.cpp | 52 +- src/graphics/shader/recompiler/SpirvBuilder.h | 6 +- .../shader/recompiler/SpirvEmitter.cpp | 42 +- src/graphics/shader/recompiler/SpirvEmitter.h | 6 +- src/graphics/shader/recompiler/SrtPatcher.cpp | 61 +- src/graphics/shader/recompiler/SrtPatcher.h | 2 +- src/graphics/shader/recompiler/SrtWalker.cpp | 224 +- src/graphics/shader/recompiler/SrtWalker.h | 18 +- .../shader/recompiler/VectorAluOps.cpp | 562 ++-- src/graphics/shader/recompiler/VectorAluOps.h | 12 +- .../shader/recompiler/shaderIR/ShaderIR.cpp | 436 ++- .../recompiler/shaderIR/ShaderIRInternal.h | 12 +- .../recompiler/shaderIR/ShaderIRMemory.cpp | 176 +- .../spirvEmitter/spirvEmitterAluOps.cpp | 2343 ++++++++--------- .../spirvEmitter/spirvEmitterAnalysis.cpp | 92 +- .../spirvEmitter/spirvEmitterControlFlow.cpp | 424 +-- .../spirvEmitter/spirvEmitterExport.cpp | 118 +- .../spirvEmitter/spirvEmitterFlowOps.cpp | 316 +-- .../spirvEmitter/spirvEmitterImageHelpers.cpp | 172 +- .../spirvEmitter/spirvEmitterImageOps.cpp | 221 +- .../spirvEmitter/spirvEmitterInternal.h | 817 +++--- .../spirvEmitter/spirvEmitterMemory.cpp | 998 +++---- .../spirvEmitter/spirvEmitterModule.cpp | 1050 ++++---- .../spirvEmitter/spirvEmitterValues.cpp | 664 ++--- src/graphics/shader/shader.cpp | 605 ++--- src/graphics/shader/shader.h | 48 +- src/graphics/shader/shaderStageRuntime.cpp | 13 +- src/graphics/shader/shaderVertexMetadata.cpp | 9 +- src/graphics/shader/shaderVertexMetadata.h | 2 +- src/kernel/memory.cpp | 6 +- src/loader/runtimeLinker.cpp | 4 +- tests/ResourceTrackingTests.cpp | 352 +-- tests/ScalarProvenanceTests.cpp | 112 +- tests/ShaderRecompilerComputeTests.cpp | 887 +++---- tests/ShaderStageRuntimeTests.cpp | 4 +- tests/ShaderVertexMetadataTests.cpp | 4 +- tests/shaderCfgTests.cpp | 322 +-- 137 files changed, 10230 insertions(+), 10893 deletions(-) diff --git a/src/graphics/guest_gpu/command_processor/commandProcessor.h b/src/graphics/guest_gpu/command_processor/commandProcessor.h index c85894ab3..afcfa4856 100644 --- a/src/graphics/guest_gpu/command_processor/commandProcessor.h +++ b/src/graphics/guest_gpu/command_processor/commandProcessor.h @@ -20,15 +20,18 @@ class CommandScheduler { public: static constexpr int BuffersNum = 8; + CommandScheduler(HW::Context& registers, HW::UserConfig& user_config, HW::Shader& shaders) + : m_registers(registers), m_user_config(user_config), m_shaders(shaders) {} + void SetQueue(int queue) { m_queue = queue; } int Queue() const { return m_queue; } bool Active() const { return m_current >= 0 && m_current < BuffersNum; } void CheckActive() const { EXIT_IF(!Active()); } - CommandBuffer* Current() const { + RenderCommandBuffer& Current() const { CheckActive(); EXIT_IF(m_buffers[m_current] == nullptr); - return m_buffers[m_current]; + return *m_buffers[m_current]; } void Init() { @@ -37,10 +40,10 @@ public: } for (auto& buf: m_buffers) { EXIT_IF(buf != nullptr); - buf = new CommandBuffer(m_queue); + buf = new RenderCommandBuffer(m_queue, m_registers, m_user_config, m_shaders); } m_current = 0; - Current()->Begin(); + Current().Begin(); } void Flush() { @@ -48,18 +51,17 @@ public: BeginNext(); } - CommandBuffer* FlushAndGetSubmitted() { - auto* submitted = SubmitCurrent(); + CommandBuffer& FlushAndGetSubmitted() { + auto& submitted = SubmitCurrent(); BeginNext(); return submitted; } - void CopyBuffers(std::array* out) const { - EXIT_IF(out == nullptr); + void CopyBuffers(std::array& out) const { for (int i = 0; i < BuffersNum; i++) { auto* buf = m_buffers[i]; EXIT_IF(buf == nullptr); - (*out)[i] = buf; + out[i] = buf; } } @@ -81,27 +83,30 @@ public: if (!Active()) { return; } - Current()->WaitForFenceAndReset(); - Current()->Begin(); + Current().WaitForFenceAndReset(); + Current().Begin(); } private: - CommandBuffer* SubmitCurrent() { - auto* submitted = Current(); - submitted->End(); - submitted->Execute(); + CommandBuffer& SubmitCurrent() { + auto& submitted = Current(); + submitted.End(); + submitted.Execute(); return submitted; } void BeginNext() { m_current = (m_current + 1) % BuffersNum; - Current()->WaitForFenceAndReset(); - Current()->Begin(); + Current().WaitForFenceAndReset(); + Current().Begin(); } - CommandBuffer* m_buffers[BuffersNum] = {}; - int m_current = -1; - int m_queue = -1; + RenderCommandBuffer* m_buffers[BuffersNum] = {}; + int m_current = -1; + int m_queue = -1; + HW::Context& m_registers; + HW::UserConfig& m_user_config; + HW::Shader& m_shaders; }; class CommandProcessor { @@ -113,7 +118,7 @@ public: int64_t flip_arg = 0; }; - CommandProcessor() = default; + CommandProcessor(): m_scheduler(m_ctx, m_ucfg, m_sh_ctx) {} ~CommandProcessor() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(CommandProcessor); @@ -145,9 +150,9 @@ public: void RunLock() { m_run_mutex.Lock(); } void RunUnlock() { m_run_mutex.Unlock(); } - HW::Context* GetCtx() { return &m_ctx; } - HW::UserConfig* GetUcfg() { return &m_ucfg; } - HW::Shader* GetShCtx() { return &m_sh_ctx; } + HW::Context& GetCtx() { return m_ctx; } + HW::UserConfig& GetUcfg() { return m_ucfg; } + HW::Shader& GetShCtx() { return m_sh_ctx; } void SetIndexType(uint32_t index_type_and_size); void SetIndexBaseAddress(uint64_t index_base_addr); @@ -244,12 +249,9 @@ private: uint32_t interrupt_context_id); void FinishCommandProcessors(); - CommandBuffer* CurrentBuffer() { return m_scheduler.Current(); } - void CheckBuffer() const { m_scheduler.CheckActive(); } - GpuResourceManager* GetGpuResources() const { - EXIT_IF(g_render_ctx == nullptr); - return g_render_ctx->GetGpuResources(); - } + RenderCommandBuffer& CurrentBuffer() { return m_scheduler.Current(); } + void CheckBuffer() const { m_scheduler.CheckActive(); } + GpuResourceManager& GetGpuResources() const { return GetRenderContext().GetGpuResources(); } HW::Context m_ctx; HW::UserConfig m_ucfg; diff --git a/src/graphics/guest_gpu/command_processor/pm4Dispatch.h b/src/graphics/guest_gpu/command_processor/pm4Dispatch.h index e601a34fa..fb398bbfd 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Dispatch.h +++ b/src/graphics/guest_gpu/command_processor/pm4Dispatch.h @@ -10,17 +10,17 @@ namespace Libs::Graphics { class CommandProcessor; -using hw_ctx_parser_func_t = uint32_t (*)(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +using hw_ctx_parser_func_t = uint32_t (*)(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -using hw_uc_parser_func_t = uint32_t (*)(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +using hw_uc_parser_func_t = uint32_t (*)(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -using hw_sh_parser_func_t = uint32_t (*)(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +using hw_sh_parser_func_t = uint32_t (*)(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -using cp_op_parser_func_t = uint32_t (*)(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, +using cp_op_parser_func_t = uint32_t (*)(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); -using hw_ctx_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t); -using hw_uc_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t); -using hw_sh_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t); +using hw_ctx_indirect_func_t = void (*)(CommandProcessor&, uint32_t, uint32_t); +using hw_uc_indirect_func_t = void (*)(CommandProcessor&, uint32_t, uint32_t); +using hw_sh_indirect_func_t = void (*)(CommandProcessor&, uint32_t, uint32_t); extern const std::array g_hw_ctx_func; extern hw_ctx_indirect_func_t g_hw_ctx_indirect_func[Pm4::CX_NUM]; @@ -36,136 +36,136 @@ void GraphicsInitJmpTablesCxIndirect(); void GraphicsInitJmpTablesShIndirect(); void GraphicsInitJmpTablesUcIndirect(); -uint32_t HwCtxSetRenderControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetDepthMetadataRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetRenderControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetDepthMetadataRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetBorderColorTableAddr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetBorderColorTableAddr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetStencilClear(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetDepthClear(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetScreenScissor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetDepthRenderTarget(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetStencilClear(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetDepthClear(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetScreenScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetDepthRenderTarget(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetStencilInfo(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetDepthHtileSurface(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetStencilInfo(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetDepthHtileSurface(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetHardwareScreenOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetHardwareScreenOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetWindowOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetWindowScissor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetClipRect(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetRenderTargetMask(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetGenericScissor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetBlendColor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetCbDccControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetStencilControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetStencilMask(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetPsInput(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetSpiTmpringSize(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetDepthControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetEqaaControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetColorControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetDepthBounds(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetPointState(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetClipControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetModeControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetPolyOffsetRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetWindowOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetWindowScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetClipRect(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetRenderTargetMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetGenericScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetBlendColor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetCbDccControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetStencilControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetStencilMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetPsInput(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetSpiTmpringSize(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetDepthControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetEqaaControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetColorControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetDepthBounds(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetPointState(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetClipControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetModeControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetPolyOffsetRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetViewportTransformControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetViewportTransformControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetLineControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetFovWindow(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetScanModeControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetScanModeControl1(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetAaConfig(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetAaSampleControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetCentroidPriority(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetAaMask(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetVtxControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetPaScExtendedControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetLineControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetFovWindow(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetScanModeControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetScanModeControl1(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetAaConfig(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetAaSampleControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetCentroidPriority(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetAaMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetVtxControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetPaScExtendedControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetAlphaToMask(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetDrawPayloadControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetAlphaToMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetDrawPayloadControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetPrimitiveIdReset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetObjprimIdControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetShaderStages(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetGuardBands(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetRenderTarget(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetColorInfo(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetBlendControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetViewportScissor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetViewportZ(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwCtxSetViewportScaleOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwCtxSetPrimitiveIdReset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetObjprimIdControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetShaderStages(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetGuardBands(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetRenderTarget(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetColorInfo(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetBlendControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetViewportScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetViewportZ(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwCtxSetViewportScaleOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetPsUserSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetGsUserSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetHsUserSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetCsUserSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetPsUserAccumSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetGsUserAccumSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetHsUserAccumSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetCsUserAccumSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShSetCsRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwShIgnoreRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetPrimitiveType(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetIndexType(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetObjectId(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetTextureGradientFactors(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwShSetPsUserSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShSetGsUserSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShSetHsUserSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShSetCsUserSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShSetPsUserAccumSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShSetGsUserAccumSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShSetHsUserAccumSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShSetCsUserAccumSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShSetCsRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwShIgnoreRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwUcSetPrimitiveType(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwUcSetIndexType(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwUcSetObjectId(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwUcSetTextureGradientFactors(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetIaMultiVgtParam(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetMultiPrimIbReset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetBorderColorTableAddr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, +uint32_t HwUcSetIaMultiVgtParam(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwUcSetMultiPrimIbReset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwUcSetBorderColorTableAddr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetGeIndexOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t HwUcSetGdsOaRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwUcSetGeIndexOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); +uint32_t HwUcSetGdsOaRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t); -uint32_t CpOpNop(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpSetBase(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpClearState(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIndexBase(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIndexBufferSize(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDispatchDirect(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDispatchIndirect(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDrawIndirect(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDrawIndirectMulti(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDrawIndex(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDrawIndexOffset(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpPfpSyncMe(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIndexType(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpNumInstances(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDrawIndexAuto(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpCondExec(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpSetPredication(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpWriteData(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIndirectBuffer(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpCopyData(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpEventWrite(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpEventWriteEop(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpEventWriteEos(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDmaData(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpAcquireMem(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpSetContextReg(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpSetShaderReg(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpSetUconfigReg(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIndirectCxRegs(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIndirectShRegs(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIndirectUcRegs(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpWriteConstRam(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDumpConstRam(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIncrementCeCounter(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpIncrementDeCounter(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpWaitOnCeCounter(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpWaitOnDeCounterDiff(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpGetLodStats(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpDispatchReset(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpWaitRegMem32(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpWaitFlipDone(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpPushMarker(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpPopMarker(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpWaitRegMem64(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpFlip(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); -uint32_t CpOpReleaseMem(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpNop(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpSetBase(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpClearState(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIndexBase(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIndexBufferSize(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDispatchDirect(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDispatchIndirect(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDrawIndirect(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDrawIndirectMulti(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDrawIndex(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDrawIndexOffset(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpPfpSyncMe(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIndexType(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpNumInstances(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDrawIndexAuto(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpCondExec(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpSetPredication(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpWriteData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIndirectBuffer(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpCopyData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpEventWrite(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpEventWriteEop(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpEventWriteEos(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDmaData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpAcquireMem(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpSetContextReg(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpSetShaderReg(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpSetUconfigReg(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIndirectCxRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIndirectShRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIndirectUcRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpWriteConstRam(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDumpConstRam(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIncrementCeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpIncrementDeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpWaitOnCeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpWaitOnDeCounterDiff(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpGetLodStats(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpDispatchReset(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpWaitRegMem32(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpWaitFlipDone(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpPushMarker(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpPopMarker(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpWaitRegMem64(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpFlip(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); +uint32_t CpOpReleaseMem(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t); } // namespace Libs::Graphics diff --git a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp index 8af12d856..46a7ff16d 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp @@ -23,13 +23,13 @@ #include #define KYTY_HW_CTX_PARSER_ARGS \ - [[maybe_unused]] CommandProcessor *cp, uint32_t cmd_id, [[maybe_unused]] uint32_t cmd_offset, \ + [[maybe_unused]] CommandProcessor &cp, uint32_t cmd_id, [[maybe_unused]] uint32_t cmd_offset, \ const uint32_t *buffer, [[maybe_unused]] uint32_t dw #define KYTY_HW_UC_PARSER_ARGS \ - [[maybe_unused]] CommandProcessor *cp, uint32_t cmd_id, [[maybe_unused]] uint32_t cmd_offset, \ + [[maybe_unused]] CommandProcessor &cp, uint32_t cmd_id, [[maybe_unused]] uint32_t cmd_offset, \ const uint32_t *buffer, [[maybe_unused]] uint32_t dw #define KYTY_HW_SH_PARSER_ARGS \ - [[maybe_unused]] CommandProcessor *cp, uint32_t cmd_id, [[maybe_unused]] uint32_t cmd_offset, \ + [[maybe_unused]] CommandProcessor &cp, uint32_t cmd_id, [[maybe_unused]] uint32_t cmd_offset, \ const uint32_t *buffer, [[maybe_unused]] uint32_t dw #define KYTY_HW_CTX_PARSER(f) uint32_t f(KYTY_HW_CTX_PARSER_ARGS) @@ -37,14 +37,14 @@ #define KYTY_HW_SH_PARSER(f) uint32_t f(KYTY_HW_SH_PARSER_ARGS) #define KYTY_HW_CTX_INDIRECT_ARGS \ - CommandProcessor *cp, [[maybe_unused]] uint32_t cmd_offset, uint32_t value + CommandProcessor &cp, [[maybe_unused]] uint32_t cmd_offset, uint32_t value #define KYTY_HW_UC_INDIRECT_ARGS \ - CommandProcessor *cp, [[maybe_unused]] uint32_t cmd_offset, uint32_t value + CommandProcessor &cp, [[maybe_unused]] uint32_t cmd_offset, uint32_t value #define KYTY_HW_SH_INDIRECT_ARGS \ - CommandProcessor *cp, [[maybe_unused]] uint32_t cmd_offset, uint32_t value + CommandProcessor &cp, [[maybe_unused]] uint32_t cmd_offset, uint32_t value #define KYTY_CP_OP_PARSER_ARGS \ - [[maybe_unused]] CommandProcessor *cp, [[maybe_unused]] uint32_t cmd_id, \ + [[maybe_unused]] CommandProcessor &cp, [[maybe_unused]] uint32_t cmd_id, \ [[maybe_unused]] const uint32_t *buffer, [[maybe_unused]] uint32_t dw, \ [[maybe_unused]] uint32_t num_dw #define KYTY_CP_OP_PARSER(f) uint32_t f(KYTY_CP_OP_PARSER_ARGS) @@ -104,7 +104,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetAaConfig) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0016900); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::PA_SC_AA_CONFIG); - cp->GetCtx()->SetAaConfig(ParseAaConfig(buffer[0])); + cp.GetCtx().SetAaConfig(ParseAaConfig(buffer[0])); return 1; } @@ -112,9 +112,9 @@ KYTY_HW_CTX_PARSER(HwCtxSetAaConfig) { KYTY_HW_CTX_PARSER(HwCtxSetAaSampleControl) { if (cmd_id == 0xc0016900 && cmd_offset >= Pm4::PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 && cmd_offset < Pm4::PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 + 16) { - auto r = cp->GetCtx()->GetAaSampleControl(); + auto r = cp.GetCtx().GetAaSampleControl(); r.locations[cmd_offset - Pm4::PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0] = buffer[0]; - cp->GetCtx()->SetAaSampleControl(r); + cp.GetCtx().SetAaSampleControl(r); return 1; } @@ -133,7 +133,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetAaSampleControl) { r.centroid_priority = static_cast(buffer[18]) | (static_cast(buffer[19]) << 32u); - cp->GetCtx()->SetAaSampleControl(r); + cp.GetCtx().SetAaSampleControl(r); } else { KYTY_NOT_IMPLEMENTED; } @@ -143,7 +143,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetAaSampleControl) { KYTY_HW_CTX_PARSER(HwCtxSetCentroidPriority) { auto num_values = KYTY_PM4_LEN(cmd_id) - 2u; - auto r = cp->GetCtx()->GetAaSampleControl(); + auto r = cp.GetCtx().GetAaSampleControl(); for (uint32_t i = 0; i < num_values; i++) { auto offset = cmd_offset + i; @@ -159,7 +159,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetCentroidPriority) { } } - cp->GetCtx()->SetAaSampleControl(r); + cp.GetCtx().SetAaSampleControl(r); return num_values; } @@ -177,14 +177,13 @@ static void HwCtxIgnorePrimitiveIdReset([[maybe_unused]] uint32_t value) {} static void HwCtxIgnoreVtxControl([[maybe_unused]] uint32_t value) {} -static void HwCtxSetDepthBoundsRegister(HW::Context* ctx, uint32_t cmd_offset, uint32_t value) { - EXIT_IF(ctx == nullptr); - - auto fvalue = *reinterpret_cast(&value); +static void HwCtxSetDepthBoundsRegister(CommandProcessor& cp, uint32_t cmd_offset, uint32_t value) { + auto& ctx = cp.GetCtx(); + auto fvalue = *reinterpret_cast(&value); switch (cmd_offset) { - case Pm4::DB_DEPTH_BOUNDS_MIN: ctx->SetDepthBoundsMin(fvalue); break; - case Pm4::DB_DEPTH_BOUNDS_MAX: ctx->SetDepthBoundsMax(fvalue); break; + case Pm4::DB_DEPTH_BOUNDS_MIN: ctx.SetDepthBoundsMin(fvalue); break; + case Pm4::DB_DEPTH_BOUNDS_MAX: ctx.SetDepthBoundsMax(fvalue); break; default: EXIT("unknown depth bounds register: 0x%08" PRIx32 "\n", cmd_offset); } } @@ -255,7 +254,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthBounds) { auto num_values = KYTY_PM4_LEN(cmd_id) - 2u; for (uint32_t i = 0; i < num_values; i++) { - HwCtxSetDepthBoundsRegister(cp->GetCtx(), cmd_offset + i, buffer[i]); + HwCtxSetDepthBoundsRegister(cp, cmd_offset + i, buffer[i]); } return num_values; @@ -402,7 +401,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetBlendColor) { r.blue = *reinterpret_cast(&buffer[2]); r.alpha = *reinterpret_cast(&buffer[3]); - cp->GetCtx()->SetBlendColor(r); + cp.GetCtx().SetBlendColor(r); return 4; } @@ -431,7 +430,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetBlendControl) { r.enable = ((buffer[0] >> Pm4::CB_BLEND0_CONTROL_ENABLE_SHIFT) & Pm4::CB_BLEND0_CONTROL_ENABLE_MASK) != 0; - cp->GetCtx()->SetBlendControl(param, r); + cp.GetCtx().SetBlendControl(param, r); return 1; } @@ -471,7 +470,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetClipControl) { r.force_viewport_index_from_vs_enable = KYTY_PM4_GET(buffer[0], PA_CL_CLIP_CNTL, VTE_VPORT_PROVOKE_DISABLE) != 0; - cp->GetCtx()->SetClipControl(r); + cp.GetCtx().SetClipControl(r); return 1; } @@ -485,7 +484,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetColorControl) { r.mode = KYTY_PM4_GET(buffer[0], CB_COLOR_CONTROL, MODE); r.op = KYTY_PM4_GET(buffer[0], CB_COLOR_CONTROL, ROP3); - cp->GetCtx()->SetColorControl(r); + cp.GetCtx().SetColorControl(r); return 1; } @@ -525,7 +524,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetColorInfo) { r.cmask_addr_type = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, CMASK_ADDR_TYPE); r.alt_tile_mode = KYTY_PM4_GET(buffer[0], CB_COLOR0_INFO, ALT_TILE_MODE) != 0; - cp->GetCtx()->SetColorInfo(param, r); + cp.GetCtx().SetColorInfo(param, r); return 1; } @@ -534,7 +533,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthClear) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_DEPTH_CLEAR); - cp->GetCtx()->SetDepthClearValue(*reinterpret_cast(buffer)); + cp.GetCtx().SetDepthClearValue(*reinterpret_cast(buffer)); return 1; } @@ -558,7 +557,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthControl) { r.color_writes_on_depth_pass_disable = KYTY_PM4_GET(buffer[0], DB_DEPTH_CONTROL, DISABLE_COLOR_WRITES_ON_DEPTH_PASS) != 0; - cp->GetCtx()->SetDepthControl(r); + cp.GetCtx().SetDepthControl(r); return 1; } @@ -575,12 +574,11 @@ static HW::DepthRenderTargetHTileSurface ParseDepthHtileSurface(uint32_t value) return r; } -static void HwCtxSetDepthHtileSurfaceRegister(HW::Context* ctx, uint32_t value) { - EXIT_IF(ctx == nullptr); - - auto target = ctx->GetDepthRenderTarget(); +static void HwCtxSetDepthHtileSurfaceRegister(CommandProcessor& cp, uint32_t value) { + auto& ctx = cp.GetCtx(); + auto target = ctx.GetDepthRenderTarget(); target.htile_surface = ParseDepthHtileSurface(value); - ctx->SetDepthRenderTarget(target); + ctx.SetDepthRenderTarget(target); } KYTY_HW_CTX_PARSER(HwCtxSetDepthHtileSurface) { @@ -589,7 +587,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthHtileSurface) { EXIT_NOT_IMPLEMENTED(num_values != 1); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_HTILE_SURFACE); - HwCtxSetDepthHtileSurfaceRegister(cp->GetCtx(), buffer[0]); + HwCtxSetDepthHtileSurfaceRegister(cp, buffer[0]); return num_values; } @@ -623,7 +621,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthRenderTarget) { r.tile_surface_enable = KYTY_PM4_GET(buffer[0], DB_Z_INFO, TILE_SURFACE_ENABLE) != 0; r.zrange_precision = KYTY_PM4_GET(buffer[0], DB_Z_INFO, ZRANGE_PRECISION); - cp->GetCtx()->SetDepthZInfo(r); + cp.GetCtx().SetDepthZInfo(r); } else if (cmd_id == 0xC0086900) { if (dw >= 22 && buffer[8] == 0xC0016900 && buffer[9] == Pm4::DB_DEPTH_INFO && buffer[11] == 0xC0016900 && buffer[12] == Pm4::DB_DEPTH_VIEW && @@ -737,7 +735,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthRenderTarget) { z.width_height_valid = true; } - cp->GetCtx()->SetDepthRenderTarget(z); + cp.GetCtx().SetDepthRenderTarget(z); } else { KYTY_NOT_IMPLEMENTED; } @@ -767,7 +765,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetEqaaControl) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_EQAA); - cp->GetCtx()->SetEqaaControl(ParseEqaaControl(buffer[0])); + cp.GetCtx().SetEqaaControl(ParseEqaaControl(buffer[0])); return 1; } @@ -805,22 +803,21 @@ KYTY_HW_CTX_PARSER(HwCtxSetViewportScissor) { const int left = ParseScissorCoord15(value); const int top = ParseScissorCoord15(value >> 16u); const bool window_offset_disable = (value & 0x80000000u) != 0; - cp->GetCtx()->SetViewportScissorTL(viewport, left, top, !window_offset_disable); + cp.GetCtx().SetViewportScissorTL(viewport, left, top, !window_offset_disable); } else { const int right = ParseScissorCoord15(value); const int bottom = ParseScissorCoord15(value >> 16u); - cp->GetCtx()->SetViewportScissorBR(viewport, right, bottom); + cp.GetCtx().SetViewportScissorBR(viewport, right, bottom); } } return reg_num; } -static void HwCtxSetClipRectRegister(HW::Context* ctx, uint32_t cmd_offset, uint32_t value) { - EXIT_IF(ctx == nullptr); - +static void HwCtxSetClipRectRegister(CommandProcessor& cp, uint32_t cmd_offset, uint32_t value) { + auto& ctx = cp.GetCtx(); if (cmd_offset == Pm4::PA_SC_CLIPRECT_RULE) { - ctx->SetClipRectRule(static_cast(value & 0xffffu)); + ctx.SetClipRectRule(static_cast(value & 0xffffu)); return; } @@ -830,11 +827,11 @@ static void HwCtxSetClipRectRegister(HW::Context* ctx, uint32_t cmd_offset, uint const int left = ParseScissorCoord15(value); const int top = ParseScissorCoord15(value >> 16u); const bool window_offset_disable = (value & 0x80000000u) != 0; - ctx->SetClipRectTL(rect_id, left, top, !window_offset_disable); + ctx.SetClipRectTL(rect_id, left, top, !window_offset_disable); } else { const int right = ParseScissorCoord15(value); const int bottom = ParseScissorCoord15(value >> 16u); - ctx->SetClipRectBR(rect_id, right, bottom); + ctx.SetClipRectBR(rect_id, right, bottom); } return; } @@ -849,7 +846,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetClipRect) { EXIT_NOT_IMPLEMENTED(cmd_offset + value_count > Pm4::PA_SC_CLIPRECT_0_TL + 8u); for (uint32_t i = 0; i < value_count; i++) { - HwCtxSetClipRectRegister(cp->GetCtx(), cmd_offset + i, buffer[i]); + HwCtxSetClipRectRegister(cp, cmd_offset + i, buffer[i]); } return value_count; @@ -864,7 +861,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetGuardBands) { auto horz_clip = *reinterpret_cast(&buffer[2]); // PA_CL_GB_HORZ_CLIP_ADJ auto horz_discard = *reinterpret_cast(&buffer[3]); // PA_CL_GB_HORZ_DISC_ADJ - cp->GetCtx()->SetGuardBands(horz_clip, vert_clip, horz_discard, vert_discard); + cp.GetCtx().SetGuardBands(horz_clip, vert_clip, horz_discard, vert_discard); return 4; } @@ -879,7 +876,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetHardwareScreenOffset) { uint32_t x = KYTY_PM4_GET(buffer[0], PA_SU_HARDWARE_SCREEN_OFFSET, HW_SCREEN_OFFSET_X); uint32_t y = KYTY_PM4_GET(buffer[0], PA_SU_HARDWARE_SCREEN_OFFSET, HW_SCREEN_OFFSET_Y); - cp->GetCtx()->SetHardwareScreenOffset(x, y); + cp.GetCtx().SetHardwareScreenOffset(x, y); return 1; } @@ -893,7 +890,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetWindowOffset) { int offset_y = static_cast( static_cast(KYTY_PM4_GET(buffer[0], PA_SC_WINDOW_OFFSET, WINDOW_Y))); - cp->GetCtx()->SetWindowOffset(offset_x, offset_y); + cp.GetCtx().SetWindowOffset(offset_x, offset_y); return 1; } @@ -918,9 +915,9 @@ KYTY_HW_CTX_PARSER(HwCtxSetLineControl) { auto line_width = KYTY_PM4_GET(buffer[0], PA_SU_LINE_CNTL, WIDTH); if (line_width == 8) { - cp->GetCtx()->SetLineWidth(1.0f); + cp.GetCtx().SetLineWidth(1.0f); } else { - cp->GetCtx()->SetLineWidth(static_cast(line_width) / 8.0f); + cp.GetCtx().SetLineWidth(static_cast(line_width) / 8.0f); } return 1; @@ -947,7 +944,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetModeControl) { r.provoking_vtx_last = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, PROVOKING_VTX_LAST) != 0; r.persp_corr_dis = KYTY_PM4_GET(buffer[0], PA_SU_SC_MODE_CNTL, PERSP_CORR_DIS) != 0; - cp->GetCtx()->SetModeControl(r); + cp.GetCtx().SetModeControl(r); return 1; } @@ -983,7 +980,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetPsInput) { EXIT_NOT_IMPLEMENTED(count > 32); for (uint32_t i = 0; i < count; i++) { - cp->GetCtx()->SetPsInputSettings(i, buffer[i]); + cp.GetCtx().SetPsInputSettings(i, buffer[i]); } return count; @@ -1004,7 +1001,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetRenderControl) { r.copy_centroid = KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, COPY_CENTROID) != 0; r.copy_sample = KYTY_PM4_GET(buffer[0], DB_RENDER_CONTROL, COPY_SAMPLE); - cp->GetCtx()->SetRenderControl(r); + cp.GetCtx().SetRenderControl(r); return 1; } @@ -1033,7 +1030,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetRenderTarget) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_BASE) / 15; - auto* ctx = cp->GetCtx(); + auto& ctx = cp.GetCtx(); HW::ColorBase base; HW::ColorPitch pitch; @@ -1131,38 +1128,38 @@ KYTY_HW_CTX_PARSER(HwCtxSetRenderTarget) { fmask.addr = static_cast(buffer[9]) << 8u; fmask_slice.slice_minus1 = buffer[10] & 0x3fffffu; - ctx->SetColorBase(slot, base); - ctx->SetColorPitch(slot, pitch); - ctx->SetColorSlice(slot, slice); - ctx->SetColorView(slot, view); - ctx->SetColorInfo(slot, info); - ctx->SetColorAttrib(slot, attrib); - ctx->SetColorDccControl(slot, dcc); - ctx->SetColorCmask(slot, cmask); - ctx->SetColorCmaskSlice(slot, cmask_slice); - ctx->SetColorFmask(slot, fmask); - ctx->SetColorFmaskSlice(slot, fmask_slice); + ctx.SetColorBase(slot, base); + ctx.SetColorPitch(slot, pitch); + ctx.SetColorSlice(slot, slice); + ctx.SetColorView(slot, view); + ctx.SetColorInfo(slot, info); + ctx.SetColorAttrib(slot, attrib); + ctx.SetColorDccControl(slot, dcc); + ctx.SetColorCmask(slot, cmask); + ctx.SetColorCmaskSlice(slot, cmask_slice); + ctx.SetColorFmask(slot, fmask); + ctx.SetColorFmaskSlice(slot, fmask_slice); if (count > 11) { HW::ColorClearWord0 clear_word0; clear_word0.word0 = buffer[11]; - ctx->SetColorClearWord0(slot, clear_word0); + ctx.SetColorClearWord0(slot, clear_word0); } if (count > 12) { HW::ColorClearWord1 clear_word1; clear_word1.word1 = buffer[12]; - ctx->SetColorClearWord1(slot, clear_word1); + ctx.SetColorClearWord1(slot, clear_word1); } if (count > 13) { HW::ColorDccAddr dcc_addr; dcc_addr.addr = static_cast(buffer[13]) << 8u; - ctx->SetColorDccAddr(slot, dcc_addr); + ctx.SetColorDccAddr(slot, dcc_addr); } if (dw >= count + 2 && buffer[count] == 0xC0001000) { @@ -1171,7 +1168,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetRenderTarget) { size.width = (buffer[count + 1] >> 0u) & 0xffffu; size.height = (buffer[count + 1] >> 16u) & 0xffffu; - ctx->SetColorSize(slot, size); + ctx.SetColorSize(slot, size); count += 2; } @@ -1183,7 +1180,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetRenderTargetMask) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::CB_TARGET_MASK); - cp->GetCtx()->SetRenderTargetMask(*buffer); + cp.GetCtx().SetRenderTargetMask(*buffer); return 1; } @@ -1198,7 +1195,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetScanModeControl) { r.vport_scissor_enable = KYTY_PM4_GET(buffer[0], PA_SC_MODE_CNTL_0, VPORT_SCISSOR_ENABLE) != 0; r.line_stipple_enable = KYTY_PM4_GET(buffer[0], PA_SC_MODE_CNTL_0, LINE_STIPPLE_ENABLE) != 0; - cp->GetCtx()->SetScanModeControl(r); + cp.GetCtx().SetScanModeControl(r); return 1; } @@ -1220,7 +1217,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetShaderStages) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::VGT_SHADER_STAGES_EN); - cp->GetCtx()->SetShaderStages(buffer[0]); + cp.GetCtx().SetShaderStages(buffer[0]); return 1; } @@ -1229,7 +1226,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetStencilClear) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_STENCIL_CLEAR); - cp->GetCtx()->SetStencilClearValue(KYTY_PM4_GET(buffer[0], DB_STENCIL_CLEAR, CLEAR)); + cp.GetCtx().SetStencilClearValue(KYTY_PM4_GET(buffer[0], DB_STENCIL_CLEAR, CLEAR)); return 1; } @@ -1247,7 +1244,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetStencilControl) { r.stencil_zpass_bf = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZPASS_BF); r.stencil_zfail_bf = KYTY_PM4_GET(buffer[0], DB_STENCIL_CONTROL, STENCILZFAIL_BF); - cp->GetCtx()->SetStencilControl(r); + cp.GetCtx().SetStencilControl(r); return 1; } @@ -1275,7 +1272,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetStencilInfo) { r.expclear_enabled = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, ALLOW_EXPCLEAR) != 0; r.tile_stencil_disable = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, TILE_STENCIL_DISABLE) != 0; - cp->GetCtx()->SetDepthStencilInfo(r); + cp.GetCtx().SetDepthStencilInfo(r); return 1; } @@ -1295,7 +1292,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetStencilMask) { r.stencil_writemask_bf = KYTY_PM4_GET(buffer[1], DB_STENCILREFMASK_BF, STENCILWRITEMASK_BF); r.stencil_opval_bf = KYTY_PM4_GET(buffer[1], DB_STENCILREFMASK_BF, STENCILOPVAL_BF); - cp->GetCtx()->SetStencilMask(r); + cp.GetCtx().SetStencilMask(r); return 2; } @@ -1314,12 +1311,12 @@ KYTY_HW_CTX_PARSER(HwCtxSetViewportScaleOffset) { EXIT_NOT_IMPLEMENTED(viewport >= 16); switch (field) { - case 0: cp->GetCtx()->SetViewportXScale(viewport, value); break; - case 1: cp->GetCtx()->SetViewportXOffset(viewport, value); break; - case 2: cp->GetCtx()->SetViewportYScale(viewport, value); break; - case 3: cp->GetCtx()->SetViewportYOffset(viewport, value); break; - case 4: cp->GetCtx()->SetViewportZScale(viewport, value); break; - case 5: cp->GetCtx()->SetViewportZOffset(viewport, value); break; + case 0: cp.GetCtx().SetViewportXScale(viewport, value); break; + case 1: cp.GetCtx().SetViewportXOffset(viewport, value); break; + case 2: cp.GetCtx().SetViewportYScale(viewport, value); break; + case 3: cp.GetCtx().SetViewportYOffset(viewport, value); break; + case 4: cp.GetCtx().SetViewportZScale(viewport, value); break; + case 5: cp.GetCtx().SetViewportZOffset(viewport, value); break; default: EXIT("invalid viewport scale/offset field\n"); } } @@ -1331,7 +1328,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetViewportTransformControl) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::PA_CL_VTE_CNTL); - cp->GetCtx()->SetViewportTransformControl(*buffer); + cp.GetCtx().SetViewportTransformControl(*buffer); return 1; } @@ -1349,9 +1346,9 @@ KYTY_HW_CTX_PARSER(HwCtxSetViewportZ) { EXIT_NOT_IMPLEMENTED(viewport >= 16); if (((reg - Pm4::PA_SC_VPORT_ZMIN_0) % 2u) == 0) { - cp->GetCtx()->SetViewportZMin(viewport, value); + cp.GetCtx().SetViewportZMin(viewport, value); } else { - cp->GetCtx()->SetViewportZMax(viewport, value); + cp.GetCtx().SetViewportZMax(viewport, value); } } @@ -1367,8 +1364,8 @@ KYTY_HW_SH_PARSER(HwShIgnoreRegisters) { return (cmd_id >> 16u) & 0x3fffu; } -static void HwShSetCsRegister(CommandProcessor* cp, uint32_t cmd_offset, uint32_t value) { - auto cs_regs = cp->GetShCtx()->GetCs().cs_regs; +static void HwShSetCsRegister(CommandProcessor& cp, uint32_t cmd_offset, uint32_t value) { + auto cs_regs = cp.GetShCtx().GetCs().cs_regs; switch (cmd_offset) { case Pm4::COMPUTE_PGM_LO: @@ -1433,7 +1430,7 @@ static void HwShSetCsRegister(CommandProcessor* cp, uint32_t cmd_offset, uint32_ value); } - cp->GetShCtx()->SetCsShader(cs_regs); + cp.GetShCtx().SetCsShader(cs_regs); } KYTY_HW_SH_PARSER(HwShSetCsRegisters) { @@ -1477,9 +1474,9 @@ KYTY_HW_SH_PARSER(HwShSetCsUserSgpr) { auto write_num = UserSgprWriteNum(slot, reg_num, "cs"); for (uint32_t i = 0; i < write_num; i++) { - cp->GetShCtx()->SetCsUserSgpr(slot + i, buffer[i], cp->GetUserDataMarker()); + cp.GetShCtx().SetCsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker()); } - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); return reg_num; } @@ -1493,9 +1490,9 @@ KYTY_HW_SH_PARSER(HwShSetCsUserAccumSgpr) { auto write_num = UserSgprWriteNum(slot, reg_num, "cs accum"); for (uint32_t i = 0; i < write_num; i++) { - cp->GetShCtx()->SetCsUserSgpr(slot + i, buffer[i], cp->GetUserDataMarker()); + cp.GetShCtx().SetCsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker()); } - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); return reg_num; } @@ -1510,9 +1507,9 @@ KYTY_HW_SH_PARSER(HwShSetPsUserSgpr) { auto write_num = UserSgprWriteNum(slot, reg_num, "ps"); for (uint32_t i = 0; i < write_num; i++) { - cp->GetShCtx()->SetPsUserSgpr(slot + i, buffer[i], cp->GetUserDataMarker()); + cp.GetShCtx().SetPsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker()); } - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); return reg_num; } @@ -1527,9 +1524,9 @@ KYTY_HW_SH_PARSER(HwShSetPsUserAccumSgpr) { auto write_num = UserSgprWriteNum(slot, reg_num, "ps accum"); for (uint32_t i = 0; i < write_num; i++) { - cp->GetShCtx()->SetPsUserSgpr(slot + i, buffer[i], cp->GetUserDataMarker()); + cp.GetShCtx().SetPsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker()); } - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); return reg_num; } @@ -1544,9 +1541,9 @@ KYTY_HW_SH_PARSER(HwShSetGsUserSgpr) { auto write_num = UserSgprWriteNum(slot, reg_num, "gs"); for (uint32_t i = 0; i < write_num; i++) { - cp->GetShCtx()->SetGsUserSgpr(slot + i, buffer[i], cp->GetUserDataMarker()); + cp.GetShCtx().SetGsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker()); } - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); return reg_num; } @@ -1561,9 +1558,9 @@ KYTY_HW_SH_PARSER(HwShSetGsUserAccumSgpr) { auto write_num = UserSgprWriteNum(slot, reg_num, "gs accum"); for (uint32_t i = 0; i < write_num; i++) { - cp->GetShCtx()->SetGsUserSgpr(slot + i, buffer[i], cp->GetUserDataMarker()); + cp.GetShCtx().SetGsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker()); } - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); return reg_num; } @@ -1578,9 +1575,9 @@ KYTY_HW_SH_PARSER(HwShSetHsUserSgpr) { auto write_num = UserSgprWriteNum(slot, reg_num, "hs"); for (uint32_t i = 0; i < write_num; i++) { - cp->GetShCtx()->SetHsUserSgpr(slot + i, buffer[i], cp->GetUserDataMarker()); + cp.GetShCtx().SetHsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker()); } - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); return reg_num; } @@ -1594,9 +1591,9 @@ KYTY_HW_SH_PARSER(HwShSetHsUserAccumSgpr) { auto write_num = UserSgprWriteNum(slot, reg_num, "hs accum"); for (uint32_t i = 0; i < write_num; i++) { - cp->GetShCtx()->SetHsUserSgpr(slot + i, buffer[i], cp->GetUserDataMarker()); + cp.GetShCtx().SetHsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker()); } - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); return reg_num; } @@ -1607,21 +1604,21 @@ KYTY_HW_UC_PARSER(HwUcSetPrimitiveType) { uint32_t prim_type = KYTY_PM4_GET(buffer[0], VGT_PRIMITIVE_TYPE, PRIM_TYPE); - cp->GetUcfg()->SetPrimitiveType(prim_type); + cp.GetUcfg().SetPrimitiveType(prim_type); return 1; } KYTY_HW_UC_PARSER(HwUcSetIndexType) { EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::VGT_INDEX_TYPE); - cp->SetIndexType(buffer[0] & 0x3u); + cp.SetIndexType(buffer[0] & 0x3u); return 1; } KYTY_HW_UC_PARSER(HwUcSetObjectId) { EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::VGT_OBJECT_ID); - cp->GetUcfg()->SetObjectId(buffer[0]); + cp.GetUcfg().SetObjectId(buffer[0]); return 1; } @@ -1677,25 +1674,23 @@ KYTY_HW_UC_PARSER(HwUcSetBorderColorTableAddr) { KYTY_HW_UC_PARSER(HwUcSetGeIndexOffset) { EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::GE_INDX_OFFSET); - cp->GetUcfg()->SetIndexOffset(buffer[0]); + cp.GetUcfg().SetIndexOffset(buffer[0]); return 1; } -static void HwUcSetGdsOaRegister(CommandProcessor* cp, uint32_t cmd_offset, uint32_t value) { - EXIT_IF(cp == nullptr); - - auto* ucfg = cp->GetUcfg(); +static void HwUcSetGdsOaRegister(CommandProcessor& cp, uint32_t cmd_offset, uint32_t value) { + auto& ucfg = cp.GetUcfg(); switch (cmd_offset) { - case Pm4::GDS_OA_CNTL: ucfg->SetGdsOaCntl(value); break; - case Pm4::GDS_OA_COUNTER: ucfg->SetGdsOaCounter(value); break; - case Pm4::GDS_OA_ADDRESS: ucfg->SetGdsOaAddress(value); break; + case Pm4::GDS_OA_CNTL: ucfg.SetGdsOaCntl(value); break; + case Pm4::GDS_OA_COUNTER: ucfg.SetGdsOaCounter(value); break; + case Pm4::GDS_OA_ADDRESS: ucfg.SetGdsOaAddress(value); break; default: EXIT("unknown GDS OA register: 0x%08" PRIx32 "\n", cmd_offset); } - const auto index = ucfg->GetGdsOaState().GetIndex(); - const auto& oa = ucfg->GetGdsOaCounter(index); + const auto index = ucfg.GetGdsOaState().GetIndex(); + const auto& oa = ucfg.GetGdsOaCounter(index); static std::atomic log_count {0}; if (oa.IsCounterEnabled() && log_count.fetch_add(1, std::memory_order_relaxed) < 128) { LOGF("GDS_OA: index=%u address_bytes=0x%04" PRIx32 " space=0x%08" PRIx32 @@ -1704,7 +1699,7 @@ static void HwUcSetGdsOaRegister(CommandProcessor* cp, uint32_t cmd_offset, uint " raw_address=0x%08" PRIx32 "\n", index, oa.GetAddressBytes(), oa.GetSpaceAvailable(), oa.GetCrawlerType(), oa.GetCrawlerId(), oa.IsAllocationCrawlerDisabled() ? "disabled" : "enabled", - ucfg->GetGdsOaState().cntl, oa.counter, oa.address); + ucfg.GetGdsOaState().cntl, oa.counter, oa.address); } } @@ -1810,9 +1805,9 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { ", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", gcr_cntl, base_lo << 8u, size_lo << 8u); - cp->MemoryBarrier(); + cp.MemoryBarrier(); if ((gcr_cntl & AcquireGcrGl2Writeback) != 0) { - cp->SynchronizeGpu(); + cp.SynchronizeGpu(); } } } break; @@ -1829,7 +1824,7 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { ", gcr_cntl = 0x%08" PRIx32 ", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", target_mask, gcr_cntl, base_lo << 8u, size_lo << 8u); - cp->MemoryBarrier(); + cp.MemoryBarrier(); } break; case 0x02000000: { // target_mask: 0x00000000 (none) @@ -1843,7 +1838,7 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { ", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", gcr_cntl, base_lo << 8u, size_lo << 8u); - cp->MemoryBarrier(); + cp.MemoryBarrier(); } break; case 0x04000000: { // target_mask: 0x00000000 (none) @@ -1857,7 +1852,7 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { ", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n", gcr_cntl, base_lo << 8u, size_lo << 8u); - cp->MemoryBarrier(); + cp.MemoryBarrier(); } break; case 0x04004000: case 0x04007fc0: { @@ -1873,9 +1868,9 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { target_mask, gcr_cntl, base_lo << 8u, size_lo << 8u); if (size_lo != 0) { - cp->DepthStencilBarrier(base_lo << 8u, size_lo << 8u); + cp.DepthStencilBarrier(base_lo << 8u, size_lo << 8u); } else { - cp->MemoryBarrier(); + cp.MemoryBarrier(); } } break; case 0x02c40040: @@ -1891,8 +1886,8 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { EXIT_NOT_IMPLEMENTED(size_lo == 0); EXIT_NOT_IMPLEMENTED(base_lo == 0); - cp->RenderTextureBarrier(base_lo << 8u, size_lo << 8u); - cp->SynchronizeGpu(); + cp.RenderTextureBarrier(base_lo << 8u, size_lo << 8u); + cp.SynchronizeGpu(); } break; case 0x02003fc0: case 0x02007fc0: { @@ -1908,11 +1903,11 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { LOGF("\t warning: acquire_mem CB-cache barrier with non-zero base"); } - cp->MemoryBarrier(); + cp.MemoryBarrier(); } else { EXIT_NOT_IMPLEMENTED(base_lo == 0); - cp->RenderTextureBarrier(base_lo << 8u, size_lo << 8u); + cp.RenderTextureBarrier(base_lo << 8u, size_lo << 8u); } } break; case 0x00C40000: { @@ -1925,8 +1920,8 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { EXIT_NOT_IMPLEMENTED(size_lo != 1); EXIT_NOT_IMPLEMENTED(base_lo != 0); - cp->MemoryBarrier(); - cp->SynchronizeGpu(); + cp.MemoryBarrier(); + cp.SynchronizeGpu(); } break; case 0x00400000: { // target_mask: 0x00000000 (none) @@ -1938,7 +1933,7 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { EXIT_NOT_IMPLEMENTED(size_lo != 1); EXIT_NOT_IMPLEMENTED(base_lo != 0); - cp->MemoryBarrier(); + cp.MemoryBarrier(); } break; case 0x04c44000: { // target_mask: 0x00004000 (Depth Target) @@ -1948,8 +1943,8 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { EXIT_IF(extended_action != 0x04000000); EXIT_IF(action != 0x38); - cp->DepthStencilBarrier(base_lo << 8u, size_lo << 8u); - cp->SynchronizeGpu(); + cp.DepthStencilBarrier(base_lo << 8u, size_lo << 8u); + cp.SynchronizeGpu(); } break; case 0x06000040: @@ -1972,13 +1967,13 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { if (size_lo != 0) { if ((target_mask & 0x00003fc0) != 0) { - cp->RenderTextureBarrier(base_lo << 8u, size_lo << 8u); + cp.RenderTextureBarrier(base_lo << 8u, size_lo << 8u); } if ((target_mask & 0x00004000) != 0) { - cp->DepthStencilBarrier(base_lo << 8u, size_lo << 8u); + cp.DepthStencilBarrier(base_lo << 8u, size_lo << 8u); } } else { - cp->MemoryBarrier(); + cp.MemoryBarrier(); } } break; @@ -1989,8 +1984,8 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) { } if (stall_mode == 0) { - cp->BufferFlush(); - cp->BufferWait(); + cp.BufferFlush(); + cp.BufferWait(); } return (custom ? 7 : 6); @@ -2007,7 +2002,7 @@ KYTY_CP_OP_PARSER(CpOpDispatchDirect) { uint32_t thread_group_z = buffer[2]; uint32_t mode = buffer[3]; - cp->DispatchDirect(thread_group_x, thread_group_y, thread_group_z, mode); + cp.DispatchDirect(thread_group_x, thread_group_y, thread_group_z, mode); return KYTY_PM4_LEN(cmd_id) - 1; } @@ -2029,7 +2024,7 @@ KYTY_CP_OP_PARSER(CpOpDispatchIndirect) { uint32_t mode = buffer[2]; EXIT_NOT_IMPLEMENTED(args == nullptr); - cp->DispatchDirect(args->thread_group_x, args->thread_group_y, args->thread_group_z, mode); + cp.DispatchDirect(args->thread_group_x, args->thread_group_y, args->thread_group_z, mode); return 3; } @@ -2037,7 +2032,7 @@ KYTY_CP_OP_PARSER(CpOpDispatchIndirect) { uint32_t data_offset = buffer[0]; uint32_t mode = buffer[1]; - cp->DispatchIndirect(data_offset, mode); + cp.DispatchIndirect(data_offset, mode); return 2; } @@ -2068,7 +2063,7 @@ KYTY_CP_OP_PARSER(CpOpDispatchReset) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0001024); - cp->Reset(); + cp.Reset(); return 1; } @@ -2108,7 +2103,7 @@ KYTY_CP_OP_PARSER(CpOpSetPredication) { auto* address = reinterpret_cast(address_value); auto count_in_dwords = 0u; - cp->SetPredication(condition, op, wait_op, address, count_in_dwords); + cp.SetPredication(condition, op, wait_op, address, count_in_dwords); return payload_dw; } @@ -2171,10 +2166,10 @@ KYTY_CP_OP_PARSER(CpOpBranch) { reinterpret_cast(else_buffer), else_num_dw); if (take_then) { - cp->Run(then_buffer, then_num_dw); + cp.Run(then_buffer, then_num_dw); } else if (mode == 2 && else_num_dw != 0) { EXIT_NOT_IMPLEMENTED(else_buffer == nullptr); - cp->Run(else_buffer, else_num_dw); + cp.Run(else_buffer, else_num_dw); } return payload_dw; @@ -2230,7 +2225,7 @@ KYTY_CP_OP_PARSER(CpOpCopyData) { " dst_sel=0x%02" PRIx32 " dst=0x%016" PRIx64 " size=%u\n", src_sel, dst_sel, dst, num_bytes); } - cp->WriteReferenceClock(dst, num_bytes); + cp.WriteReferenceClock(dst, num_bytes); return 5; } const auto dma_src = CopyDataSrcToDma(src_sel); @@ -2238,8 +2233,8 @@ KYTY_CP_OP_PARSER(CpOpCopyData) { EXIT("unsupported 64-bit immediate copyData\n"); } - cp->DmaData(0, CopyDataDstToDma(dst_sel), dst_cache, dst, dma_src, src_cache, src, num_bytes, 1, - write_confirm, 1); + cp.DmaData(0, CopyDataDstToDma(dst_sel), dst_cache, dst, dma_src, src_cache, src, num_bytes, 1, + write_confirm, 1); return 5; } @@ -2257,7 +2252,7 @@ KYTY_CP_OP_PARSER(CpOpDmaData) { if (control == 0x60000000 && dst == 0x0003022c && (control2 >> 21u) == 0x141u) { auto* addr = reinterpret_cast(src); - cp->PrefetchL2(addr, control2 & 0x1fffffu); + cp.PrefetchL2(addr, control2 & 0x1fffffu); return 6; } @@ -2273,8 +2268,8 @@ KYTY_CP_OP_PARSER(CpOpDmaData) { const uint8_t write_confirm = static_cast((control2 >> 31u) & 0x1u); const uint32_t num_bytes = control2 & 0x03ffffffu; - cp->DmaData(engine, dst_sel, dst_cache_policy, dst, src_sel, src_cache_policy, src, num_bytes, - wait_previous, write_confirm, block_engine); + cp.DmaData(engine, dst_sel, dst_cache_policy, dst, src_sel, src_cache_policy, src, num_bytes, + wait_previous, write_confirm, block_engine); return 6; } @@ -2297,7 +2292,7 @@ KYTY_CP_OP_PARSER(CpOpDrawIndex) { EXIT_NOT_IMPLEMENTED(instance_count > max_instance_count); EXIT_NOT_IMPLEMENTED((flags & ~0xa0u) != 0); - cp->DrawIndex(index_count, index_addr, 0, 1, instance_count, object_ids); + cp.DrawIndex(index_count, index_addr, 0, 1, instance_count, object_ids); return 8; } @@ -2312,7 +2307,7 @@ KYTY_CP_OP_PARSER(CpOpDrawIndex) { EXIT_NOT_IMPLEMENTED(index_count > max_index_count); EXIT_NOT_IMPLEMENTED((flags & ~0x20u) != 0); - cp->DrawIndex(index_count, index_addr, 0, 1); + cp.DrawIndex(index_count, index_addr, 0, 1); return 5; } @@ -2329,7 +2324,7 @@ KYTY_CP_OP_PARSER(CpOpDrawIndirect) { const auto draw_initiator = buffer[3]; const bool indexed = (cmd_id == 0xc0032500); - cp->DrawIndirect(data_offset, draw_initiator, indexed); + cp.DrawIndirect(data_offset, draw_initiator, indexed); return 4; } @@ -2352,8 +2347,8 @@ KYTY_CP_OP_PARSER(CpOpDrawIndirectMulti) { count_addr = nullptr; } - cp->DrawIndirectMulti(data_offset, max_count_or_count, count_addr, stride_in_bytes, - draw_initiator, indexed); + cp.DrawIndirectMulti(data_offset, max_count_or_count, count_addr, stride_in_bytes, + draw_initiator, indexed); return 9; } @@ -2371,7 +2366,7 @@ KYTY_CP_OP_PARSER(CpOpDrawIndexOffset) { EXIT_NOT_IMPLEMENTED(index_count > max_index_size); EXIT_NOT_IMPLEMENTED((flags & ~0x20u) != 0); - cp->DrawIndexOffset(index_offset, index_count, 0); + cp.DrawIndexOffset(index_offset, index_count, 0); return 4; } @@ -2386,7 +2381,7 @@ KYTY_CP_OP_PARSER(CpOpDrawIndexAuto) { EXIT_NOT_IMPLEMENTED((flags & ~0x22u) != 0); - cp->DrawIndexAuto(index_count, 0); + cp.DrawIndexAuto(index_count, 0); return 2; } @@ -2397,7 +2392,7 @@ KYTY_CP_OP_PARSER(CpOpClearState) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0001200); EXIT_NOT_IMPLEMENTED((buffer[0] & ~0xfu) != 0); - cp->Reset(); + cp.Reset(); return 1; } @@ -2415,7 +2410,7 @@ KYTY_CP_OP_PARSER(CpOpDumpConstRam) { EXIT_NOT_IMPLEMENTED(offset > 0xbffc); EXIT_NOT_IMPLEMENTED((offset & 0x3u) != 0); - cp->DumpConstRam(dst, offset, dw_num); + cp.DumpConstRam(dst, offset, dw_num); return 4; } @@ -2428,7 +2423,7 @@ KYTY_CP_OP_PARSER(CpOpEventWrite) { uint32_t event_index = (buffer[0] >> 8u) & 0x7u; uint32_t event_type = (buffer[0]) & 0x3fu; - cp->TriggerEvent(event_type, event_index); + cp.TriggerEvent(event_type, event_index); return KYTY_PM4_LEN(cmd_id) - 1u; } @@ -2449,9 +2444,8 @@ KYTY_CP_OP_PARSER(CpOpEventWriteEop) { reinterpret_cast(buffer[1] | (static_cast(buffer[2] & 0xffffu) << 32u)); uint64_t value = (buffer[3] | (static_cast(buffer[4]) << 32u)); - cp->WriteAtEndOfPipe64(cache_policy, event_write_dest, eop_event_type, cache_action, - event_index, event_write_source, dst_gpu_addr, value, - interrupt_selector); + cp.WriteAtEndOfPipe64(cache_policy, event_write_dest, eop_event_type, cache_action, event_index, + event_write_source, dst_gpu_addr, value, interrupt_selector); return 5; } @@ -2473,9 +2467,8 @@ KYTY_CP_OP_PARSER(CpOpEventWriteEos) { reinterpret_cast(buffer[1] | (static_cast(buffer[2] & 0xffffu) << 32u)); uint32_t value = buffer[3]; - cp->WriteAtEndOfPipe32(cache_policy, event_write_dest, eop_event_type, cache_action, - event_index, event_write_source, dst_gpu_addr, value, - interrupt_selector); + cp.WriteAtEndOfPipe32(cache_policy, event_write_dest, eop_event_type, cache_action, event_index, + event_write_source, dst_gpu_addr, value, interrupt_selector); return 4; } @@ -2492,8 +2485,8 @@ KYTY_CP_OP_PARSER(CpOpFlip) { f.flip_mode = static_cast(buffer[2]); f.flip_arg = static_cast(buffer[3] | (static_cast(buffer[4]) << 32u)); - cp->SetFlip(f); - cp->Flip(); + cp.SetFlip(f); + cp.Flip(); return 5; } @@ -2503,7 +2496,7 @@ KYTY_CP_OP_PARSER(CpOpIncrementCeCounter) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008400); EXIT_NOT_IMPLEMENTED(buffer[0] != 1); - cp->IncremenetCe(); + cp.IncremenetCe(); return 1; } @@ -2514,7 +2507,7 @@ KYTY_CP_OP_PARSER(CpOpIncrementDeCounter) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008500); EXIT_NOT_IMPLEMENTED(buffer[0] != 0); - cp->IncremenetDe(); + cp.IncremenetDe(); return 1; } @@ -2524,7 +2517,7 @@ KYTY_CP_OP_PARSER(CpOpIndexType) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0002A00); - cp->SetIndexType(buffer[0]); + cp.SetIndexType(buffer[0]); return 1; } @@ -2534,7 +2527,7 @@ KYTY_CP_OP_PARSER(CpOpIndexBufferSize) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0001300); - cp->SetIndexBufferSize(buffer[0]); + cp.SetIndexBufferSize(buffer[0]); return 1; } @@ -2546,7 +2539,7 @@ KYTY_CP_OP_PARSER(CpOpIndexBase) { auto index_base_addr = buffer[0] | (static_cast(buffer[1]) << 32u); - cp->SetIndexBaseAddress(index_base_addr); + cp.SetIndexBaseAddress(index_base_addr); return 2; } @@ -2566,9 +2559,9 @@ KYTY_CP_OP_PARSER(CpOpSetBase) { EXIT_NOT_IMPLEMENTED(shader_type > 1u); if (shader_type == 0u) { - cp->SetDrawIndirectArgsBaseAddress(base_addr); + cp.SetDrawIndirectArgsBaseAddress(base_addr); } else { - cp->SetDispatchIndirectArgsBaseAddress(base_addr); + cp.SetDispatchIndirectArgsBaseAddress(base_addr); } return 3; @@ -2614,7 +2607,7 @@ KYTY_CP_OP_PARSER(CpOpIndirectBuffer) { GraphicsDbgDumpDcb("ci", indirect_num_dw, indirect_buffer); - cp->Run(indirect_buffer, indirect_num_dw); + cp.Run(indirect_buffer, indirect_num_dw); return 3; } @@ -2811,18 +2804,18 @@ KYTY_CP_OP_PARSER(CpOpMarker) { uint32_t len_dw = ((cmd_id >> 16u) & 0x3fffu); switch (id) { - case 0x0: cp->SetEmbeddedDataMarker(buffer + 1, len_dw, align); break; - case 0x4: cp->SetUserDataMarker(HW::UserSgprType::Vsharp); break; - case 0xd: cp->SetUserDataMarker(HW::UserSgprType::Region); break; + case 0x0: cp.SetEmbeddedDataMarker(buffer + 1, len_dw, align); break; + case 0x4: cp.SetUserDataMarker(HW::UserSgprType::Vsharp); break; + case 0xd: cp.SetUserDataMarker(HW::UserSgprType::Region); break; case 0x777: { - cp->Flip(); + cp.Flip(); break; } case 0x778: { auto* addr = reinterpret_cast(buffer[1] | (static_cast(buffer[2]) << 32u)); uint32_t value = buffer[3]; - cp->Flip(addr, value); + cp.Flip(addr, value); break; } case 0x781: { @@ -2831,7 +2824,7 @@ KYTY_CP_OP_PARSER(CpOpMarker) { uint32_t value = buffer[3]; uint32_t eop_event_type = buffer[4]; uint32_t cache_action = buffer[5]; - cp->FlipWithInterrupt(eop_event_type, cache_action, addr, value); + cp.FlipWithInterrupt(eop_event_type, cache_action, addr, value); break; } default: EXIT("unknown marker at %05" PRIx32 ": 0x%" PRIx32 "\n", num_dw - dw, id); @@ -2868,7 +2861,7 @@ KYTY_CP_OP_PARSER(CpOpNumInstances) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0002f00); - cp->SetNumInstances(buffer[0]); + cp.SetNumInstances(buffer[0]); return 1; } @@ -2883,7 +2876,7 @@ KYTY_CP_OP_PARSER(CpOpPopMarker) { LOGF("Pop marker\n"); } - cp->PopMarker(); + cp.PopMarker(); return dw_num + 1; } @@ -2900,7 +2893,7 @@ KYTY_CP_OP_PARSER(CpOpPushMarker) { LOGF("Push marker: %s\n", str); } - cp->PushMarker(str); + cp.PushMarker(str); return dw_num + 1; } @@ -2939,18 +2932,18 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) { case 0x03: break; case 0x01: case 0x02: - case 0x04: cp->TriggerEopEventAtEndOfPipe(interrupt_context_id); break; + case 0x04: cp.TriggerEopEventAtEndOfPipe(interrupt_context_id); break; default: EXIT("unknown release_mem interrupt selector\n"); } }; if (data_sel == 0 || interrupt_selector == 4) { if (eop_event_type != 0x28 || gcr_cntl != 0) { - cp->MemoryBarrier(); + cp.MemoryBarrier(); } if (gl2_writeback) { - cp->SynchronizeGpu(); + cp.SynchronizeGpu(); } trigger_interrupt(); @@ -2960,11 +2953,11 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) { if (release_dst == ReleaseMemDstMemory && dst_gpu_addr == nullptr) { if (eop_event_type != 0x28 || gcr_cntl != 0) { - cp->MemoryBarrier(); + cp.MemoryBarrier(); } if (gl2_writeback) { - cp->SynchronizeGpu(); + cp.SynchronizeGpu(); } trigger_interrupt(); @@ -2973,7 +2966,7 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) { } if (ReleaseMemGcrNeedsBarrier(eop_event_type, gcr_cntl)) { - cp->MemoryBarrier(); + cp.MemoryBarrier(); } auto cache_action = ReleaseMemCacheActionFromGcr(gcr_cntl); @@ -2995,17 +2988,17 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) { event_index = 6; auto event_source = 2u; - cp->WriteAtEndOfPipe32( - cache_policy, event_write_dest, eop_event_type, cache_action, event_index, event_source, - dst_gpu_addr, static_cast(value), interrupt_selector, interrupt_context_id); - cp->BufferFlush(); + cp.WriteAtEndOfPipe32(cache_policy, event_write_dest, eop_event_type, cache_action, + event_index, event_source, dst_gpu_addr, static_cast(value), + interrupt_selector, interrupt_context_id); + cp.BufferFlush(); return 7; } if (data_sel == 5) { if (gl2_writeback) { - cp->SynchronizeGpu(); + cp.SynchronizeGpu(); cache_action = 0; } @@ -3013,10 +3006,10 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) { event_index = 6; auto event_source = 1u; - cp->WriteAtEndOfPipe32( - cache_policy, event_write_dest, eop_event_type, cache_action, event_index, event_source, - dst_gpu_addr, static_cast(value), interrupt_selector, interrupt_context_id); - cp->BufferFlush(); + cp.WriteAtEndOfPipe32(cache_policy, event_write_dest, eop_event_type, cache_action, + event_index, event_source, dst_gpu_addr, static_cast(value), + interrupt_selector, interrupt_context_id); + cp.BufferFlush(); return 7; } @@ -3037,9 +3030,8 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) { data_sel = 4; } - cp->WriteAtEndOfPipe64(cache_policy, event_write_dest, eop_event_type, cache_action, - event_index, data_sel, dst_gpu_addr, value, interrupt_selector, - interrupt_context_id); + cp.WriteAtEndOfPipe64(cache_policy, event_write_dest, eop_event_type, cache_action, event_index, + data_sel, dst_gpu_addr, value, interrupt_selector, interrupt_context_id); return 7; } @@ -3175,7 +3167,7 @@ KYTY_CP_OP_PARSER(CpOpWaitFlipDone) { auto video_out_handle = buffer[0]; auto display_buffer_index = buffer[1]; - cp->WaitFlipDone(video_out_handle, display_buffer_index); + cp.WaitFlipDone(video_out_handle, display_buffer_index); return 6; } @@ -3203,7 +3195,7 @@ static uint32_t CpOpWaitRegMemWaitOp(uint32_t control) { } template -static uint32_t CpOpWaitRegMemSized(CommandProcessor* cp, uint32_t cmd_id, const uint32_t* buffer) { +static uint32_t CpOpWaitRegMemSized(CommandProcessor& cp, uint32_t cmd_id, const uint32_t* buffer) { static_assert(sizeof(T) == sizeof(uint32_t) || sizeof(T) == sizeof(uint64_t)); constexpr auto value_dw = static_cast(sizeof(T) / sizeof(uint32_t)); @@ -3223,7 +3215,7 @@ static uint32_t CpOpWaitRegMemSized(CommandProcessor* cp, uint32_t cmd_id, const EXIT_NOT_IMPLEMENTED((ctrl & 0x10u) == 0); - cp->WaitRegMem(ctrl & 0x7u, addr, ref, mask, poll, CpOpWaitRegMemWaitOp(ctrl)); + cp.WaitRegMem(ctrl & 0x7u, addr, ref, mask, poll, CpOpWaitRegMemWaitOp(ctrl)); return payload_dw; } @@ -3246,7 +3238,7 @@ KYTY_CP_OP_PARSER(CpOpWaitOnCeCounter) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008600); EXIT_NOT_IMPLEMENTED(buffer[0] != 1); - cp->WaitCe(); + cp.WaitCe(); return 1; } @@ -3256,7 +3248,7 @@ KYTY_CP_OP_PARSER(CpOpWaitOnDeCounterDiff) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008800); - cp->WaitDeDiff(buffer[0]); + cp.WaitDeDiff(buffer[0]); return 1; } @@ -3271,7 +3263,7 @@ KYTY_CP_OP_PARSER(CpOpWriteConstRam) { EXIT_NOT_IMPLEMENTED(offset > 0xbffc); EXIT_NOT_IMPLEMENTED((offset & 0x3u) != 0); - cp->WriteConstRam(offset, buffer + 1, dw_num); + cp.WriteConstRam(offset, buffer + 1, dw_num); return 1 + dw_num; } @@ -3288,7 +3280,7 @@ KYTY_CP_OP_PARSER(CpOpWriteData) { auto write_control = buffer[0]; auto* dst = reinterpret_cast(buffer[1] | (static_cast(buffer[2]) << 32u)); - cp->WriteData(dst, buffer + 3, dw_num - 2, write_control); + cp.WriteData(dst, buffer + 3, dw_num - 2, write_control); return 1 + dw_num; } @@ -3302,7 +3294,7 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset++) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = cmd_offset - Pm4::SPI_PS_INPUT_CNTL_0; - cp->GetCtx()->SetPsInputSettings(slot, value); + cp.GetCtx().SetPsInputSettings(slot, value); }; } @@ -3310,10 +3302,10 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset += 15) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_BASE) / 15; - auto base = cp->GetCtx()->GetRenderTarget(slot).base; + auto base = cp.GetCtx().GetRenderTarget(slot).base; base.addr &= 0xFFFFFF00000000FFull; base.addr |= static_cast(value) << 8u; - cp->GetCtx()->SetColorBase(slot, base); + cp.GetCtx().SetColorBase(slot, base); }; } @@ -3324,7 +3316,7 @@ void GraphicsInitJmpTablesCxIndirect() { HW::ColorPitch pitch; pitch.pitch_div8_minus1 = value & 0x7ffu; pitch.fmask_pitch_div8_minus1 = (value >> 20u) & 0x7ffu; - cp->GetCtx()->SetColorPitch(slot, pitch); + cp.GetCtx().SetColorPitch(slot, pitch); }; } @@ -3334,7 +3326,7 @@ void GraphicsInitJmpTablesCxIndirect() { uint32_t slot = (cmd_offset - (Pm4::CB_COLOR0_BASE + 2)) / 15; HW::ColorSlice slice; slice.slice_div64_minus1 = value & 0x3fffffu; - cp->GetCtx()->SetColorSlice(slot, slice); + cp.GetCtx().SetColorSlice(slot, slice); }; } @@ -3342,10 +3334,10 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset++) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_BASE_EXT); - auto base = cp->GetCtx()->GetRenderTarget(slot).base; + auto base = cp.GetCtx().GetRenderTarget(slot).base; base.addr &= 0xFFFF00FFFFFFFFFFull; base.addr |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetColorBase(slot, base); + cp.GetCtx().SetColorBase(slot, base); }; } @@ -3357,7 +3349,7 @@ void GraphicsInitJmpTablesCxIndirect() { view.base_array_slice_index = KYTY_PM4_GET(value, CB_COLOR0_VIEW, SLICE_START); view.last_array_slice_index = KYTY_PM4_GET(value, CB_COLOR0_VIEW, SLICE_MAX); view.current_mip_level = KYTY_PM4_GET(value, CB_COLOR0_VIEW, MIP_LEVEL); - cp->GetCtx()->SetColorView(slot, view); + cp.GetCtx().SetColorView(slot, view); }; } @@ -3382,7 +3374,7 @@ void GraphicsInitJmpTablesCxIndirect() { info.dcc_compression_enable = KYTY_PM4_GET(value, CB_COLOR0_INFO, DCC_ENABLE) != 0; info.cmask_addr_type = KYTY_PM4_GET(value, CB_COLOR0_INFO, CMASK_ADDR_TYPE); info.alt_tile_mode = KYTY_PM4_GET(value, CB_COLOR0_INFO, ALT_TILE_MODE) != 0; - cp->GetCtx()->SetColorInfo(slot, info); + cp.GetCtx().SetColorInfo(slot, info); }; } @@ -3397,7 +3389,7 @@ void GraphicsInitJmpTablesCxIndirect() { attrib.fmask_tile_mode = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, FMASK_TILE_MODE_INDEX); attrib.num_samples = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, NUM_SAMPLES); attrib.num_fragments = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB, NUM_FRAGMENTS); - cp->GetCtx()->SetColorAttrib(slot, attrib); + cp.GetCtx().SetColorAttrib(slot, attrib); }; } @@ -3423,7 +3415,7 @@ void GraphicsInitJmpTablesCxIndirect() { KYTY_PM4_GET(value, CB_COLOR0_DCC_CONTROL, ENABLE_CONSTANT_ENCODE_REG_WRITE) != 0; dcc.independent_128b_blocks = KYTY_PM4_GET(value, CB_COLOR0_DCC_CONTROL, INDEPENDENT_128B_BLOCKS) != 0; - cp->GetCtx()->SetColorDccControl(slot, dcc); + cp.GetCtx().SetColorDccControl(slot, dcc); }; } @@ -3431,10 +3423,10 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset += 15) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_CMASK) / 15; - auto base = cp->GetCtx()->GetRenderTarget(slot).cmask; + auto base = cp.GetCtx().GetRenderTarget(slot).cmask; base.addr &= 0xFFFFFF00000000FFull; base.addr |= static_cast(value) << 8u; - cp->GetCtx()->SetColorCmask(slot, base); + cp.GetCtx().SetColorCmask(slot, base); }; } @@ -3444,7 +3436,7 @@ void GraphicsInitJmpTablesCxIndirect() { uint32_t slot = (cmd_offset - (Pm4::CB_COLOR0_CMASK + 1)) / 15; HW::ColorCmaskSlice cmask_slice; cmask_slice.slice_minus1 = value & 0x3fffu; - cp->GetCtx()->SetColorCmaskSlice(slot, cmask_slice); + cp.GetCtx().SetColorCmaskSlice(slot, cmask_slice); }; } @@ -3452,10 +3444,10 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset <= Pm4::CB_COLOR7_CMASK_BASE_EXT; cmd_offset++) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_CMASK_BASE_EXT); - auto base = cp->GetCtx()->GetRenderTarget(slot).cmask; + auto base = cp.GetCtx().GetRenderTarget(slot).cmask; base.addr &= 0xFFFF00FFFFFFFFFFull; base.addr |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetColorCmask(slot, base); + cp.GetCtx().SetColorCmask(slot, base); }; } @@ -3463,10 +3455,10 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset += 15) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_FMASK) / 15; - auto base = cp->GetCtx()->GetRenderTarget(slot).fmask; + auto base = cp.GetCtx().GetRenderTarget(slot).fmask; base.addr &= 0xFFFFFF00000000FFull; base.addr |= static_cast(value) << 8u; - cp->GetCtx()->SetColorFmask(slot, base); + cp.GetCtx().SetColorFmask(slot, base); }; } @@ -3476,7 +3468,7 @@ void GraphicsInitJmpTablesCxIndirect() { uint32_t slot = (cmd_offset - (Pm4::CB_COLOR0_FMASK + 1)) / 15; HW::ColorFmaskSlice fmask_slice; fmask_slice.slice_minus1 = value & 0x3fffffu; - cp->GetCtx()->SetColorFmaskSlice(slot, fmask_slice); + cp.GetCtx().SetColorFmaskSlice(slot, fmask_slice); }; } @@ -3484,10 +3476,10 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset <= Pm4::CB_COLOR7_FMASK_BASE_EXT; cmd_offset++) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_FMASK_BASE_EXT); - auto base = cp->GetCtx()->GetRenderTarget(slot).fmask; + auto base = cp.GetCtx().GetRenderTarget(slot).fmask; base.addr &= 0xFFFF00FFFFFFFFFFull; base.addr |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetColorFmask(slot, base); + cp.GetCtx().SetColorFmask(slot, base); }; } @@ -3497,7 +3489,7 @@ void GraphicsInitJmpTablesCxIndirect() { HW::ColorClearWord0 clear_word0; clear_word0.word0 = value; uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_CLEAR_WORD0) / 15; - cp->GetCtx()->SetColorClearWord0(slot, clear_word0); + cp.GetCtx().SetColorClearWord0(slot, clear_word0); }; } @@ -3507,7 +3499,7 @@ void GraphicsInitJmpTablesCxIndirect() { HW::ColorClearWord1 clear_word1; clear_word1.word1 = value; uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_CLEAR_WORD1) / 15; - cp->GetCtx()->SetColorClearWord1(slot, clear_word1); + cp.GetCtx().SetColorClearWord1(slot, clear_word1); }; } @@ -3515,10 +3507,10 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset += 15) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_DCC_BASE) / 15; - auto base = cp->GetCtx()->GetRenderTarget(slot).dcc_addr; + auto base = cp.GetCtx().GetRenderTarget(slot).dcc_addr; base.addr &= 0xFFFFFF00000000FFull; base.addr |= static_cast(value) << 8u; - cp->GetCtx()->SetColorDccAddr(slot, base); + cp.GetCtx().SetColorDccAddr(slot, base); }; } @@ -3526,10 +3518,10 @@ void GraphicsInitJmpTablesCxIndirect() { cmd_offset++) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t slot = (cmd_offset - Pm4::CB_COLOR0_DCC_BASE_EXT); - auto base = cp->GetCtx()->GetRenderTarget(slot).dcc_addr; + auto base = cp.GetCtx().GetRenderTarget(slot).dcc_addr; base.addr &= 0xFFFF00FFFFFFFFFFull; base.addr |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetColorDccAddr(slot, base); + cp.GetCtx().SetColorDccAddr(slot, base); }; } @@ -3541,7 +3533,7 @@ void GraphicsInitJmpTablesCxIndirect() { attrib2.height = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB2, MIP0_HEIGHT); attrib2.width = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB2, MIP0_WIDTH); attrib2.num_mip_levels = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB2, MAX_MIP); - cp->GetCtx()->SetColorAttrib2(slot, attrib2); + cp.GetCtx().SetColorAttrib2(slot, attrib2); }; } @@ -3555,55 +3547,55 @@ void GraphicsInitJmpTablesCxIndirect() { attrib3.dimension = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, RESOURCE_TYPE); attrib3.cmask_pipe_aligned = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, CMASK_PIPE_ALIGNED); attrib3.dcc_pipe_aligned = KYTY_PM4_GET(value, CB_COLOR0_ATTRIB3, DCC_PIPE_ALIGNED); - cp->GetCtx()->SetColorAttrib3(slot, attrib3); + cp.GetCtx().SetColorAttrib3(slot, attrib3); }; } for (auto cmd_offset = Pm4::PA_CL_VPORT_XSCALE; cmd_offset <= Pm4::PA_CL_VPORT_XSCALE_15; cmd_offset += 6) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportXScale((cmd_offset - Pm4::PA_CL_VPORT_XSCALE) / 6, - *reinterpret_cast(&value)); + cp.GetCtx().SetViewportXScale((cmd_offset - Pm4::PA_CL_VPORT_XSCALE) / 6, + *reinterpret_cast(&value)); }; } for (auto cmd_offset = Pm4::PA_CL_VPORT_XOFFSET; cmd_offset <= Pm4::PA_CL_VPORT_XOFFSET_15; cmd_offset += 6) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportXOffset((cmd_offset - Pm4::PA_CL_VPORT_XOFFSET) / 6, - *reinterpret_cast(&value)); + cp.GetCtx().SetViewportXOffset((cmd_offset - Pm4::PA_CL_VPORT_XOFFSET) / 6, + *reinterpret_cast(&value)); }; } for (auto cmd_offset = Pm4::PA_CL_VPORT_YSCALE; cmd_offset <= Pm4::PA_CL_VPORT_YSCALE_15; cmd_offset += 6) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportYScale((cmd_offset - Pm4::PA_CL_VPORT_YSCALE) / 6, - *reinterpret_cast(&value)); + cp.GetCtx().SetViewportYScale((cmd_offset - Pm4::PA_CL_VPORT_YSCALE) / 6, + *reinterpret_cast(&value)); }; } for (auto cmd_offset = Pm4::PA_CL_VPORT_YOFFSET; cmd_offset <= Pm4::PA_CL_VPORT_YOFFSET_15; cmd_offset += 6) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportYOffset((cmd_offset - Pm4::PA_CL_VPORT_YOFFSET) / 6, - *reinterpret_cast(&value)); + cp.GetCtx().SetViewportYOffset((cmd_offset - Pm4::PA_CL_VPORT_YOFFSET) / 6, + *reinterpret_cast(&value)); }; } for (auto cmd_offset = Pm4::PA_CL_VPORT_ZSCALE; cmd_offset <= Pm4::PA_CL_VPORT_ZSCALE_15; cmd_offset += 6) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportZScale((cmd_offset - Pm4::PA_CL_VPORT_ZSCALE) / 6, - *reinterpret_cast(&value)); + cp.GetCtx().SetViewportZScale((cmd_offset - Pm4::PA_CL_VPORT_ZSCALE) / 6, + *reinterpret_cast(&value)); }; } for (auto cmd_offset = Pm4::PA_CL_VPORT_ZOFFSET; cmd_offset <= Pm4::PA_CL_VPORT_ZOFFSET_15; cmd_offset += 6) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportZOffset((cmd_offset - Pm4::PA_CL_VPORT_ZOFFSET) / 6, - *reinterpret_cast(&value)); + cp.GetCtx().SetViewportZOffset((cmd_offset - Pm4::PA_CL_VPORT_ZOFFSET) / 6, + *reinterpret_cast(&value)); }; } @@ -3616,8 +3608,8 @@ void GraphicsInitJmpTablesCxIndirect() { static_cast(KYTY_PM4_GET(value, PA_SC_VPORT_SCISSOR_0_TL, TL_Y))); bool window_offset_disable = KYTY_PM4_GET(value, PA_SC_VPORT_SCISSOR_0_TL, WINDOW_OFFSET_DISABLE) != 0; - cp->GetCtx()->SetViewportScissorTL((cmd_offset - Pm4::PA_SC_VPORT_SCISSOR_0_TL) / 2, - left, top, !window_offset_disable); + cp.GetCtx().SetViewportScissorTL((cmd_offset - Pm4::PA_SC_VPORT_SCISSOR_0_TL) / 2, left, + top, !window_offset_disable); }; } @@ -3628,58 +3620,56 @@ void GraphicsInitJmpTablesCxIndirect() { static_cast(KYTY_PM4_GET(value, PA_SC_VPORT_SCISSOR_0_BR, BR_X))); int bottom = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_VPORT_SCISSOR_0_BR, BR_Y))); - cp->GetCtx()->SetViewportScissorBR((cmd_offset - Pm4::PA_SC_VPORT_SCISSOR_0_BR) / 2, - right, bottom); + cp.GetCtx().SetViewportScissorBR((cmd_offset - Pm4::PA_SC_VPORT_SCISSOR_0_BR) / 2, + right, bottom); }; } for (auto cmd_offset = Pm4::PA_SC_VPORT_ZMIN_0; cmd_offset <= Pm4::PA_SC_VPORT_ZMIN_15; cmd_offset += 2) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportZMin((cmd_offset - Pm4::PA_SC_VPORT_ZMIN_0) / 2, - *reinterpret_cast(&value)); + cp.GetCtx().SetViewportZMin((cmd_offset - Pm4::PA_SC_VPORT_ZMIN_0) / 2, + *reinterpret_cast(&value)); }; } for (auto cmd_offset = Pm4::PA_SC_VPORT_ZMAX_0; cmd_offset <= Pm4::PA_SC_VPORT_ZMAX_15; cmd_offset += 2) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportZMax((cmd_offset - Pm4::PA_SC_VPORT_ZMAX_0) / 2, - *reinterpret_cast(&value)); + cp.GetCtx().SetViewportZMax((cmd_offset - Pm4::PA_SC_VPORT_ZMAX_0) / 2, + *reinterpret_cast(&value)); }; } g_hw_ctx_indirect_func[Pm4::PA_CL_GB_VERT_CLIP_ADJ] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto vp = cp->GetCtx()->GetScreenViewport(); - cp->GetCtx()->SetGuardBands(vp.guard_band_horz_clip, - *reinterpret_cast(&value), - vp.guard_band_horz_discard, vp.guard_band_vert_discard); + auto vp = cp.GetCtx().GetScreenViewport(); + cp.GetCtx().SetGuardBands(vp.guard_band_horz_clip, *reinterpret_cast(&value), + vp.guard_band_horz_discard, vp.guard_band_vert_discard); }; g_hw_ctx_indirect_func[Pm4::PA_CL_GB_VERT_DISC_ADJ] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto vp = cp->GetCtx()->GetScreenViewport(); - cp->GetCtx()->SetGuardBands(vp.guard_band_horz_clip, vp.guard_band_vert_clip, - vp.guard_band_horz_discard, - *reinterpret_cast(&value)); + auto vp = cp.GetCtx().GetScreenViewport(); + cp.GetCtx().SetGuardBands(vp.guard_band_horz_clip, vp.guard_band_vert_clip, + vp.guard_band_horz_discard, + *reinterpret_cast(&value)); }; g_hw_ctx_indirect_func[Pm4::PA_CL_GB_HORZ_CLIP_ADJ] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto vp = cp->GetCtx()->GetScreenViewport(); - cp->GetCtx()->SetGuardBands(*reinterpret_cast(&value), - vp.guard_band_vert_clip, vp.guard_band_horz_discard, - vp.guard_band_vert_discard); + auto vp = cp.GetCtx().GetScreenViewport(); + cp.GetCtx().SetGuardBands(*reinterpret_cast(&value), vp.guard_band_vert_clip, + vp.guard_band_horz_discard, vp.guard_band_vert_discard); }; g_hw_ctx_indirect_func[Pm4::PA_CL_GB_HORZ_DISC_ADJ] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto vp = cp->GetCtx()->GetScreenViewport(); - cp->GetCtx()->SetGuardBands(vp.guard_band_horz_clip, vp.guard_band_vert_clip, - *reinterpret_cast(&value), - vp.guard_band_vert_discard); + auto vp = cp.GetCtx().GetScreenViewport(); + cp.GetCtx().SetGuardBands(vp.guard_band_horz_clip, vp.guard_band_vert_clip, + *reinterpret_cast(&value), + vp.guard_band_vert_discard); }; for (auto cmd_offset = Pm4::CB_BLEND_RED; cmd_offset <= Pm4::CB_BLEND_ALPHA; cmd_offset++) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto color = cp->GetCtx()->GetBlendColor(); + auto color = cp.GetCtx().GetBlendColor(); auto f = *reinterpret_cast(&value); switch (cmd_offset) { case Pm4::CB_BLEND_RED: color.red = f; break; @@ -3688,7 +3678,7 @@ void GraphicsInitJmpTablesCxIndirect() { case Pm4::CB_BLEND_ALPHA: color.alpha = f; break; default: break; } - cp->GetCtx()->SetBlendColor(color); + cp.GetCtx().SetBlendColor(color); }; } g_hw_ctx_indirect_func[Pm4::CB_DCC_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -3726,70 +3716,70 @@ void GraphicsInitJmpTablesCxIndirect() { }; g_hw_ctx_indirect_func[Pm4::SPI_VS_OUT_CONFIG] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetVsOutConfig(value); + cp.GetCtx().SetVsOutConfig(value); }; g_hw_ctx_indirect_func[Pm4::SPI_SHADER_POS_FORMAT] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetShaderPosFormat(value); + cp.GetCtx().SetShaderPosFormat(value); }; g_hw_ctx_indirect_func[Pm4::SPI_SHADER_IDX_FORMAT] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetShaderIdxFormat(value); + cp.GetCtx().SetShaderIdxFormat(value); }; g_hw_ctx_indirect_func[Pm4::SPI_TMPRING_SIZE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { HwCtxIgnoreSpiTmpringSize(value); }; g_hw_ctx_indirect_func[Pm4::PA_CL_VS_OUT_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetClVsOutCntl(value); + cp.GetCtx().SetClVsOutCntl(value); }; g_hw_ctx_indirect_func[Pm4::GE_NGG_SUBGRP_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetNggSubgrpCntl(value); + cp.GetCtx().SetNggSubgrpCntl(value); }; g_hw_ctx_indirect_func[Pm4::VGT_GS_INSTANCE_CNT] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetGsInstanceCnt(value); + cp.GetCtx().SetGsInstanceCnt(value); }; g_hw_ctx_indirect_func[Pm4::VGT_GS_ONCHIP_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetGsOnchipCntl(value); + cp.GetCtx().SetGsOnchipCntl(value); }; g_hw_ctx_indirect_func[Pm4::VGT_HOS_MAX_TESS_LEVEL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetHosMaxTessLevel(value); + cp.GetCtx().SetHosMaxTessLevel(value); }; g_hw_ctx_indirect_func[Pm4::VGT_HOS_MIN_TESS_LEVEL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetHosMinTessLevel(value); + cp.GetCtx().SetHosMinTessLevel(value); }; g_hw_ctx_indirect_func[Pm4::GE_MAX_OUTPUT_PER_SUBGROUP] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetMaxOutputPerSubgroup(value); + cp.GetCtx().SetMaxOutputPerSubgroup(value); }; g_hw_ctx_indirect_func[Pm4::VGT_ESGS_RING_ITEMSIZE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetEsgsRingItemsize(value); + cp.GetCtx().SetEsgsRingItemsize(value); }; g_hw_ctx_indirect_func[Pm4::VGT_GS_MAX_VERT_OUT] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetGsMaxVertOut(value); + cp.GetCtx().SetGsMaxVertOut(value); }; g_hw_ctx_indirect_func[Pm4::VGT_PRIMITIVEID_EN] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetPrimitiveIdEn(value); + cp.GetCtx().SetPrimitiveIdEn(value); }; g_hw_ctx_indirect_func[Pm4::VGT_REUSE_OFF] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetReuseOff(value); + cp.GetCtx().SetReuseOff(value); }; g_hw_ctx_indirect_func[Pm4::VGT_MULTI_PRIM_IB_RESET_INDX] = [](KYTY_HW_CTX_INDIRECT_ARGS) { HwIgnoreMultiPrimIbReset(value); }; g_hw_ctx_indirect_func[Pm4::VGT_TESS_DISTRIBUTION] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetTessDistribution(value); + cp.GetCtx().SetTessDistribution(value); }; g_hw_ctx_indirect_func[Pm4::VGT_SHADER_STAGES_EN] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetShaderStages(value); + cp.GetCtx().SetShaderStages(value); }; g_hw_ctx_indirect_func[Pm4::VGT_LS_HS_CONFIG] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetLsHsConfig(value); + cp.GetCtx().SetLsHsConfig(value); }; g_hw_ctx_indirect_func[Pm4::VGT_GS_OUT_PRIM_TYPE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetGsOutPrimType(value); + cp.GetCtx().SetGsOutPrimType(value); }; g_hw_ctx_indirect_func[Pm4::VGT_TF_PARAM] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetTfParam(value); + cp.GetCtx().SetTfParam(value); }; g_hw_ctx_indirect_func[Pm4::VGT_DRAW_PAYLOAD_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { HwCtxIgnoreDrawPayloadControl(value); @@ -3798,7 +3788,7 @@ void GraphicsInitJmpTablesCxIndirect() { HwCtxIgnorePrimitiveIdReset(value); }; g_hw_ctx_indirect_func[Pm4::SPI_SHADER_Z_FORMAT] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetShaderZFormat(value); + cp.GetCtx().SetShaderZFormat(value); }; g_hw_ctx_indirect_func[Pm4::PA_CL_OBJPRIM_ID_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { HwCtxIgnoreObjprimIdControl(value); @@ -3807,27 +3797,27 @@ void GraphicsInitJmpTablesCxIndirect() { for (auto cmd_offset = Pm4::PA_SC_CLIPRECT_RULE; cmd_offset < Pm4::PA_SC_CLIPRECT_0_TL + 8u; cmd_offset++) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - HwCtxSetClipRectRegister(cp->GetCtx(), cmd_offset, value); + HwCtxSetClipRectRegister(cp, cmd_offset, value); }; } g_hw_ctx_indirect_func[Pm4::SPI_SHADER_COL_FORMAT] = [](KYTY_HW_CTX_INDIRECT_ARGS) { for (uint32_t i = 0; i < 8; i++) { - cp->GetCtx()->SetTargetOutputMode(i, (value >> (i * 4)) & 0xFu); + cp.GetCtx().SetTargetOutputMode(i, (value >> (i * 4)) & 0xFu); } }; g_hw_ctx_indirect_func[Pm4::SPI_PS_INPUT_ENA] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetPsInputEna(value); + cp.GetCtx().SetPsInputEna(value); }; g_hw_ctx_indirect_func[Pm4::SPI_PS_INPUT_ADDR] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetPsInputAddr(value); + cp.GetCtx().SetPsInputAddr(value); }; g_hw_ctx_indirect_func[Pm4::SPI_PS_IN_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetPsInControl(value); + cp.GetCtx().SetPsInControl(value); }; g_hw_ctx_indirect_func[Pm4::SPI_BARYC_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetBarycCntl(value); + cp.GetCtx().SetBarycCntl(value); }; g_hw_ctx_indirect_func[Pm4::DB_SHADER_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -3848,65 +3838,63 @@ void GraphicsInitJmpTablesCxIndirect() { KYTY_PM4_GET(value, DB_SHADER_CONTROL, EXEC_ON_NOOP) != 0; db_shader_control.alpha_to_mask_disable = KYTY_PM4_GET(value, DB_SHADER_CONTROL, ALPHA_TO_MASK_DISABLE) != 0; - cp->GetCtx()->SetDepthShaderControl(db_shader_control); + cp.GetCtx().SetDepthShaderControl(db_shader_control); }; g_hw_ctx_indirect_func[Pm4::CB_SHADER_MASK] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetShaderMask(value); + cp.GetCtx().SetShaderMask(value); }; g_hw_ctx_indirect_func[Pm4::PA_SC_SHADER_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetScShaderControl(value); + cp.GetCtx().SetScShaderControl(value); }; g_hw_ctx_indirect_func[Pm4::CB_TARGET_MASK] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetRenderTargetMask(value); + cp.GetCtx().SetRenderTargetMask(value); }; g_hw_ctx_indirect_func[Pm4::PA_SC_SCREEN_SCISSOR_TL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - const auto& vp = cp->GetCtx()->GetScreenViewport(); + const auto& vp = cp.GetCtx().GetScreenViewport(); int left = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_SCREEN_SCISSOR_TL, TL_X))); int top = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_SCREEN_SCISSOR_TL, TL_Y))); - cp->GetCtx()->SetScreenScissor(left, top, vp.screen_scissor_right, - vp.screen_scissor_bottom); + cp.GetCtx().SetScreenScissor(left, top, vp.screen_scissor_right, vp.screen_scissor_bottom); }; g_hw_ctx_indirect_func[Pm4::PA_SC_SCREEN_SCISSOR_BR] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - const auto& vp = cp->GetCtx()->GetScreenViewport(); + const auto& vp = cp.GetCtx().GetScreenViewport(); int right = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_SCREEN_SCISSOR_BR, BR_X))); int bottom = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_SCREEN_SCISSOR_BR, BR_Y))); - cp->GetCtx()->SetScreenScissor(vp.screen_scissor_left, vp.screen_scissor_top, right, - bottom); + cp.GetCtx().SetScreenScissor(vp.screen_scissor_left, vp.screen_scissor_top, right, bottom); }; g_hw_ctx_indirect_func[Pm4::PA_SC_GENERIC_SCISSOR_TL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - const auto& vp = cp->GetCtx()->GetScreenViewport(); + const auto& vp = cp.GetCtx().GetScreenViewport(); int left = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_GENERIC_SCISSOR_TL, TL_X))); int top = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_GENERIC_SCISSOR_TL, TL_Y))); bool window_offset_disable = KYTY_PM4_GET(value, PA_SC_GENERIC_SCISSOR_TL, WINDOW_OFFSET_DISABLE) != 0; - cp->GetCtx()->SetGenericScissor(left, top, vp.generic_scissor_right, - vp.generic_scissor_bottom, !window_offset_disable); + cp.GetCtx().SetGenericScissor(left, top, vp.generic_scissor_right, + vp.generic_scissor_bottom, !window_offset_disable); }; g_hw_ctx_indirect_func[Pm4::PA_SC_GENERIC_SCISSOR_BR] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - const auto& vp = cp->GetCtx()->GetScreenViewport(); + const auto& vp = cp.GetCtx().GetScreenViewport(); int right = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_GENERIC_SCISSOR_BR, BR_X))); int bottom = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_GENERIC_SCISSOR_BR, BR_Y))); - cp->GetCtx()->SetGenericScissor(vp.generic_scissor_left, vp.generic_scissor_top, right, - bottom, vp.generic_scissor_window_offset_enable); + cp.GetCtx().SetGenericScissor(vp.generic_scissor_left, vp.generic_scissor_top, right, + bottom, vp.generic_scissor_window_offset_enable); }; g_hw_ctx_indirect_func[Pm4::PA_SU_HARDWARE_SCREEN_OFFSET] = [](KYTY_HW_CTX_INDIRECT_ARGS) { uint32_t x = KYTY_PM4_GET(value, PA_SU_HARDWARE_SCREEN_OFFSET, HW_SCREEN_OFFSET_X); uint32_t y = KYTY_PM4_GET(value, PA_SU_HARDWARE_SCREEN_OFFSET, HW_SCREEN_OFFSET_Y); - cp->GetCtx()->SetHardwareScreenOffset(x, y); + cp.GetCtx().SetHardwareScreenOffset(x, y); }; g_hw_ctx_indirect_func[Pm4::PA_SC_WINDOW_OFFSET] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -3915,29 +3903,29 @@ void GraphicsInitJmpTablesCxIndirect() { int offset_y = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_WINDOW_OFFSET, WINDOW_Y))); - cp->GetCtx()->SetWindowOffset(offset_x, offset_y); + cp.GetCtx().SetWindowOffset(offset_x, offset_y); }; g_hw_ctx_indirect_func[Pm4::PA_SC_WINDOW_SCISSOR_TL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - const auto& vp = cp->GetCtx()->GetScreenViewport(); + const auto& vp = cp.GetCtx().GetScreenViewport(); int left = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_WINDOW_SCISSOR_TL, TL_X))); int top = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_WINDOW_SCISSOR_TL, TL_Y))); bool window_offset_disable = KYTY_PM4_GET(value, PA_SC_WINDOW_SCISSOR_TL, WINDOW_OFFSET_DISABLE) != 0; - cp->GetCtx()->SetWindowScissor(left, top, vp.window_scissor_right, vp.window_scissor_bottom, - !window_offset_disable); + cp.GetCtx().SetWindowScissor(left, top, vp.window_scissor_right, vp.window_scissor_bottom, + !window_offset_disable); }; g_hw_ctx_indirect_func[Pm4::PA_SC_WINDOW_SCISSOR_BR] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - const auto& vp = cp->GetCtx()->GetScreenViewport(); + const auto& vp = cp.GetCtx().GetScreenViewport(); int right = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_WINDOW_SCISSOR_BR, BR_X))); int bottom = static_cast( static_cast(KYTY_PM4_GET(value, PA_SC_WINDOW_SCISSOR_BR, BR_Y))); - cp->GetCtx()->SetWindowScissor(vp.window_scissor_left, vp.window_scissor_top, right, bottom, - vp.window_scissor_window_offset_enable); + cp.GetCtx().SetWindowScissor(vp.window_scissor_left, vp.window_scissor_top, right, bottom, + vp.window_scissor_window_offset_enable); }; for (uint32_t slot = 0; slot < 8; slot++) { @@ -3955,7 +3943,7 @@ void GraphicsInitJmpTablesCxIndirect() { KYTY_PM4_GET(value, CB_BLEND0_CONTROL, SEPARATE_ALPHA_BLEND) != 0; r.enable = KYTY_PM4_GET(value, CB_BLEND0_CONTROL, ENABLE) != 0; - cp->GetCtx()->SetBlendControl(param, r); + cp.GetCtx().SetBlendControl(param, r); }; } @@ -3975,7 +3963,7 @@ void GraphicsInitJmpTablesCxIndirect() { KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, VTX_WINDOW_OFFSET_ENABLE) != 0; r.provoking_vtx_last = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, PROVOKING_VTX_LAST) != 0; r.persp_corr_dis = KYTY_PM4_GET(value, PA_SU_SC_MODE_CNTL, PERSP_CORR_DIS) != 0; - cp->GetCtx()->SetModeControl(r); + cp.GetCtx().SetModeControl(r); }; g_hw_ctx_indirect_func[Pm4::PA_SU_POLY_OFFSET_DB_FMT_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4009,11 +3997,11 @@ void GraphicsInitJmpTablesCxIndirect() { r.expclear_enabled = KYTY_PM4_GET(value, DB_Z_INFO, ALLOW_EXPCLEAR) != 0; r.tile_surface_enable = KYTY_PM4_GET(value, DB_Z_INFO, TILE_SURFACE_ENABLE) != 0; r.zrange_precision = KYTY_PM4_GET(value, DB_Z_INFO, ZRANGE_PRECISION); - cp->GetCtx()->SetDepthZInfo(r); + cp.GetCtx().SetDepthZInfo(r); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto z = cp->GetCtx()->GetDepthRenderTarget(); + auto z = cp.GetCtx().GetDepthRenderTarget(); z.depth_info.addr5_swizzle_mask = KYTY_PM4_GET(value, DB_DEPTH_INFO, ADDR5_SWIZZLE_MASK); z.depth_info.array_mode = (value >> Pm4::DB_DEPTH_INFO_ARRAY_MODE_SHIFT) & Pm4::DB_DEPTH_INFO_ARRAY_MODE_MASK; @@ -4026,14 +4014,14 @@ void GraphicsInitJmpTablesCxIndirect() { z.depth_info.macro_tile_aspect = KYTY_PM4_GET(value, DB_DEPTH_INFO, MACRO_TILE_ASPECT); z.depth_info.num_banks = (value >> Pm4::DB_DEPTH_INFO_NUM_BANKS_SHIFT) & Pm4::DB_DEPTH_INFO_NUM_BANKS_MASK; - cp->GetCtx()->SetDepthRenderTarget(z); + cp.GetCtx().SetDepthRenderTarget(z); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_BOUNDS_MIN] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - HwCtxSetDepthBoundsRegister(cp->GetCtx(), cmd_offset, value); + HwCtxSetDepthBoundsRegister(cp, cmd_offset, value); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_BOUNDS_MAX] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - HwCtxSetDepthBoundsRegister(cp->GetCtx(), cmd_offset, value); + HwCtxSetDepthBoundsRegister(cp, cmd_offset, value); }; g_hw_ctx_indirect_func[Pm4::DB_STENCIL_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4045,81 +4033,81 @@ void GraphicsInitJmpTablesCxIndirect() { r.tile_mode_index = KYTY_PM4_GET(value, DB_STENCIL_INFO, TILE_MODE_INDEX); r.expclear_enabled = KYTY_PM4_GET(value, DB_STENCIL_INFO, ALLOW_EXPCLEAR) != 0; r.tile_stencil_disable = KYTY_PM4_GET(value, DB_STENCIL_INFO, TILE_STENCIL_DISABLE) != 0; - cp->GetCtx()->SetDepthStencilInfo(r); + cp.GetCtx().SetDepthStencilInfo(r); }; g_hw_ctx_indirect_func[Pm4::DB_Z_READ_BASE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().z_read_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().z_read_base_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetCtx()->SetDepthZReadBase(base); + cp.GetCtx().SetDepthZReadBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_Z_READ_BASE_HI] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().z_read_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().z_read_base_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetDepthZReadBase(base); + cp.GetCtx().SetDepthZReadBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_STENCIL_READ_BASE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().stencil_read_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().stencil_read_base_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetCtx()->SetDepthStencilReadBase(base); + cp.GetCtx().SetDepthStencilReadBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_STENCIL_READ_BASE_HI] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().stencil_read_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().stencil_read_base_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetDepthStencilReadBase(base); + cp.GetCtx().SetDepthStencilReadBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_Z_WRITE_BASE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().z_write_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().z_write_base_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetCtx()->SetDepthZWriteBase(base); + cp.GetCtx().SetDepthZWriteBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_Z_WRITE_BASE_HI] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().z_write_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().z_write_base_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetDepthZWriteBase(base); + cp.GetCtx().SetDepthZWriteBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_STENCIL_WRITE_BASE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().stencil_write_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().stencil_write_base_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetCtx()->SetDepthStencilWriteBase(base); + cp.GetCtx().SetDepthStencilWriteBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_STENCIL_WRITE_BASE_HI] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().stencil_write_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().stencil_write_base_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetDepthStencilWriteBase(base); + cp.GetCtx().SetDepthStencilWriteBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_HTILE_DATA_BASE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().htile_data_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().htile_data_base_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetCtx()->SetDepthHTileDataBase(base); + cp.GetCtx().SetDepthHTileDataBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_HTILE_DATA_BASE_HI] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto base = cp->GetCtx()->GetDepthRenderTarget().htile_data_base_addr; + auto base = cp.GetCtx().GetDepthRenderTarget().htile_data_base_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetCtx()->SetDepthHTileDataBase(base); + cp.GetCtx().SetDepthHTileDataBase(base); }; g_hw_ctx_indirect_func[Pm4::DB_HTILE_SURFACE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - HwCtxSetDepthHtileSurfaceRegister(cp->GetCtx(), value); + HwCtxSetDepthHtileSurfaceRegister(cp, value); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_VIEW] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4131,7 +4119,7 @@ void GraphicsInitJmpTablesCxIndirect() { r.depth_write_disable = KYTY_PM4_GET(value, DB_DEPTH_VIEW, Z_READ_ONLY) != 0; r.stencil_write_disable = KYTY_PM4_GET(value, DB_DEPTH_VIEW, STENCIL_READ_ONLY) != 0; r.current_mip_level = KYTY_PM4_GET(value, DB_DEPTH_VIEW, MIPID); - cp->GetCtx()->SetDepthDepthView(r); + cp.GetCtx().SetDepthDepthView(r); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_SIZE_XY] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4139,26 +4127,26 @@ void GraphicsInitJmpTablesCxIndirect() { r.x_max = KYTY_PM4_GET(value, DB_DEPTH_SIZE_XY, X_MAX); r.y_max = KYTY_PM4_GET(value, DB_DEPTH_SIZE_XY, Y_MAX); r.valid = true; - cp->GetCtx()->SetDepthDepthSizeXY(r); + cp.GetCtx().SetDepthDepthSizeXY(r); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_SIZE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto target = cp->GetCtx()->GetDepthRenderTarget(); + auto target = cp.GetCtx().GetDepthRenderTarget(); target.pitch_div8_minus1 = KYTY_PM4_GET(value, DB_DEPTH_SIZE, PITCH_TILE_MAX); target.height_div8_minus1 = KYTY_PM4_GET(value, DB_DEPTH_SIZE, HEIGHT_TILE_MAX); target.pitch_height_valid = true; - cp->GetCtx()->SetDepthRenderTarget(target); + cp.GetCtx().SetDepthRenderTarget(target); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_SLICE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto target = cp->GetCtx()->GetDepthRenderTarget(); + auto target = cp.GetCtx().GetDepthRenderTarget(); target.slice_div64_minus1 = KYTY_PM4_GET(value, DB_DEPTH_SLICE, SLICE_TILE_MAX); - cp->GetCtx()->SetDepthRenderTarget(target); + cp.GetCtx().SetDepthRenderTarget(target); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_CLEAR] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetDepthClearValue(*reinterpret_cast(&value)); + cp.GetCtx().SetDepthClearValue(*reinterpret_cast(&value)); }; g_hw_ctx_indirect_func[Pm4::DB_STENCIL_CLEAR] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetStencilClearValue(KYTY_PM4_GET(value, DB_STENCIL_CLEAR, CLEAR)); + cp.GetCtx().SetStencilClearValue(KYTY_PM4_GET(value, DB_STENCIL_CLEAR, CLEAR)); }; g_hw_ctx_indirect_func[Pm4::DB_STENCIL_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4169,7 +4157,7 @@ void GraphicsInitJmpTablesCxIndirect() { r.stencil_fail_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILFAIL_BF); r.stencil_zpass_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZPASS_BF); r.stencil_zfail_bf = KYTY_PM4_GET(value, DB_STENCIL_CONTROL, STENCILZFAIL_BF); - cp->GetCtx()->SetStencilControl(r); + cp.GetCtx().SetStencilControl(r); }; g_hw_ctx_indirect_func[Pm4::DB_RENDER_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4183,25 +4171,25 @@ void GraphicsInitJmpTablesCxIndirect() { KYTY_PM4_GET(value, DB_RENDER_CONTROL, DEPTH_COMPRESS_DISABLE) != 0; r.copy_centroid = KYTY_PM4_GET(value, DB_RENDER_CONTROL, COPY_CENTROID) != 0; r.copy_sample = KYTY_PM4_GET(value, DB_RENDER_CONTROL, COPY_SAMPLE); - cp->GetCtx()->SetRenderControl(r); + cp.GetCtx().SetRenderControl(r); }; g_hw_ctx_indirect_func[Pm4::DB_STENCILREFMASK] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto r = cp->GetCtx()->GetStencilMask(); + auto r = cp.GetCtx().GetStencilMask(); r.stencil_testval = KYTY_PM4_GET(value, DB_STENCILREFMASK, STENCILTESTVAL); r.stencil_mask = KYTY_PM4_GET(value, DB_STENCILREFMASK, STENCILMASK); r.stencil_writemask = KYTY_PM4_GET(value, DB_STENCILREFMASK, STENCILWRITEMASK); r.stencil_opval = KYTY_PM4_GET(value, DB_STENCILREFMASK, STENCILOPVAL); - cp->GetCtx()->SetStencilMask(r); + cp.GetCtx().SetStencilMask(r); }; g_hw_ctx_indirect_func[Pm4::DB_STENCILREFMASK_BF] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto r = cp->GetCtx()->GetStencilMask(); + auto r = cp.GetCtx().GetStencilMask(); r.stencil_testval_bf = KYTY_PM4_GET(value, DB_STENCILREFMASK_BF, STENCILTESTVAL_BF); r.stencil_mask_bf = KYTY_PM4_GET(value, DB_STENCILREFMASK_BF, STENCILMASK_BF); r.stencil_writemask_bf = KYTY_PM4_GET(value, DB_STENCILREFMASK_BF, STENCILWRITEMASK_BF); r.stencil_opval_bf = KYTY_PM4_GET(value, DB_STENCILREFMASK_BF, STENCILOPVAL_BF); - cp->GetCtx()->SetStencilMask(r); + cp.GetCtx().SetStencilMask(r); }; g_hw_ctx_indirect_func[Pm4::PA_CL_CLIP_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4221,12 +4209,12 @@ void GraphicsInitJmpTablesCxIndirect() { KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, DX_LINEAR_ATTR_CLIP_ENA) != 0; r.force_viewport_index_from_vs_enable = KYTY_PM4_GET(value, PA_CL_CLIP_CNTL, VTE_VPORT_PROVOKE_DISABLE) != 0; - cp->GetCtx()->SetClipControl(r); + cp.GetCtx().SetClipControl(r); }; g_hw_ctx_indirect_func[Pm4::PA_SU_LINE_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { auto line_width = KYTY_PM4_GET(value, PA_SU_LINE_CNTL, WIDTH); - cp->GetCtx()->SetLineWidth(line_width == 8 ? 1.0f : static_cast(line_width) / 8.0f); + cp.GetCtx().SetLineWidth(line_width == 8 ? 1.0f : static_cast(line_width) / 8.0f); }; g_hw_ctx_indirect_func[Pm4::PA_SC_FOV_WINDOW_LR] = [](KYTY_HW_CTX_INDIRECT_ARGS) { HwCtxIgnoreFovWindow(value); @@ -4245,7 +4233,7 @@ void GraphicsInitJmpTablesCxIndirect() { }; g_hw_ctx_indirect_func[Pm4::PA_CL_VTE_CNTL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetViewportTransformControl(value); + cp.GetCtx().SetViewportTransformControl(value); }; g_hw_ctx_indirect_func[Pm4::PA_SC_MODE_CNTL_0] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4253,36 +4241,36 @@ void GraphicsInitJmpTablesCxIndirect() { r.msaa_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, MSAA_ENABLE) != 0; r.vport_scissor_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, VPORT_SCISSOR_ENABLE) != 0; r.line_stipple_enable = KYTY_PM4_GET(value, PA_SC_MODE_CNTL_0, LINE_STIPPLE_ENABLE) != 0; - cp->GetCtx()->SetScanModeControl(r); + cp.GetCtx().SetScanModeControl(r); }; g_hw_ctx_indirect_func[Pm4::PA_SC_MODE_CNTL_1] = [](KYTY_HW_CTX_INDIRECT_ARGS) { HwCtxIgnoreScanModeControl1(value); }; g_hw_ctx_indirect_func[Pm4::PA_SC_AA_CONFIG] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetAaConfig(ParseAaConfig(value)); + cp.GetCtx().SetAaConfig(ParseAaConfig(value)); }; for (auto cmd_offset = Pm4::PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0; cmd_offset < Pm4::PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 + 16; cmd_offset++) { g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto r = cp->GetCtx()->GetAaSampleControl(); + auto r = cp.GetCtx().GetAaSampleControl(); r.locations[cmd_offset - Pm4::PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0] = value; - cp->GetCtx()->SetAaSampleControl(r); + cp.GetCtx().SetAaSampleControl(r); }; } g_hw_ctx_indirect_func[Pm4::PA_SC_CENTROID_PRIORITY_0] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto r = cp->GetCtx()->GetAaSampleControl(); + auto r = cp.GetCtx().GetAaSampleControl(); r.centroid_priority = (r.centroid_priority & 0xffffffff00000000ull) | value; - cp->GetCtx()->SetAaSampleControl(r); + cp.GetCtx().SetAaSampleControl(r); }; g_hw_ctx_indirect_func[Pm4::PA_SC_CENTROID_PRIORITY_1] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - auto r = cp->GetCtx()->GetAaSampleControl(); + auto r = cp.GetCtx().GetAaSampleControl(); r.centroid_priority = (r.centroid_priority & 0x00000000ffffffffull) | (static_cast(value) << 32u); - cp->GetCtx()->SetAaSampleControl(r); + cp.GetCtx().SetAaSampleControl(r); }; g_hw_ctx_indirect_func[Pm4::PA_SC_AA_MASK_X0Y0_X1Y0] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4315,7 +4303,7 @@ void GraphicsInitJmpTablesCxIndirect() { HW::ColorControl r; r.mode = KYTY_PM4_GET(value, CB_COLOR_CONTROL, MODE); r.op = KYTY_PM4_GET(value, CB_COLOR_CONTROL, ROP3); - cp->GetCtx()->SetColorControl(r); + cp.GetCtx().SetColorControl(r); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -4332,11 +4320,11 @@ void GraphicsInitJmpTablesCxIndirect() { KYTY_PM4_GET(value, DB_DEPTH_CONTROL, ENABLE_COLOR_WRITES_ON_DEPTH_FAIL) != 0; r.color_writes_on_depth_pass_disable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, DISABLE_COLOR_WRITES_ON_DEPTH_PASS) != 0; - cp->GetCtx()->SetDepthControl(r); + cp.GetCtx().SetDepthControl(r); }; g_hw_ctx_indirect_func[Pm4::DB_EQAA] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - cp->GetCtx()->SetEqaaControl(ParseEqaaControl(value)); + cp.GetCtx().SetEqaaControl(ParseEqaaControl(value)); }; } @@ -4418,55 +4406,55 @@ void GraphicsInitJmpTablesShIndirect() { for (uint32_t slot = 0; slot < 16; slot++) { g_hw_sh_indirect_func[Pm4::COMPUTE_USER_DATA_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) { auto sgpr = cmd_offset - Pm4::COMPUTE_USER_DATA_0; - cp->GetShCtx()->SetCsUserSgpr(sgpr, value, cp->GetUserDataMarker()); - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.GetShCtx().SetCsUserSgpr(sgpr, value, cp.GetUserDataMarker()); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); }; } for (uint32_t slot = 0; Pm4::COMPUTE_USER_ACCUM_0 + slot < Pm4::COMPUTE_USER_DATA_0; slot++) { g_hw_sh_indirect_func[Pm4::COMPUTE_USER_ACCUM_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) { auto sgpr = 16u + (cmd_offset - Pm4::COMPUTE_USER_ACCUM_0); - cp->GetShCtx()->SetCsUserSgpr(sgpr, value, cp->GetUserDataMarker()); - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.GetShCtx().SetCsUserSgpr(sgpr, value, cp.GetUserDataMarker()); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); }; } for (uint32_t slot = 0; slot < 32; slot++) { g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_DATA_PS_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) { auto sgpr = cmd_offset - Pm4::SPI_SHADER_USER_DATA_PS_0; - cp->GetShCtx()->SetPsUserSgpr(sgpr, value, cp->GetUserDataMarker()); - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.GetShCtx().SetPsUserSgpr(sgpr, value, cp.GetUserDataMarker()); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_DATA_GS_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) { auto sgpr = cmd_offset - Pm4::SPI_SHADER_USER_DATA_GS_0; - cp->GetShCtx()->SetGsUserSgpr(sgpr, value, cp->GetUserDataMarker()); - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.GetShCtx().SetGsUserSgpr(sgpr, value, cp.GetUserDataMarker()); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_DATA_HS_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) { auto sgpr = cmd_offset - Pm4::SPI_SHADER_USER_DATA_HS_0; - cp->GetShCtx()->SetHsUserSgpr(sgpr, value, cp->GetUserDataMarker()); - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.GetShCtx().SetHsUserSgpr(sgpr, value, cp.GetUserDataMarker()); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); }; } for (uint32_t slot = 0; slot < 4; slot++) { g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_ACCUM_PS_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) { auto sgpr = 16u + (cmd_offset - Pm4::SPI_SHADER_USER_ACCUM_PS_0); - cp->GetShCtx()->SetPsUserSgpr(sgpr, value, cp->GetUserDataMarker()); - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.GetShCtx().SetPsUserSgpr(sgpr, value, cp.GetUserDataMarker()); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_ACCUM_ESGS_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) { auto sgpr = 16u + (cmd_offset - Pm4::SPI_SHADER_USER_ACCUM_ESGS_0); - cp->GetShCtx()->SetGsUserSgpr(sgpr, value, cp->GetUserDataMarker()); - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.GetShCtx().SetGsUserSgpr(sgpr, value, cp.GetUserDataMarker()); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_ACCUM_LSHS_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) { auto sgpr = 16u + (cmd_offset - Pm4::SPI_SHADER_USER_ACCUM_LSHS_0); - cp->GetShCtx()->SetHsUserSgpr(sgpr, value, cp->GetUserDataMarker()); - cp->SetUserDataMarker(HW::UserSgprType::Unknown); + cp.GetShCtx().SetHsUserSgpr(sgpr, value, cp.GetUserDataMarker()); + cp.SetUserDataMarker(HW::UserSgprType::Unknown); }; } g_hw_sh_indirect_func[Pm4::SPI_SHADER_TBA_LO_PS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4518,21 +4506,21 @@ void GraphicsInitJmpTablesShIndirect() { HwShIgnoreShaderRegister(cmd_offset, value); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_LO_HS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetVs().hs_regs.data_addr; + auto base = cp.GetShCtx().GetVs().hs_regs.data_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetShCtx()->SetHsShaderBase(base); + cp.GetShCtx().SetHsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_HI_HS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetVs().hs_regs.data_addr; + auto base = cp.GetShCtx().GetVs().hs_regs.data_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetShCtx()->SetHsShaderBase(base); + cp.GetShCtx().SetHsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_CHKSUM_HS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - cp->GetShCtx()->SetHsShaderChksum(value); + cp.GetShCtx().SetHsShaderChksum(value); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_RSRC1_HS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4548,7 +4536,7 @@ void GraphicsInitJmpTablesShIndirect() { r1.require_forward_progress = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_VS, FWD_PROGRESS) != 0; r1.fp16_overflow = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_VS, FP16_OVFL) != 0; - cp->GetShCtx()->SetHsShaderResource1(r1); + cp.GetShCtx().SetHsShaderResource1(r1); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_RSRC2_HS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4559,21 +4547,21 @@ void GraphicsInitJmpTablesShIndirect() { r2.offchip_lds = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_VS, OC_LDS_EN) != 0; r2.streamout_enabled = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_VS, SO_EN) != 0; r2.shared_vgprs = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_VS, SHARED_VGPR_CNT); - cp->GetShCtx()->SetHsShaderResource2(r2); + cp.GetShCtx().SetHsShaderResource2(r2); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_LO_LS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetVs().ls_regs.data_addr; + auto base = cp.GetShCtx().GetVs().ls_regs.data_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetShCtx()->SetLsShaderBase(base); + cp.GetShCtx().SetLsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_HI_LS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetVs().ls_regs.data_addr; + auto base = cp.GetShCtx().GetVs().ls_regs.data_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetShCtx()->SetLsShaderBase(base); + cp.GetShCtx().SetLsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_RSRC1_LS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4589,7 +4577,7 @@ void GraphicsInitJmpTablesShIndirect() { r1.require_forward_progress = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_VS, FWD_PROGRESS) != 0; r1.fp16_overflow = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_VS, FP16_OVFL) != 0; - cp->GetShCtx()->SetLsShaderResource1(r1); + cp.GetShCtx().SetLsShaderResource1(r1); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_RSRC2_LS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4600,38 +4588,38 @@ void GraphicsInitJmpTablesShIndirect() { r2.offchip_lds = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_VS, OC_LDS_EN) != 0; r2.streamout_enabled = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_VS, SO_EN) != 0; r2.shared_vgprs = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_VS, SHARED_VGPR_CNT); - cp->GetShCtx()->SetLsShaderResource2(r2); + cp.GetShCtx().SetLsShaderResource2(r2); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_LO_ES] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetVs().es_regs.data_addr; + auto base = cp.GetShCtx().GetVs().es_regs.data_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetShCtx()->SetEsShaderBase(base); + cp.GetShCtx().SetEsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_HI_ES] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetVs().es_regs.data_addr; + auto base = cp.GetShCtx().GetVs().es_regs.data_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetShCtx()->SetEsShaderBase(base); + cp.GetShCtx().SetEsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_LO_GS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetVs().gs_regs.data_addr; + auto base = cp.GetShCtx().GetVs().gs_regs.data_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetShCtx()->SetGsShaderBase(base); + cp.GetShCtx().SetGsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_HI_GS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetVs().gs_regs.data_addr; + auto base = cp.GetShCtx().GetVs().gs_regs.data_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetShCtx()->SetGsShaderBase(base); + cp.GetShCtx().SetGsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_CHKSUM_GS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - cp->GetShCtx()->SetGsShaderChksum(value); + cp.GetShCtx().SetGsShaderChksum(value); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_RSRC1_GS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4649,7 +4637,7 @@ void GraphicsInitJmpTablesShIndirect() { r1.lds_configuration = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_GS, WGP_MODE) != 0; r1.gs_vgpr_component_count = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_GS, GS_VGPR_COMP_CNT); r1.fp16_overflow = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_GS, FP16_OVFL) != 0; - cp->GetShCtx()->SetGsShaderResource1(r1); + cp.GetShCtx().SetGsShaderResource1(r1); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_RSRC2_GS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4661,25 +4649,25 @@ void GraphicsInitJmpTablesShIndirect() { r2.offchip_lds = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_GS, OC_LDS_EN) != 0; r2.lds_size = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_GS, LDS_SIZE); r2.shared_vgprs = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_GS, SHARED_VGPR_CNT); - cp->GetShCtx()->SetGsShaderResource2(r2); + cp.GetShCtx().SetGsShaderResource2(r2); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_LO_PS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetPs().ps_regs.data_addr; + auto base = cp.GetShCtx().GetPs().ps_regs.data_addr; base &= 0xFFFFFF00000000FFull; base |= static_cast(value) << 8u; - cp->GetShCtx()->SetPsShaderBase(base); + cp.GetShCtx().SetPsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_HI_PS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - auto base = cp->GetShCtx()->GetPs().ps_regs.data_addr; + auto base = cp.GetShCtx().GetPs().ps_regs.data_addr; base &= 0xFFFF00FFFFFFFFFFull; base |= (static_cast(value) & 0xffu) << 40u; - cp->GetShCtx()->SetPsShaderBase(base); + cp.GetShCtx().SetPsShaderBase(base); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_CHKSUM_PS] = [](KYTY_HW_SH_INDIRECT_ARGS) { - cp->GetShCtx()->SetPsShaderChksum(value); + cp.GetShCtx().SetPsShaderChksum(value); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_RSRC1_PS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4695,7 +4683,7 @@ void GraphicsInitJmpTablesShIndirect() { r1.require_forward_progress = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_PS, FWD_PROGRESS) != 0; r1.fp16_overflow = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC1_PS, FP16_OVFL) != 0; - cp->GetShCtx()->SetPsShaderResource1(r1); + cp.GetShCtx().SetPsShaderResource1(r1); }; g_hw_sh_indirect_func[Pm4::SPI_SHADER_PGM_RSRC2_PS] = [](KYTY_HW_SH_INDIRECT_ARGS) { @@ -4708,7 +4696,7 @@ void GraphicsInitJmpTablesShIndirect() { r2.raster_ordered_shading = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_PS, LOAD_INTRAWAVE_COLLISION); r2.shared_vgprs = KYTY_PM4_GET(value, SPI_SHADER_PGM_RSRC2_PS, SHARED_VGPR_CNT); - cp->GetShCtx()->SetPsShaderResource2(r2); + cp.GetShCtx().SetPsShaderResource2(r2); }; } @@ -4721,7 +4709,7 @@ void GraphicsInitJmpTablesUcIndirect() { HW::GeControl r; r.primitive_group_size = KYTY_PM4_GET(value, GE_CNTL, PRIM_GRP_SIZE); r.vertex_group_size = KYTY_PM4_GET(value, GE_CNTL, VERT_GRP_SIZE); - cp->GetUcfg()->SetGeControl(r); + cp.GetUcfg().SetGeControl(r); }; g_hw_uc_indirect_func[Pm4::GE_USER_VGPR_EN] = [](KYTY_HW_UC_INDIRECT_ARGS) { @@ -4729,18 +4717,18 @@ void GraphicsInitJmpTablesUcIndirect() { r.vgpr1 = KYTY_PM4_GET(value, GE_USER_VGPR_EN, EN_USER_VGPR1) != 0; r.vgpr2 = KYTY_PM4_GET(value, GE_USER_VGPR_EN, EN_USER_VGPR2) != 0; r.vgpr3 = KYTY_PM4_GET(value, GE_USER_VGPR_EN, EN_USER_VGPR3) != 0; - cp->GetUcfg()->SetGeUserVgprEn(r); + cp.GetUcfg().SetGeUserVgprEn(r); }; g_hw_uc_indirect_func[Pm4::VGT_PRIMITIVE_TYPE] = [](KYTY_HW_UC_INDIRECT_ARGS) { uint32_t prim_type = KYTY_PM4_GET(value, VGT_PRIMITIVE_TYPE, PRIM_TYPE); - cp->GetUcfg()->SetPrimitiveType(prim_type); + cp.GetUcfg().SetPrimitiveType(prim_type); }; g_hw_uc_indirect_func[Pm4::VGT_INDEX_TYPE] = [](KYTY_HW_UC_INDIRECT_ARGS) { - cp->SetIndexType(value & 0x3u); + cp.SetIndexType(value & 0x3u); }; g_hw_uc_indirect_func[Pm4::VGT_OBJECT_ID] = [](KYTY_HW_UC_INDIRECT_ARGS) { - cp->GetUcfg()->SetObjectId(value); + cp.GetUcfg().SetObjectId(value); }; g_hw_uc_indirect_func[Pm4::TEXTURE_GRADIENT_FACTORS] = [](KYTY_HW_UC_INDIRECT_ARGS) { HwUcIgnoreTextureGradientFactors(value); @@ -4759,7 +4747,7 @@ void GraphicsInitJmpTablesUcIndirect() { }; g_hw_uc_indirect_func[Pm4::GE_INDX_OFFSET] = [](KYTY_HW_UC_INDIRECT_ARGS) { - cp->GetUcfg()->SetIndexOffset(value); + cp.GetUcfg().SetIndexOffset(value); }; g_hw_uc_indirect_func[Pm4::GDS_OA_CNTL] = [](KYTY_HW_UC_INDIRECT_ARGS) { HwUcSetGdsOaRegister(cp, cmd_offset, value); diff --git a/src/graphics/guest_gpu/graphicsRun.cpp b/src/graphics/guest_gpu/graphicsRun.cpp index 00f2c6fd7..18d700703 100644 --- a/src/graphics/guest_gpu/graphicsRun.cpp +++ b/src/graphics/guest_gpu/graphicsRun.cpp @@ -122,8 +122,8 @@ public: void WaitForIdle(); bool IsIdle(); - void SetCp(CommandProcessor* cp) { - m_cp = cp; + void SetCp(CommandProcessor& cp) { + m_cp = &cp; Start(); } @@ -171,8 +171,8 @@ public: void WaitForIdle(); bool IsIdle(); - void SetCp(CommandProcessor* cp) { - m_cp = cp; + void SetCp(CommandProcessor& cp) { + m_cp = &cp; Start(); } @@ -382,7 +382,7 @@ void Gpu::Init() { m_gfx_cp = new CommandProcessor; m_gfx_ring = new GraphicsRing; m_gfx_cp->SetQueue(GraphicContext::QUEUE_GFX); - m_gfx_ring->SetCp(m_gfx_cp); + m_gfx_ring->SetCp(*m_gfx_cp); EXIT_IF(GraphicContext::QUEUE_COMPUTE_NUM < 8); } @@ -400,7 +400,7 @@ ComputeRing* Gpu::GetRing(uint32_t ring_id) { if (m_compute_ring[v] == nullptr) { m_compute_ring[v] = new ComputeRing; m_compute_ring[v]->SetQueueId(queue_id); - m_compute_ring[v]->SetCp(m_compute_cp[pipe_id]); + m_compute_ring[v]->SetCp(*m_compute_cp[pipe_id]); } return m_compute_ring[v]; @@ -475,14 +475,12 @@ void CommandProcessor::BufferFlush() { } void CommandProcessor::BufferFlushAndWait() { - CommandBuffer* submitted = nullptr; - - { + auto& submitted = [&]() -> CommandBuffer& { Common::LockGuard lock(m_mutex); - submitted = m_scheduler.FlushAndGetSubmitted(); - } + return m_scheduler.FlushAndGetSubmitted(); + }(); - submitted->WaitForFence(); + submitted.WaitForFence(); } void CommandProcessor::BufferWait() { @@ -493,7 +491,7 @@ void CommandProcessor::BufferWait() { std::array buffers {}; { Common::LockGuard lock(m_mutex); - m_scheduler.CopyBuffers(&buffers); + m_scheduler.CopyBuffers(buffers); } for (auto* buf: buffers) { @@ -691,14 +689,14 @@ void CommandProcessor::DmaData(uint8_t engine, uint8_t dst_sel, uint8_t dst_cach EXIT("unsupported dmaData destination selector 0x%02" PRIx8 "\n", dst_sel); } if (src_sel == 2) { - GetGpuResources()->FillBuffer( + GetGpuResources().FillBuffer( CurrentBuffer(), dst_address_or_offset, num_bytes, static_cast(src_address_or_offset_or_immediate & 0xffffffffu)); return; } if (src_memory) { - GetGpuResources()->CopyBuffer(CurrentBuffer(), dst_address_or_offset, - src_address_or_offset_or_immediate, num_bytes); + GetGpuResources().CopyBuffer(CurrentBuffer(), dst_address_or_offset, + src_address_or_offset_or_immediate, num_bytes); return; } EXIT("unsupported dmaData source selector 0x%02" PRIx8 "\n", src_sel); @@ -960,11 +958,11 @@ void CommandProcessor::Run(uint32_t* data, uint32_t num_dw) { KYTY_PROFILER_BLOCK("CommandProcessor::Run"); struct RunScope { - explicit RunScope(CommandProcessor* cp): prev(g_current_run_cp) { g_current_run_cp = cp; } + explicit RunScope(CommandProcessor& cp): prev(g_current_run_cp) { g_current_run_cp = &cp; } ~RunScope() { g_current_run_cp = prev; } CommandProcessor* prev; - } run_scope(this); + } run_scope(*this); auto* cmd = data; auto dw = num_dw; @@ -1033,7 +1031,7 @@ void CommandProcessor::Run(uint32_t* data, uint32_t num_dw) { EXIT("unknown op\n\t%05" PRIx32 ":\n\tcmd_id = %08" PRIx32 "\n", num_dw - dw, cmd_id); } - auto s = pfunc(this, cmd_id & ~1u, cmd, dw, num_dw); + auto s = pfunc(*this, cmd_id & ~1u, cmd, dw, num_dw); // LOGF("\t %05" PRIx32 ": %u\n", num_dw - dw, s); @@ -1142,9 +1140,9 @@ void CommandProcessor::DrawIndex(uint32_t index_count, const void* index_addr, u "\n", vertex_offset_add, first_instance); } - RenderDrawIndex(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, m_index_type_and_size, - index_count, index_addr, flags, type, instance_count, - render_target_slice_offset, vertex_offset_add, first_instance); + RenderDrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr, + flags, type, instance_count, render_target_slice_offset, vertex_offset_add, + first_instance); } void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_count, @@ -1164,8 +1162,8 @@ void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_cou auto* index_addr = reinterpret_cast( m_index_base_addr + static_cast(index_offset) * index_size); - RenderDrawIndex(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, m_index_type_and_size, - index_count, index_addr, flags, 1, m_num_instances); + RenderDrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr, + flags, 1, m_num_instances); } void CommandProcessor::DrawIndirect(uint32_t data_offset, uint32_t draw_initiator, bool indexed) { @@ -1393,8 +1391,8 @@ void CommandProcessor::DispatchDirect(uint32_t thread_group_x, uint32_t thread_g } } - RenderDispatchDirect(m_submit_id, CurrentBuffer(), &m_ctx, &m_sh_ctx, thread_group_x, - thread_group_y, thread_group_z, mode); + RenderDispatchDirect(m_submit_id, CurrentBuffer(), thread_group_x, thread_group_y, + thread_group_z, mode); } constexpr uint32_t DispatchInitiatorUseThreadDimensions = 1u << 5u; @@ -1442,9 +1440,8 @@ void CommandProcessor::DrawIndexAuto(uint32_t index_count, uint32_t flags, CheckBuffer(); - RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, index_count, - flags, render_target_slice_offset, instance_count, first_vertex, - first_instance); + RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), index_count, flags, + render_target_slice_offset, instance_count, first_vertex, first_instance); } void CommandProcessor::WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index) { @@ -1778,7 +1775,7 @@ void CommandProcessor::Flip() { LOGF("CommandProcessor::Flip()\n"); } - auto* command = CurrentBuffer(); + auto& command = CurrentBuffer(); auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index, m_flip.flip_mode, m_flip.flip_arg); Sync::WriteAtEndOfPipeOnlyFlip(m_submit_id, command, m_flip.handle, m_flip.index, @@ -1799,7 +1796,7 @@ void CommandProcessor::Flip(void* dst_gpu_addr, uint32_t value) { } std::memcpy(dst_gpu_addr, &value, sizeof(value)); - auto* command = CurrentBuffer(); + auto& command = CurrentBuffer(); auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index, m_flip.flip_mode, m_flip.flip_arg); Sync::WriteAtEndOfPipeWithFlip32(m_submit_id, command, static_cast(dst_gpu_addr), @@ -1827,7 +1824,7 @@ void CommandProcessor::FlipWithInterrupt(uint32_t eop_event_type, uint32_t cache EXIT("unknown event type\n"); } std::memcpy(dst_gpu_addr, &value, sizeof(value)); - auto* command = CurrentBuffer(); + auto& command = CurrentBuffer(); auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index, m_flip.flip_mode, m_flip.flip_arg); Sync::WriteAtEndOfPipeWithInterruptWriteBackFlip32( @@ -1843,10 +1840,10 @@ void CommandProcessor::PrepareCpuFlip() { EXIT("invalid graphics-thread CPU flip preparation\n"); } struct RunScope { - explicit RunScope(CommandProcessor* cp) { g_current_run_cp = cp; } + explicit RunScope(CommandProcessor& cp) { g_current_run_cp = &cp; } ~RunScope() { g_current_run_cp = nullptr; } }; - RunScope run_scope(this); + RunScope run_scope(*this); auto prepared_id = Presentation::DisplayBufferPrepareNextFlipOnGpu(CurrentBuffer()); m_scheduler.Flush(); diff --git a/src/graphics/guest_gpu/tile.cpp b/src/graphics/guest_gpu/tile.cpp index bea0c64ab..77cb328f3 100644 --- a/src/graphics/guest_gpu/tile.cpp +++ b/src/graphics/guest_gpu/tile.cpp @@ -404,33 +404,33 @@ struct TextureBlockLayout { uint32_t block_size; }; -static bool GetTextureBlockLayout(uint32_t format, uint32_t tile, TextureBlockLayout* out) { +static bool GetTextureBlockLayout(uint32_t format, uint32_t tile, TextureBlockLayout& out) { uint32_t width_log2 = 0, height_log2 = 0; - if (tile == 1 && Gen5Standard256BLayout(format, &out->bytes, &out->texel_width, - &out->texel_height, &width_log2, &height_log2)) { - out->block_size = 256; - } else if (tile == 5 && Gen5Standard4KBLayout(format, &out->bytes, &out->texel_width, - &out->texel_height, &width_log2, &height_log2)) { - out->block_size = 4096; + if (tile == 1 && Gen5Standard256BLayout(format, &out.bytes, &out.texel_width, + &out.texel_height, &width_log2, &height_log2)) { + out.block_size = 256; + } else if (tile == 5 && Gen5Standard4KBLayout(format, &out.bytes, &out.texel_width, + &out.texel_height, &width_log2, &height_log2)) { + out.block_size = 4096; } else if ((tile == 9 || tile == 17) && - Gen5Standard64KBLayout(format, &out->bytes, &out->texel_width, &out->texel_height, + Gen5Standard64KBLayout(format, &out.bytes, &out.texel_width, &out.texel_height, &width_log2, &height_log2)) { - out->block_size = 65536; + out.block_size = 65536; } else if (tile == 24 || tile == 27) { - out->bytes = Prospero::NumBytesPerElement(format); - out->texel_width = out->texel_height = 1; - if (out->bytes == 0 || (tile == 24 && out->bytes > 8) || - !Gen5Thin64KBBlockSizeFromElementBytes(out->bytes, &out->block_width, - &out->block_height)) { + out.bytes = Prospero::NumBytesPerElement(format); + out.texel_width = out.texel_height = 1; + if (out.bytes == 0 || (tile == 24 && out.bytes > 8) || + !Gen5Thin64KBBlockSizeFromElementBytes(out.bytes, &out.block_width, + &out.block_height)) { return false; } - out->block_size = 65536; + out.block_size = 65536; return true; } else { return false; } - out->block_width = 1u << width_log2; - out->block_height = 1u << height_log2; + out.block_width = 1u << width_log2; + out.block_height = 1u << height_log2; return true; } @@ -524,12 +524,12 @@ static void SetMacroMipLayout(const TextureBlockLayout& block, uint32_t tile, ui } bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, - uint32_t levels, uint32_t tile, TileVolumeLayout* out) { - if (out == nullptr || width == 0 || height == 0 || depth == 0 || levels == 0 || levels > 16) { + uint32_t levels, uint32_t tile, TileVolumeLayout& out) { + if (width == 0 || height == 0 || depth == 0 || levels == 0 || levels > 16) { return false; } TextureBlockLayout element {}; - if (!GetTextureBlockLayout(format, tile, &element)) return false; + if (!GetTextureBlockLayout(format, tile, element)) return false; TileBlockFamily family = TileBlockFamily::Count; switch (tile) { @@ -541,15 +541,15 @@ bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height default: return false; } TileBlockLayout block {}; - if (!TileGetBlockLayout(family, element.bytes, &block)) return false; + if (!TileGetBlockLayout(family, element.bytes, block)) return false; - *out = {}; - out->family = family; - out->bytes_per_element = element.bytes; - out->texel_width = element.texel_width; - out->texel_height = element.texel_height; - out->block_depth = block.block_depth; - out->first_tail_level = levels; + out = {}; + out.family = family; + out.bytes_per_element = element.bytes; + out.texel_width = element.texel_width; + out.texel_height = element.texel_height; + out.block_depth = block.block_depth; + out.first_tail_level = levels; const uint32_t width0 = (width + element.texel_width - 1u) / element.texel_width; const uint32_t height0 = (height + element.texel_height - 1u) / element.texel_height; const bool thick4 = family == TileBlockFamily::Standard4KB3D; @@ -568,37 +568,37 @@ bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height const uint32_t mip_height = std::max(ShiftCeil(height0, level), 1u); if (levels > 1 && mip_width <= tail_width && mip_height <= tail_height && levels - level <= max_tail) { - out->first_tail_level = level; - out->block_slice_size += block.block_size; + out.first_tail_level = level; + out.block_slice_size += block.block_size; break; } - out->level_widths[level] = AlignUp(mip_width, block.block_width); - out->level_heights[level] = AlignUp(mip_height, block.block_height); - out->level_sizes[level] = static_cast(block.block_depth) * - out->level_widths[level] * out->level_heights[level] * + out.level_widths[level] = AlignUp(mip_width, block.block_width); + out.level_heights[level] = AlignUp(mip_height, block.block_height); + out.level_sizes[level] = static_cast(block.block_depth) * + out.level_widths[level] * out.level_heights[level] * element.bytes; - out->block_slice_size += out->level_sizes[level]; + out.block_slice_size += out.level_sizes[level]; } const auto bytes_log2 = std::countr_zero(element.bytes); - for (uint32_t level = out->first_tail_level; level < levels; ++level) { - const auto index = level - out->first_tail_level; + for (uint32_t level = out.first_tail_level; level < levels; ++level) { + const auto index = level - out.first_tail_level; const auto tail = thick4 ? GEN5_MIP_TAIL_LOCATIONS_THICK_4KB[bytes_log2][index] : (thick64 ? GEN5_MIP_TAIL_LOCATIONS_THICK_64KB[bytes_log2][index] : GEN5_MIP_TAIL_LOCATIONS_THIN_64KB[bytes_log2][index]); - out->level_sizes[level] = block.block_size; - out->level_widths[level] = block.block_width; - out->level_heights[level] = block.block_height; - out->tail_x[level] = tail.x; - out->tail_y[level] = tail.y; + out.level_sizes[level] = block.block_size; + out.level_widths[level] = block.block_width; + out.level_heights[level] = block.block_height; + out.tail_x[level] = tail.x; + out.tail_y[level] = tail.y; } - uint64_t offset = out->first_tail_level < levels ? block.block_size : 0; - for (int32_t l = static_cast(out->first_tail_level) - 1; l >= 0; --l) { - out->level_offsets[l] = offset; - offset += out->level_sizes[l]; + uint64_t offset = out.first_tail_level < levels ? block.block_size : 0; + for (int32_t l = static_cast(out.first_tail_level) - 1; l >= 0; --l) { + out.level_offsets[l] = offset; + offset += out.level_sizes[l]; } - out->total_size = out->block_slice_size * ShiftCeil(depth, std::countr_zero(block.block_depth)); - return offset == out->block_slice_size; + out.total_size = out.block_slice_size * ShiftCeil(depth, std::countr_zero(block.block_depth)); + return offset == out.block_slice_size; } static uint32_t Gen5Standard4KBOffsetInBlock(uint32_t x, uint32_t y, uint32_t bytes_per_element) { @@ -1047,8 +1047,8 @@ static constexpr uint32_t Depth64KB64XOffsetBytes(uint32_t x); static constexpr uint32_t Depth64KB64YOffsetBytes(uint32_t y); bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element, - TileBlockLayout* layout) { - if (layout == nullptr || !std::has_single_bit(bytes_per_element) || bytes_per_element > 16) { + TileBlockLayout& layout) { + if (!std::has_single_bit(bytes_per_element) || bytes_per_element > 16) { return false; } @@ -1121,15 +1121,14 @@ bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element, result.block_size) { return false; } - *layout = result; + layout = result; return true; } bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, uint32_t z, - uint32_t* byte_offset) { + uint32_t& byte_offset) { TileBlockLayout expected {}; - if (byte_offset == nullptr || - !TileGetBlockLayout(layout.family, layout.bytes_per_element, &expected) || + if (!TileGetBlockLayout(layout.family, layout.bytes_per_element, expected) || layout.block_size != expected.block_size || layout.block_width != expected.block_width || layout.block_height != expected.block_height || layout.block_depth != expected.block_depth || x >= layout.block_width || @@ -1222,20 +1221,19 @@ bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, u if (offset >= layout.block_size || offset % layout.bytes_per_element != 0) { return false; } - *byte_offset = offset; + byte_offset = offset; return true; } bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y, - uint32_t* byte_offset) { + uint32_t& byte_offset) { return TileGetBlockXor(layout, block_x, block_y, 0, byte_offset); } bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y, - uint32_t block_z, uint32_t* byte_offset) { + uint32_t block_z, uint32_t& byte_offset) { TileBlockLayout expected {}; - if (byte_offset == nullptr || - !TileGetBlockLayout(layout.family, layout.bytes_per_element, &expected) || + if (!TileGetBlockLayout(layout.family, layout.bytes_per_element, expected) || layout.block_size != expected.block_size || layout.block_width != expected.block_width || layout.block_height != expected.block_height || layout.block_depth != expected.block_depth) { @@ -1246,8 +1244,8 @@ bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t b block_y > UINT32_MAX / layout.block_height) { return false; } - *byte_offset = Depth64KB64XOffsetBytes(block_x * layout.block_width) ^ - Depth64KB64YOffsetBytes(block_y * layout.block_height); + byte_offset = Depth64KB64XOffsetBytes(block_x * layout.block_width) ^ + Depth64KB64YOffsetBytes(block_y * layout.block_height); } else if (layout.family == TileBlockFamily::RenderTarget64KB) { if (block_x > UINT32_MAX / layout.block_width || block_y > UINT32_MAX / layout.block_height) { @@ -1256,22 +1254,22 @@ bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t b const auto x = block_x * layout.block_width; const auto y = block_y * layout.block_height; switch (layout.bytes_per_element) { - case 1: *byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; - case 2: *byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; - case 4: *byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; - case 8: *byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; - case 16: *byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; + case 1: byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; + case 2: byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; + case 4: byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; + case 8: byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; + case 16: byte_offset = Gen5RenderTargetOffsetInBlock(x, y); break; default: return false; } } else { - *byte_offset = 0; + byte_offset = 0; } if (layout.family == TileBlockFamily::RenderTarget64KB || layout.family == TileBlockFamily::Depth64KB) { - *byte_offset ^= ((block_z & 8u) << 5u) ^ ((block_z & 4u) << 7u) ^ ((block_z & 2u) << 9u) ^ - ((block_z & 1u) << 11u); + byte_offset ^= ((block_z & 8u) << 5u) ^ ((block_z & 4u) << 7u) ^ ((block_z & 2u) << 9u) ^ + ((block_z & 1u) << 11u); } - return *byte_offset < layout.block_size && *byte_offset % layout.bytes_per_element == 0; + return byte_offset < layout.block_size && byte_offset % layout.bytes_per_element == 0; } static constexpr uint32_t Depth64KB8XOffsetBytes(uint32_t x) { @@ -1362,8 +1360,8 @@ static_assert(Depth64KB32XOffsetBytes(2) == 0x0010u); static_assert(Depth64KB32YOffsetBytes(1) == 0x0008u); static_assert((Depth64KB32XOffsetBytes(3) ^ Depth64KB32YOffsetBytes(5)) == 0x009cu); -bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign* htile_size) { - *htile_size = {}; +bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& htile_size) { + htile_size = {}; if (width == 0 || width > 16384 || height == 0 || height > 16384) { return false; } @@ -1374,13 +1372,13 @@ bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign* htile_size if (size == 0 || size > UINT32_MAX) { return false; } - *htile_size = {static_cast(size), 32768}; + htile_size = {static_cast(size), 32768}; return true; } bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format, - uint32_t stencil_format, bool htile, TileSizeAlign* stencil_size, - TileSizeAlign* htile_size, TileSizeAlign* depth_size, + uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size, + TileSizeAlign& htile_size, TileSizeAlign& depth_size, uint32_t num_fragments_log2) { EXIT_IF(pitch != 0); // Prospero derives uncompressed depth/stencil as independent 64 KiB block surfaces. @@ -1408,19 +1406,19 @@ bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t AlignUp(height, stencil_block_height) * fragments : 0; TileSizeAlign calculated_htile {}; - const bool htile_valid = !htile || TileGetHtileSize(width, height, &calculated_htile); + const bool htile_valid = !htile || TileGetHtileSize(width, height, calculated_htile); if (depth_bytes_total <= UINT32_MAX && stencil_bytes_total <= UINT32_MAX && htile_valid) { - *depth_size = {static_cast(depth_bytes_total), 65536}; - *stencil_size = stencil_format == 1 + depth_size = {static_cast(depth_bytes_total), 65536}; + stencil_size = stencil_format == 1 ? TileSizeAlign {static_cast(stencil_bytes_total), 65536} : TileSizeAlign {}; - *htile_size = calculated_htile; + htile_size = calculated_htile; return true; } } - *depth_size = TileSizeAlign(); - *htile_size = TileSizeAlign(); - *stencil_size = TileSizeAlign(); + depth_size = TileSizeAlign(); + htile_size = TileSizeAlign(); + stencil_size = TileSizeAlign(); return false; } @@ -1443,9 +1441,9 @@ uint32_t TileGetDepthPitch(uint32_t width, uint32_t bytes_per_element, } bool TileGetRenderTargetSize(uint32_t width, uint32_t height, uint32_t pitch, - uint32_t bytes_per_element, TileSizeAlign* total_size, + uint32_t bytes_per_element, TileSizeAlign& total_size, uint32_t num_fragments_log2) { - *total_size = {}; + total_size = {}; uint32_t block_width = 0; uint32_t block_height = 0; if (height == 0 || pitch == 0 || @@ -1461,16 +1459,16 @@ bool TileGetRenderTargetSize(uint32_t width, uint32_t height, uint32_t pitch, if (size == 0 || size > UINT32_MAX) { return false; } - total_size->size = static_cast(size); - total_size->align = 65536; + total_size.size = static_cast(size); + total_size.align = 65536; return true; } bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch, uint32_t bytes_per_element, uint32_t levels, - TileSizeAlign* total_size, TileSizeOffset* level_sizes, + TileSizeAlign& total_size, TileSizeOffset* level_sizes, TilePaddedSize* padded_size) { - *total_size = {}; + total_size = {}; if (width == 0 || height == 0 || levels == 0 || levels > 16 || pitch != TileGetRenderTargetPitch(width, bytes_per_element)) { return false; @@ -1494,9 +1492,9 @@ bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitc default: return false; } TileGetTextureSize(format, width, height, pitch, levels, - Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), total_size, + Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), &total_size, level_sizes, padded_size); - return total_size->size != 0 && total_size->align == 65536; + return total_size.size != 0 && total_size.align == 65536; } void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch, @@ -1529,7 +1527,7 @@ void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32 } TextureBlockLayout block {}; - if (GetTextureBlockLayout(format, tile, &block)) { + if (GetTextureBlockLayout(format, tile, block)) { if (tile == 1) { SetMicroMipLayout(block, width, height, levels, total_size, level_sizes, padded_size); } else { @@ -1580,24 +1578,24 @@ void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32 void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, uint32_t pitch, uint32_t levels, uint32_t tile, bool volume_texture, - TileSizeAlign* total_size) { + TileSizeAlign& total_size) { EXIT_NOT_IMPLEMENTED(depth == 0); if (volume_texture) { TileVolumeLayout volume {}; - if (TileGetTextureVolumeLayout(format, width, height, depth, levels, tile, &volume)) { + if (TileGetTextureVolumeLayout(format, width, height, depth, levels, tile, volume)) { EXIT_NOT_IMPLEMENTED(volume.total_size > UINT32_MAX); - total_size->size = static_cast(volume.total_size); - total_size->align = tile == 5 ? 4096u : 65536u; + total_size.size = static_cast(volume.total_size); + total_size.align = tile == 5 ? 4096u : 65536u; return; } } TileSizeAlign slice_size {}; TileGetTextureSize(format, width, height, pitch, levels, tile, &slice_size, nullptr, nullptr); - *total_size = slice_size; + total_size = slice_size; const uint64_t total = static_cast(slice_size.size) * depth; EXIT_NOT_IMPLEMENTED(total > 0xffffffffull); - total_size->size = static_cast(total); + total_size.size = static_cast(total); } uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t levels, uint32_t tile) { diff --git a/src/graphics/guest_gpu/tile.h b/src/graphics/guest_gpu/tile.h index 30122f00e..7e4ab35d2 100644 --- a/src/graphics/guest_gpu/tile.h +++ b/src/graphics/guest_gpu/tile.h @@ -65,41 +65,41 @@ struct TileVolumeLayout { }; bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element, - TileBlockLayout* layout); + TileBlockLayout& layout); bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, uint32_t z, - uint32_t* byte_offset); + uint32_t& byte_offset); bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y, - uint32_t* byte_offset); + uint32_t& byte_offset); bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y, - uint32_t block_z, uint32_t* byte_offset); + uint32_t block_z, uint32_t& byte_offset); bool TileIsStandard256BTextureSupported(uint32_t format); bool TileIsStandard4KBTextureSupported(uint32_t format); bool TileIsStandard64KBTextureSupported(uint32_t format); bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, - uint32_t levels, uint32_t tile, TileVolumeLayout* layout); + uint32_t levels, uint32_t tile, TileVolumeLayout& layout); -bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign* htile_size); +bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& htile_size); bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format, - uint32_t stencil_format, bool htile, TileSizeAlign* stencil_size, - TileSizeAlign* htile_size, TileSizeAlign* depth_size, + uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size, + TileSizeAlign& htile_size, TileSizeAlign& depth_size, uint32_t num_fragments_log2 = 0); uint32_t TileGetRenderTargetPitch(uint32_t width, uint32_t bytes_per_element, uint32_t num_fragments_log2 = 0); uint32_t TileGetDepthPitch(uint32_t width, uint32_t bytes_per_element, uint32_t num_fragments_log2 = 0); bool TileGetRenderTargetSize(uint32_t width, uint32_t height, uint32_t pitch, - uint32_t bytes_per_element, TileSizeAlign* total_size, + uint32_t bytes_per_element, TileSizeAlign& total_size, uint32_t num_fragments_log2 = 0); bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch, - uint32_t bytes_per_element, uint32_t levels, - TileSizeAlign* total_size, TileSizeOffset* level_sizes, + uint32_t bytes_per_element, uint32_t levels, + TileSizeAlign& total_size, TileSizeOffset* level_sizes, TilePaddedSize* padded_size); void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch, uint32_t levels, uint32_t tile, TileSizeAlign* total_size, TileSizeOffset* level_sizes, TilePaddedSize* padded_size); void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, uint32_t pitch, uint32_t levels, uint32_t tile, bool volume_texture, - TileSizeAlign* total_size); + TileSizeAlign& total_size); uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t levels, uint32_t tile); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/gpuTiler.cpp b/src/graphics/host_gpu/gpuTiler.cpp index 27ae91e30..1b35126d0 100644 --- a/src/graphics/host_gpu/gpuTiler.cpp +++ b/src/graphics/host_gpu/gpuTiler.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace Libs::Graphics { @@ -86,17 +87,17 @@ struct Resources { void* mapped = nullptr; }; -bool CheckedAdd(uint64_t a, uint64_t b, uint64_t* result) { - return b <= UINT64_MAX - a && (*result = a + b, true); +bool CheckedAdd(uint64_t a, uint64_t b, uint64_t& result) { + return b <= UINT64_MAX - a && (result = a + b, true); } -bool CheckedMultiply(uint64_t a, uint64_t b, uint64_t* result) { - return (a == 0 || b <= UINT64_MAX / a) && (*result = a * b, true); +bool CheckedMultiply(uint64_t a, uint64_t b, uint64_t& result) { + return (a == 0 || b <= UINT64_MAX / a) && (result = a * b, true); } -bool CheckedAddProduct(uint64_t* value, uint64_t count, uint64_t stride) { +bool CheckedAddProduct(uint64_t& value, uint64_t count, uint64_t stride) { uint64_t bytes = 0; - return CheckedMultiply(count, stride, &bytes) && CheckedAdd(*value, bytes, value); + return CheckedMultiply(count, stride, bytes) && CheckedAdd(value, bytes, value); } bool IsRangeValid(uint64_t offset, uint64_t size, uint64_t capacity) { @@ -129,53 +130,51 @@ void Barrier(vk::CommandBuffer command, vk::Buffer buffer, vk::AccessFlags src_a command.pipelineBarrier(src_stage, dst_stage, {}, 0, nullptr, 1, &barrier, 0, nullptr); } -class Tiler final { +class TileCompute final { public: - void Run(bool to_tiled, GraphicContext* context, const void* input, void* output, - uint64_t tiled_capacity, uint64_t linear_capacity, std::span infos, + explicit TileCompute(GraphicContext& graphics): graphics(graphics) {} + void Run(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity, + uint64_t linear_capacity, std::span infos, const GpuTileRecord& record); - void Release(GraphicContext* context); + void Release(); private: - void Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capacity, - uint64_t linear_capacity, std::span infos, - std::vector* dispatches) const; - void Init(GraphicContext* context); + void Prepare(bool to_tiled, uint64_t tiled_capacity, uint64_t linear_capacity, + std::span infos, std::vector& dispatches) const; + void Init(); void CreatePipelines(std::span dispatches); void CreatePipeline(uint32_t pipeline_slot); void Resize(uint64_t staging_size, uint64_t linear_size); - void CreateBuffer(uint64_t size, bool mapped, VulkanBuffer* buffer, void** data) const; + void CreateBuffer(uint64_t size, bool mapped, VulkanBuffer& buffer, void** data) const; void Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity, uint64_t linear_capacity, std::span dispatches, const GpuTileRecord& record); - void Destroy(Resources* target) const; + void Destroy(Resources& target) const; - Common::Mutex mutex; - GraphicContext* ctx = nullptr; + GraphicContext& graphics; Resources resources; }; -Tiler g_tiler; +Common::Mutex g_tiler_mutex; +std::unique_ptr g_tiler; -void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capacity, - uint64_t linear_capacity, std::span infos, - std::vector* dispatches) const { - EXIT_IF(context == nullptr || g_render_ctx == nullptr || - g_render_ctx->GetGraphicCtx() != context || infos.empty() || tiled_capacity == 0 || - linear_capacity == 0); - const auto& limits = context->GetPhysicalDeviceProperties().limits; +void TileCompute::Prepare(bool to_tiled, uint64_t tiled_capacity, uint64_t linear_capacity, + std::span infos, + std::vector& dispatches) const { + EXIT_IF(infos.empty() || tiled_capacity == 0 || linear_capacity == 0); + const auto& limits = graphics.GetPhysicalDeviceProperties().limits; EXIT_NOT_IMPLEMENTED(tiled_capacity > UINT32_MAX || linear_capacity > UINT32_MAX || AlignToDword(tiled_capacity) > limits.maxStorageBufferRange || AlignToDword(linear_capacity) > limits.maxStorageBufferRange); - dispatches->clear(); - dispatches->reserve(infos.size()); + dispatches.clear(); + dispatches.reserve(infos.size()); for (const auto& info: infos) { TileBlockLayout block {}; const uint32_t tiled_width = info.tiled_width != 0 ? info.tiled_width : info.pitch; const uint32_t tiled_height = info.tiled_height != 0 ? info.tiled_height : info.height; EXIT_NOT_IMPLEMENTED( - !TileGetBlockLayout(info.family, info.bytes_per_element, &block) || info.width == 0 || + !TileGetBlockLayout(info.family, info.bytes_per_element, block) || info.width == 0 || info.height == 0 || info.depth == 0 || info.pitch < info.width || (!info.tail && (tiled_width < info.width || tiled_height < info.height)) || !IsRangeValid(info.linear_offset, info.linear_size, linear_capacity) || @@ -183,19 +182,19 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac (block.block_depth == 1 && info.depth != 1)); uint64_t elements = 0, pitch_bytes = 0; - EXIT_NOT_IMPLEMENTED(!CheckedMultiply(info.width, info.height, &elements) || - !CheckedMultiply(elements, info.depth, &elements) || - !CheckedMultiply(info.pitch, info.bytes_per_element, &pitch_bytes) || + EXIT_NOT_IMPLEMENTED(!CheckedMultiply(info.width, info.height, elements) || + !CheckedMultiply(elements, info.depth, elements) || + !CheckedMultiply(info.pitch, info.bytes_per_element, pitch_bytes) || elements > UINT32_MAX || pitch_bytes > UINT32_MAX); uint64_t slice_bytes = info.linear_slice_stride; EXIT_NOT_IMPLEMENTED(slice_bytes == 0 && - !CheckedMultiply(pitch_bytes, info.height, &slice_bytes)); + !CheckedMultiply(pitch_bytes, info.height, slice_bytes)); uint64_t linear_used = 0, minimum_slice = 0; - EXIT_NOT_IMPLEMENTED(!CheckedMultiply(pitch_bytes, info.height, &minimum_slice) || + EXIT_NOT_IMPLEMENTED(!CheckedMultiply(pitch_bytes, info.height, minimum_slice) || (info.depth > 1 && slice_bytes < minimum_slice) || - !CheckedAddProduct(&linear_used, info.depth - 1u, slice_bytes) || - !CheckedAddProduct(&linear_used, info.height - 1u, pitch_bytes) || - !CheckedAddProduct(&linear_used, info.width, info.bytes_per_element) || + !CheckedAddProduct(linear_used, info.depth - 1u, slice_bytes) || + !CheckedAddProduct(linear_used, info.height - 1u, pitch_bytes) || + !CheckedAddProduct(linear_used, info.width, info.bytes_per_element) || linear_used > info.linear_size || slice_bytes > UINT32_MAX); const uint64_t columns = @@ -203,7 +202,7 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac const uint64_t rows = (static_cast(tiled_height) + block.block_height - 1u) / block.block_height; uint64_t blocks_per_slice = 0; - EXIT_NOT_IMPLEMENTED(!CheckedMultiply(columns, rows, &blocks_per_slice) || + EXIT_NOT_IMPLEMENTED(!CheckedMultiply(columns, rows, blocks_per_slice) || columns > UINT32_MAX || blocks_per_slice > UINT32_MAX || rows * block.block_height > UINT32_MAX); if (info.tail) { @@ -217,8 +216,8 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac const uint64_t slices = (static_cast(info.depth) + block.block_depth - 1u) / block.block_depth; uint64_t tiled_used = 0; - EXIT_NOT_IMPLEMENTED(!CheckedMultiply(blocks_per_slice, slices, &tiled_used) || - !CheckedMultiply(tiled_used, block.block_size, &tiled_used) || + EXIT_NOT_IMPLEMENTED(!CheckedMultiply(blocks_per_slice, slices, tiled_used) || + !CheckedMultiply(tiled_used, block.block_size, tiled_used) || tiled_used > info.tiled_size); } const uint32_t alignment = std::min(info.bytes_per_element, 4u); @@ -243,47 +242,42 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac dispatch.push.tail_x = info.tail_x; dispatch.push.tail_y = info.tail_y; dispatch.push.tail = info.tail; - dispatches->push_back(dispatch); + dispatches.push_back(dispatch); } } -void Tiler::Destroy(Resources* target) const { - if (ctx == nullptr) { - return; +void TileCompute::Destroy(Resources& target) const { + if (target.mapped != nullptr) { + graphics.UnmapMemory(target.staging.memory); } - if (target->mapped != nullptr) { - VulkanUnmapMemory(ctx, &target->staging.memory); + if (target.staging.buffer != nullptr) { + graphics.DeleteBuffer(target.staging); } - if (target->staging.buffer != nullptr) { - VulkanDeleteBuffer(ctx, &target->staging); + if (target.linear.buffer != nullptr) { + graphics.DeleteBuffer(target.linear); } - if (target->linear.buffer != nullptr) { - VulkanDeleteBuffer(ctx, &target->linear); - } - for (auto pipeline: target->pipelines) { + for (auto pipeline: target.pipelines) { if (pipeline != nullptr) { - ctx->device.destroyPipeline(pipeline, nullptr); + graphics.device.destroyPipeline(pipeline, nullptr); } } - if (target->descriptor_pool != nullptr) { - ctx->device.destroyDescriptorPool(target->descriptor_pool, nullptr); + if (target.descriptor_pool != nullptr) { + graphics.device.destroyDescriptorPool(target.descriptor_pool, nullptr); } - if (target->pipeline_layout != nullptr) { - ctx->device.destroyPipelineLayout(target->pipeline_layout, nullptr); + if (target.pipeline_layout != nullptr) { + graphics.device.destroyPipelineLayout(target.pipeline_layout, nullptr); } - if (target->descriptor_layout != nullptr) { - ctx->device.destroyDescriptorSetLayout(target->descriptor_layout, nullptr); + if (target.descriptor_layout != nullptr) { + graphics.device.destroyDescriptorSetLayout(target.descriptor_layout, nullptr); } - *target = {}; + target = {}; } -void Tiler::Init(GraphicContext* context) { +void TileCompute::Init() { if (resources.pipeline_layout != nullptr) { - EXIT_IF(ctx != context); return; } - EXIT_IF(context == nullptr || context->device == nullptr || context->allocator == nullptr); - ctx = context; + EXIT_IF(graphics.device == nullptr || graphics.allocator == nullptr); std::array bindings {}; for (uint32_t i = 0; i < bindings.size(); i++) { bindings[i] = {i, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute, @@ -293,8 +287,8 @@ void Tiler::Init(GraphicContext* context) { descriptor_info.sType = vk::StructureType::eDescriptorSetLayoutCreateInfo; descriptor_info.bindingCount = static_cast(bindings.size()); descriptor_info.pBindings = bindings.data(); - RequireVulkanSuccess(ctx->device.createDescriptorSetLayout(&descriptor_info, nullptr, - &resources.descriptor_layout), + RequireVulkanSuccess(graphics.device.createDescriptorSetLayout(&descriptor_info, nullptr, + &resources.descriptor_layout), "create GPU tiler descriptor layout"); vk::PushConstantRange push_range {vk::ShaderStageFlagBits::eCompute, 0, sizeof(Push)}; @@ -305,7 +299,7 @@ void Tiler::Init(GraphicContext* context) { layout_info.pushConstantRangeCount = 1; layout_info.pPushConstantRanges = &push_range; RequireVulkanSuccess( - ctx->device.createPipelineLayout(&layout_info, nullptr, &resources.pipeline_layout), + graphics.device.createPipelineLayout(&layout_info, nullptr, &resources.pipeline_layout), "create GPU tiler pipeline layout"); vk::DescriptorPoolSize pool_size {vk::DescriptorType::eStorageBuffer, 2}; vk::DescriptorPoolCreateInfo pool_info {}; @@ -314,18 +308,19 @@ void Tiler::Init(GraphicContext* context) { pool_info.poolSizeCount = 1; pool_info.pPoolSizes = &pool_size; RequireVulkanSuccess( - ctx->device.createDescriptorPool(&pool_info, nullptr, &resources.descriptor_pool), + graphics.device.createDescriptorPool(&pool_info, nullptr, &resources.descriptor_pool), "create GPU tiler descriptor pool"); vk::DescriptorSetAllocateInfo set_info {}; set_info.sType = vk::StructureType::eDescriptorSetAllocateInfo; set_info.descriptorPool = resources.descriptor_pool; set_info.descriptorSetCount = 1; set_info.pSetLayouts = &resources.descriptor_layout; - RequireVulkanSuccess(ctx->device.allocateDescriptorSets(&set_info, &resources.descriptor_set), - "allocate GPU tiler descriptor set"); + RequireVulkanSuccess( + graphics.device.allocateDescriptorSets(&set_info, &resources.descriptor_set), + "allocate GPU tiler descriptor set"); } -void Tiler::CreatePipeline(uint32_t pipeline_slot) { +void TileCompute::CreatePipeline(uint32_t pipeline_slot) { const uint32_t element_size_index = pipeline_slot % BYTES_PER_ELEMENT_COUNT; const uint32_t family_direction_index = pipeline_slot / BYTES_PER_ELEMENT_COUNT; const uint32_t family_index = family_direction_index % FAMILY_COUNT; @@ -339,7 +334,7 @@ void Tiler::CreatePipeline(uint32_t pipeline_slot) { module_info.codeSize = SHADERS[family_index].words * sizeof(uint32_t); module_info.pCode = SHADERS[family_index].code; vk::ShaderModule module = nullptr; - RequireVulkanSuccess(ctx->device.createShaderModule(&module_info, nullptr, &module), + RequireVulkanSuccess(graphics.device.createShaderModule(&module_info, nullptr, &module), "create GPU tiler shader module"); vk::PipelineShaderStageCreateInfo stage {}; stage.sType = vk::StructureType::ePipelineShaderStageCreateInfo; @@ -352,13 +347,14 @@ void Tiler::CreatePipeline(uint32_t pipeline_slot) { info.stage = stage; info.layout = resources.pipeline_layout; vk::Pipeline pipeline = nullptr; - const auto result = ctx->device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline); - ctx->device.destroyShaderModule(module, nullptr); + const auto result = + graphics.device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline); + graphics.device.destroyShaderModule(module, nullptr); RequireVulkanSuccess(result, "create GPU tiler pipeline"); resources.pipelines[pipeline_slot] = pipeline; } -void Tiler::CreatePipelines(std::span dispatches) { +void TileCompute::CreatePipelines(std::span dispatches) { for (const auto& dispatch: dispatches) { if (resources.pipelines[dispatch.pipeline_slot] == nullptr) { CreatePipeline(dispatch.pipeline_slot); @@ -366,18 +362,19 @@ void Tiler::CreatePipelines(std::span dispatches) { } } -void Tiler::CreateBuffer(uint64_t size, bool mapped, VulkanBuffer* buffer, void** data) const { - buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer | - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; - buffer->memory.property = +void TileCompute::CreateBuffer(uint64_t size, bool mapped, VulkanBuffer& buffer, + void** data) const { + buffer.usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst; + buffer.memory.property = mapped ? vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent : vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eDeviceLocal); - VulkanCreateBuffer(ctx, size, buffer); - if (mapped) VulkanMapMemory(ctx, &buffer->memory, data); + graphics.CreateBuffer(size, buffer); + if (mapped) graphics.MapMemory(buffer.memory, *data); } -void Tiler::Resize(uint64_t staging_size, uint64_t linear_size) { +void TileCompute::Resize(uint64_t staging_size, uint64_t linear_size) { if (resources.staging.buffer_size >= staging_size && resources.linear.buffer_size >= linear_size) { return; @@ -386,19 +383,19 @@ void Tiler::Resize(uint64_t staging_size, uint64_t linear_size) { linear_size = std::max(linear_size, resources.linear.buffer_size); VulkanBuffer staging {}, linear {}; void* mapped = nullptr; - CreateBuffer(staging_size, true, &staging, &mapped); - CreateBuffer(linear_size, false, &linear, nullptr); - if (resources.mapped != nullptr) VulkanUnmapMemory(ctx, &resources.staging.memory); - if (resources.staging.buffer != nullptr) VulkanDeleteBuffer(ctx, &resources.staging); - if (resources.linear.buffer != nullptr) VulkanDeleteBuffer(ctx, &resources.linear); + CreateBuffer(staging_size, true, staging, &mapped); + CreateBuffer(linear_size, false, linear, nullptr); + if (resources.mapped != nullptr) graphics.UnmapMemory(resources.staging.memory); + if (resources.staging.buffer != nullptr) graphics.DeleteBuffer(resources.staging); + if (resources.linear.buffer != nullptr) graphics.DeleteBuffer(resources.linear); resources.staging = staging; resources.linear = linear; resources.mapped = mapped; } -void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity, - uint64_t linear_capacity, std::span dispatches, - const GpuTileRecord& record) { +void TileCompute::Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity, + uint64_t linear_capacity, std::span dispatches, + const GpuTileRecord& record) { const uint64_t tiled_size = AlignToDword(tiled_capacity); const uint64_t linear_size = AlignToDword(linear_capacity); const uint64_t input_size = to_tiled ? linear_capacity : tiled_capacity; @@ -423,8 +420,8 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til writes[i].descriptorType = vk::DescriptorType::eStorageBuffer; writes[i].pBufferInfo = &buffer_info[i]; } - ctx->device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, - nullptr); + graphics.device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, + nullptr); CommandBuffer command(GraphicContext::QUEUE_UTIL); command.Begin(); @@ -446,7 +443,7 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til vk::PipelineStageFlagBits::eTransfer); } if (to_tiled && record) { - record(&command, &resources.linear); + record(command, resources.linear); Barrier(vk_command, resources.linear.buffer, vk::AccessFlagBits::eTransferWrite | vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eShaderRead, vk::PipelineStageFlagBits::eAllCommands, @@ -463,7 +460,7 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til &resources.descriptor_set, 0, nullptr); const uint64_t limit = static_cast( - ctx->GetPhysicalDeviceProperties().limits.maxComputeWorkGroupCount[0]) * + graphics.GetPhysicalDeviceProperties().limits.maxComputeWorkGroupCount[0]) * GROUP_SIZE; for (const auto& dispatch: dispatches) { vk_command.bindPipeline(vk::PipelineBindPoint::eCompute, @@ -484,7 +481,7 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eHost); if (!to_tiled && record) { - record(&command, &resources.linear); + record(command, resources.linear); } if (!to_tiled && output != nullptr) { const vk::BufferCopy copy {0, 0, linear_size}; @@ -502,15 +499,14 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til } } -void Tiler::Run(bool to_tiled, GraphicContext* context, const void* input, void* output, - uint64_t tiled_capacity, uint64_t linear_capacity, - std::span infos, const GpuTileRecord& record) { - Common::LockGuard lock(mutex); +void TileCompute::Run(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity, + uint64_t linear_capacity, std::span infos, + const GpuTileRecord& record) { EXIT_IF((to_tiled && (output == nullptr || (input == nullptr && !record))) || (!to_tiled && (input == nullptr || (output == nullptr && !record)))); std::vector dispatches; - Prepare(to_tiled, context, tiled_capacity, linear_capacity, infos, &dispatches); - Init(context); + Prepare(to_tiled, tiled_capacity, linear_capacity, infos, dispatches); + Init(); CreatePipelines(dispatches); const uint64_t staging_size = std::max(AlignToDword(tiled_capacity), AlignToDword(linear_capacity)); @@ -519,29 +515,38 @@ void Tiler::Run(bool to_tiled, GraphicContext* context, const void* input, void* Execute(to_tiled, input, output, tiled_capacity, linear_capacity, dispatches, record); } -void Tiler::Release(GraphicContext* context) { - Common::LockGuard lock(mutex); - EXIT_IF(ctx != nullptr && context != ctx); - Destroy(&resources); - ctx = nullptr; +void TileCompute::Release() { + Destroy(resources); } } // namespace -void GpuDetile(GraphicContext* ctx, const void* tiled, void* linear, uint64_t tiled_capacity, +void GpuDetile(const void* tiled, void* linear, uint64_t tiled_capacity, uint64_t linear_capacity, std::span infos, const GpuTileRecord& after) { - g_tiler.Run(false, ctx, tiled, linear, tiled_capacity, linear_capacity, infos, after); + Common::LockGuard lock(g_tiler_mutex); + if (!g_tiler) { + g_tiler = std::make_unique(GetRenderContext().GetGraphics()); + } + g_tiler->Run(false, tiled, linear, tiled_capacity, linear_capacity, infos, after); } -void GpuTile(GraphicContext* ctx, const void* linear, void* tiled, uint64_t tiled_capacity, +void GpuTile(const void* linear, void* tiled, uint64_t tiled_capacity, uint64_t linear_capacity, std::span infos, const GpuTileRecord& before) { - g_tiler.Run(true, ctx, linear, tiled, tiled_capacity, linear_capacity, infos, before); + Common::LockGuard lock(g_tiler_mutex); + if (!g_tiler) { + g_tiler = std::make_unique(GetRenderContext().GetGraphics()); + } + g_tiler->Run(true, linear, tiled, tiled_capacity, linear_capacity, infos, before); } -void GpuTileRelease(GraphicContext* ctx) { - g_tiler.Release(ctx); +void GpuTileRelease() { + Common::LockGuard lock(g_tiler_mutex); + if (g_tiler) { + g_tiler->Release(); + g_tiler.reset(); + } } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/gpuTiler.h b/src/graphics/host_gpu/gpuTiler.h index cadf55481..ad2af34f9 100644 --- a/src/graphics/host_gpu/gpuTiler.h +++ b/src/graphics/host_gpu/gpuTiler.h @@ -32,14 +32,14 @@ struct GpuTileInfo { uint32_t surface_z = 0; }; -using GpuTileRecord = std::function; +using GpuTileRecord = std::function; -void GpuDetile(GraphicContext* ctx, const void* tiled, void* linear, uint64_t tiled_capacity, +void GpuDetile(const void* tiled, void* linear, uint64_t tiled_capacity, uint64_t linear_capacity, std::span infos, const GpuTileRecord& after = {}); -void GpuTile(GraphicContext* ctx, const void* linear, void* tiled, uint64_t tiled_capacity, +void GpuTile(const void* linear, void* tiled, uint64_t tiled_capacity, uint64_t linear_capacity, std::span infos, const GpuTileRecord& before = {}); -void GpuTileRelease(GraphicContext* ctx); +void GpuTileRelease(); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/graphicContext.h b/src/graphics/host_gpu/graphicContext.h index 8e7a41877..2b872e732 100644 --- a/src/graphics/host_gpu/graphicContext.h +++ b/src/graphics/host_gpu/graphicContext.h @@ -16,6 +16,9 @@ namespace Libs::Graphics { class CommandBuffer; +struct VulkanBuffer; +struct VulkanImage; +struct VulkanMemory; struct VulkanSwapchain { ~VulkanSwapchain(); @@ -43,6 +46,20 @@ struct VulkanCommandPool { }; struct GraphicContext: public VulkanInstance { + [[nodiscard]] bool CreateAllocator(); + void DestroyAllocator(); + void LogMemoryBudget() const; + void CreateBuffer(uint64_t size, VulkanBuffer& buffer); + void DeleteBuffer(VulkanBuffer& buffer); + [[nodiscard]] bool CreateImage(const vk::ImageCreateInfo& info, VulkanImage& image); + void DeleteImage(VulkanImage& image); + void MapMemory(VulkanMemory& memory, void*& data); + void UnmapMemory(VulkanMemory& memory); + void AppendHardwareRayTracingDeviceExtensions( + const std::vector& available_extensions, + std::vector& device_extensions); + void LoadHardwareRayTracingFunctions() const; + uint32_t screen_width = 0; uint32_t screen_height = 0; std::array queue_mutexes; diff --git a/src/graphics/host_gpu/hostMemory.cpp b/src/graphics/host_gpu/hostMemory.cpp index 292252d3b..f7c7e886e 100644 --- a/src/graphics/host_gpu/hostMemory.cpp +++ b/src/graphics/host_gpu/hostMemory.cpp @@ -30,11 +30,8 @@ bool IsAccessible(DWORD protect, HostMemoryAccess access) { } // namespace bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAccess access, - uint64_t* accessible_size) { - if (accessible_size == nullptr) { - return false; - } - *accessible_size = 0; + uint64_t& accessible_size) { + accessible_size = 0; if (addr == 0 || requested_size == 0) { return false; } @@ -87,11 +84,11 @@ bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAcce (void)access; #endif - *accessible_size = current - addr; - return *accessible_size != 0; + accessible_size = current - addr; + return accessible_size != 0; } -bool HostMemoryQueryReadable(uint64_t addr, uint64_t requested_size, uint64_t* readable_size) { +bool HostMemoryQueryReadable(uint64_t addr, uint64_t requested_size, uint64_t& readable_size) { return HostMemoryQueryRange(addr, requested_size, HostMemoryAccess::Read, readable_size); } @@ -104,7 +101,7 @@ bool HostMemoryRangeIsReadable(uint64_t addr, uint64_t size) { return false; } uint64_t readable_size = 0; - return HostMemoryQueryReadable(addr, size, &readable_size) && readable_size >= size; + return HostMemoryQueryReadable(addr, size, readable_size) && readable_size >= size; } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/hostMemory.h b/src/graphics/host_gpu/hostMemory.h index eca0b155a..b6c669ecd 100644 --- a/src/graphics/host_gpu/hostMemory.h +++ b/src/graphics/host_gpu/hostMemory.h @@ -8,8 +8,8 @@ namespace Libs::Graphics { enum class HostMemoryAccess { Read, Mapped }; bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAccess access, - uint64_t* accessible_size); -bool HostMemoryQueryReadable(uint64_t addr, uint64_t requested_size, uint64_t* readable_size); + uint64_t& accessible_size); +bool HostMemoryQueryReadable(uint64_t addr, uint64_t requested_size, uint64_t& readable_size); bool HostMemoryIsReadable(uint64_t addr); bool HostMemoryRangeIsReadable(uint64_t addr, uint64_t size); diff --git a/src/graphics/host_gpu/objects/label.cpp b/src/graphics/host_gpu/objects/label.cpp index 2d6bc6247..162838c28 100644 --- a/src/graphics/host_gpu/objects/label.cpp +++ b/src/graphics/host_gpu/objects/label.cpp @@ -4,6 +4,7 @@ #include "common/threads.h" #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/renderer/render.h" +#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/vulkanCommon.h" #include @@ -58,17 +59,16 @@ public: ~LabelManager() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(LabelManager); - Label* Create(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2, - const uint64_t* args); - void Delete(Label* label); - void Set(CommandBuffer* buffer, Label* label); + Label* Create(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args); + void Delete(Label& label); + void Set(CommandBuffer& buffer, Label& label); void Drain(); private: static void ThreadRun(void* data); - bool Remove(Label* label); - static void Destroy(Label* label); + bool Remove(Label& label); + static void Destroy(Label& label); Common::Mutex m_mutex; Common::CondVar m_cond_var; @@ -146,7 +146,7 @@ void LabelManager::ThreadRun(void* data) { manager->m_callbacks_in_flight += fired_labels.size(); for (auto& label: deleted_labels) { - bool removed = manager->Remove(label); + bool removed = manager->Remove(*label); EXIT_NOT_IMPLEMENTED(!removed); } @@ -158,7 +158,7 @@ void LabelManager::ThreadRun(void* data) { (void)finished_submissions; for (auto& label: deleted_labels) { - Destroy(label); + Destroy(*label); } for (auto& label: fired_labels) { @@ -186,16 +186,14 @@ void LabelManager::ThreadRun(void* data) { } } -Label* LabelManager::Create(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2, +Label* LabelManager::Create(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args) { - EXIT_IF(ctx == nullptr); - Common::LockGuard lock(m_mutex); auto* label = new Label; label->status = LabelStatus::New; - label->device = ctx->device; + label->device = GetRenderContext().GetGraphics().device; label->callbacks.callback_1 = callback_1; label->callbacks.callback_2 = callback_2; @@ -210,21 +208,20 @@ Label* LabelManager::Create(GraphicContext* ctx, LabelCallback callback_1, Label return label; } -bool LabelManager::Remove(Label* label) { - EXIT_IF(label == nullptr); - EXIT_IF(label->device == nullptr); +bool LabelManager::Remove(Label& label) { + EXIT_IF(label.device == nullptr); Common::LockGuard lock(m_mutex); - const auto it = std::find(m_labels.begin(), m_labels.end(), label); + const auto it = std::find(m_labels.begin(), m_labels.end(), &label); EXIT_NOT_IMPLEMENTED(it == m_labels.end()); - EXIT_NOT_IMPLEMENTED(label->status != LabelStatus::NotActive && - label->status != LabelStatus::Active && - label->status != LabelStatus::ActiveDeleted); + EXIT_NOT_IMPLEMENTED(label.status != LabelStatus::NotActive && + label.status != LabelStatus::Active && + label.status != LabelStatus::ActiveDeleted); - if (!label->submissions.empty()) { - label->status = LabelStatus::ActiveDeleted; + if (!label.submissions.empty()) { + label.status = LabelStatus::ActiveDeleted; return false; } @@ -234,44 +231,41 @@ bool LabelManager::Remove(Label* label) { return true; } -void LabelManager::Destroy(Label* label) { - EXIT_IF(label == nullptr); - EXIT_IF(label->device == nullptr); +void LabelManager::Destroy(Label& label) { + EXIT_IF(label.device == nullptr); - EXIT_NOT_IMPLEMENTED(!label->submissions.empty()); + EXIT_NOT_IMPLEMENTED(!label.submissions.empty()); - delete label; + delete &label; } -void LabelManager::Delete(Label* label) { +void LabelManager::Delete(Label& label) { if (Remove(label)) { Destroy(label); } } -void LabelManager::Set(CommandBuffer* buffer, Label* label) { - EXIT_IF(label == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - EXIT_IF(label->device == nullptr); +void LabelManager::Set(CommandBuffer& buffer, Label& label) { + EXIT_IF(buffer.IsInvalid()); + EXIT_IF(label.device == nullptr); Common::LockGuard lock(m_mutex); - const auto it = std::find(m_labels.begin(), m_labels.end(), label); + const auto it = std::find(m_labels.begin(), m_labels.end(), &label); EXIT_NOT_IMPLEMENTED(it == m_labels.end()); - EXIT_NOT_IMPLEMENTED(label->status != LabelStatus::New && - label->status != LabelStatus::NotActive && - label->status != LabelStatus::Active); + EXIT_NOT_IMPLEMENTED(label.status != LabelStatus::New && + label.status != LabelStatus::NotActive && + label.status != LabelStatus::Active); - label->status = LabelStatus::Active; + label.status = LabelStatus::Active; LabelSubmission submission {}; - submission.callbacks = label->callbacks; + submission.callbacks = label.callbacks; submission.completion = std::make_shared(); - submission.completion->device = label->device; + submission.completion->device = label.device; - auto vk_buffer = buffer->Handle(); + auto vk_buffer = buffer.Handle(); EXIT_NOT_IMPLEMENTED(vk_buffer == nullptr); @@ -281,24 +275,24 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) { create_info.flags = {}; const auto create_result = - label->device.createEvent(&create_info, nullptr, &submission.completion->event); + label.device.createEvent(&create_info, nullptr, &submission.completion->event); if (create_result != vk::Result::eSuccess || submission.completion->event == nullptr) { EXIT("failed to create label event: %s (%d)\n", VulkanToString(create_result).c_str(), static_cast(create_result)); } - buffer->RetainResourceUntilFence(submission.completion); + buffer.RetainResourceUntilFence(submission.completion); // Labels can be reused before an earlier end-of-pipe event has been // observed by the polling thread. Capture a separate Vulkan event and // callback snapshot for each set so older writes are not lost. - const auto reset_result = label->device.resetEvent(submission.completion->event); + const auto reset_result = label.device.resetEvent(submission.completion->event); if (reset_result != vk::Result::eSuccess) { EXIT("failed to reset label event: %s (%d)\n", VulkanToString(reset_result).c_str(), static_cast(reset_result)); } vk_buffer.setEvent(submission.completion->event, vk::PipelineStageFlagBits::eBottomOfPipe); - label->submissions.push_back(submission); + label.submissions.push_back(submission); m_cond_var.SignalAll(); } @@ -324,20 +318,19 @@ void LabelInit() { g_label_manager = new LabelManager; } -Label* LabelCreate(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2, - const uint64_t* args) { +Label* LabelCreate(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args) { EXIT_IF(g_label_manager == nullptr); - return g_label_manager->Create(ctx, callback_1, callback_2, args); + return g_label_manager->Create(callback_1, callback_2, args); } -void LabelDelete(Label* label) { +void LabelDelete(Label& label) { EXIT_IF(g_label_manager == nullptr); g_label_manager->Delete(label); } -void LabelSet(CommandBuffer* buffer, Label* label) { +void LabelSet(CommandBuffer& buffer, Label& label) { EXIT_IF(g_label_manager == nullptr); g_label_manager->Set(buffer, label); diff --git a/src/graphics/host_gpu/objects/label.h b/src/graphics/host_gpu/objects/label.h index 033903c78..19db369ef 100644 --- a/src/graphics/host_gpu/objects/label.h +++ b/src/graphics/host_gpu/objects/label.h @@ -15,10 +15,9 @@ void LabelInit(); constexpr int LABEL_ARGS_MAX = 5; using LabelCallback = bool (*)(const uint64_t* args); -Label* LabelCreate(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2, - const uint64_t* args); -void LabelDelete(Label* label); -void LabelSet(CommandBuffer* buffer, Label* label); +Label* LabelCreate(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args); +void LabelDelete(Label& label); +void LabelSet(CommandBuffer& buffer, Label& label); void LabelDrain(); [[nodiscard]] bool LabelInCallback() noexcept; diff --git a/src/graphics/host_gpu/objects/textureCommon.cpp b/src/graphics/host_gpu/objects/textureCommon.cpp index dbe695c41..bbd0c5004 100644 --- a/src/graphics/host_gpu/objects/textureCommon.cpp +++ b/src/graphics/host_gpu/objects/textureCommon.cpp @@ -5,6 +5,7 @@ #include "graphics/guest_gpu/gpu_defs.h" #include "graphics/guest_gpu/gpu_format.h" #include "graphics/host_gpu/graphicContext.h" +#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vulkanCommon.h" @@ -240,25 +241,26 @@ vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle) { return components; } -bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info) { +bool TextureCheckFormat(vk::ImageCreateInfo& image_info) { + auto& graphics = GetRenderContext().GetGraphics(); vk::ImageFormatProperties props {}; - if (ctx->GetImageFormatProperties(image_info->format, image_info->imageType, image_info->tiling, - image_info->usage, image_info->flags, - &props) == vk::Result::eErrorFormatNotSupported) { + if (graphics.GetImageFormatProperties(image_info.format, image_info.imageType, + image_info.tiling, image_info.usage, image_info.flags, + &props) == vk::Result::eErrorFormatNotSupported) { auto apply_fallback = [&](vk::Format replacement, const char* message) { - image_info->format = replacement; - const bool result = TextureCheckFormat(ctx, image_info); + image_info.format = replacement; + const bool result = TextureCheckFormat(image_info); LOGF("%s [%s]\n", message, (!result ? "FAIL" : "SUCCESS")); return result; }; - if (image_info->format == vk::Format::eR8G8B8A8Srgb) { + if (image_info.format == vk::Format::eR8G8B8A8Srgb) { // TODO() convert SRGB -> LINEAR in shader return apply_fallback( vk::Format::eR8G8B8A8Unorm, "replace vk::Format::eR8G8B8A8Srgb => vk::Format::eR8G8B8A8Unorm"); } - if (image_info->format == vk::Format::eB8G8R8A8Srgb) { + if (image_info.format == vk::Format::eB8G8R8A8Srgb) { // TODO() convert SRGB -> LINEAR in shader return apply_fallback( vk::Format::eB8G8R8A8Unorm, @@ -269,34 +271,31 @@ bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info) { return true; } -static bool TextureCheckFormatExact(GraphicContext* ctx, const vk::ImageCreateInfo& image_info) { +static bool TextureCheckFormatExact(const vk::ImageCreateInfo& image_info) { + auto& graphics = GetRenderContext().GetGraphics(); vk::ImageFormatProperties props {}; - return ctx->GetImageFormatProperties(image_info.format, image_info.imageType, image_info.tiling, - image_info.usage, image_info.flags, - &props) != vk::Result::eErrorFormatNotSupported; + return graphics.GetImageFormatProperties(image_info.format, image_info.imageType, + image_info.tiling, image_info.usage, image_info.flags, + &props) != vk::Result::eErrorFormatNotSupported; } -bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components) { - if (image_info->usage & vk::ImageUsageFlagBits::eStorage) { - if (components->r == vk::ComponentSwizzle::eR && - components->g == vk::ComponentSwizzle::eG && - components->b == vk::ComponentSwizzle::eB && - components->a == vk::ComponentSwizzle::eA) { +bool TextureCheckStorageSwizzle(vk::ImageCreateInfo& image_info, vk::ComponentMapping& components) { + if (image_info.usage & vk::ImageUsageFlagBits::eStorage) { + if (components.r == vk::ComponentSwizzle::eR && components.g == vk::ComponentSwizzle::eG && + components.b == vk::ComponentSwizzle::eB && components.a == vk::ComponentSwizzle::eA) { return true; } - if (components->r == vk::ComponentSwizzle::eB && - components->g == vk::ComponentSwizzle::eG && - components->b == vk::ComponentSwizzle::eR && - components->a == vk::ComponentSwizzle::eA && - image_info->format == vk::Format::eR8G8B8A8Srgb) { + if (components.r == vk::ComponentSwizzle::eB && components.g == vk::ComponentSwizzle::eG && + components.b == vk::ComponentSwizzle::eR && components.a == vk::ComponentSwizzle::eA && + image_info.format == vk::Format::eR8G8B8A8Srgb) { LOGF("replace vk::Format::eR8G8B8A8Srgb => vk::Format::eB8G8R8A8Srgb\n"); - components->r = vk::ComponentSwizzle::eR; - components->g = vk::ComponentSwizzle::eG; - components->b = vk::ComponentSwizzle::eB; - components->a = vk::ComponentSwizzle::eA; - image_info->format = vk::Format::eB8G8R8A8Srgb; + components.r = vk::ComponentSwizzle::eR; + components.g = vk::ComponentSwizzle::eG; + components.b = vk::ComponentSwizzle::eB; + components.a = vk::ComponentSwizzle::eA; + image_info.format = vk::Format::eB8G8R8A8Srgb; return true; } @@ -413,10 +412,9 @@ bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer layer_count % 6u == 0; } -vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj, +vk::ComponentMapping TextureCreateImage(VulkanImage& vk_obj, const TextureImageCreateParams& params) { - EXIT_IF(ctx == nullptr); - EXIT_IF(vk_obj == nullptr); + auto& graphics = GetRenderContext().GetGraphics(); EXIT_IF(params.owner == nullptr); const bool array_texture = TextureIsLayeredTexture(params.type); @@ -474,7 +472,7 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj image_info.samples = vk::SampleCountFlagBits::e1; const bool storage_view = TextureHasFormatUsage(params.view_usage, TextureFormatUsage::Storage); - if (storage_view && !TextureCheckStorageSwizzle(&image_info, &components)) { + if (storage_view && !TextureCheckStorageSwizzle(image_info, components)) { if (!params.storage_swizzle_fallback) { EXIT("swizzle is not supported"); } @@ -494,11 +492,11 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj const auto requested_usage = params.format_usage; const auto required_usage = params.required_format_usage; const bool has_optional_usage = static_cast(requested_usage & ~required_usage) != 0; - if (!TextureCheckFormatExact(ctx, image_info) && has_optional_usage) { + if (!TextureCheckFormatExact(image_info) && has_optional_usage) { auto required_info = image_info; required_info.usage = TextureGetUsage(required_usage); required_info.format = view_checked_format; - if (TextureCheckFormatExact(ctx, required_info)) { + if (TextureCheckFormatExact(required_info)) { static std::atomic_uint log_count {0}; if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { LOGF("\t %s usage 0x%08x is not supported for format %d, using required " @@ -511,39 +509,38 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj } } - if (!TextureCheckFormat(ctx, &image_info)) { + if (!TextureCheckFormat(image_info)) { if (has_optional_usage) { image_info.format = view_checked_format; image_info.usage = TextureGetUsage(required_usage); } - if (!has_optional_usage || !TextureCheckFormat(ctx, &image_info)) { + if (!has_optional_usage || !TextureCheckFormat(image_info)) { EXIT("format is not supported"); } } - vk_obj->extent.width = image_info.extent.width; - vk_obj->extent.height = image_info.extent.height; - vk_obj->layers = image_info.arrayLayers; - vk_obj->mip_levels = image_info.mipLevels; - vk_obj->format = image_info.format; - vk_obj->image = nullptr; - vk_obj->layout = image_info.initialLayout; + vk_obj.extent.width = image_info.extent.width; + vk_obj.extent.height = image_info.extent.height; + vk_obj.layers = image_info.arrayLayers; + vk_obj.mip_levels = image_info.mipLevels; + vk_obj.format = image_info.format; + vk_obj.image = nullptr; + vk_obj.layout = image_info.initialLayout; - vk_obj->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; + vk_obj.memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; - bool created = VulkanCreateImage(ctx, image_info, vk_obj); + bool created = graphics.CreateImage(image_info, vk_obj); EXIT_NOT_IMPLEMENTED(!created); return components; } -void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj, +void TextureCreateImageViews(VulkanImage& vk_obj, vk::ComponentMapping components, uint64_t type, uint32_t base_array, uint32_t base_level, uint32_t level_count, uint32_t depth, bool allow_cube_view, TextureFormatUsage view_usage) { - EXIT_IF(ctx == nullptr); - EXIT_IF(vk_obj == nullptr); - EXIT_IF(level_count == 0 || base_level + level_count > vk_obj->mip_levels); + auto& graphics = GetRenderContext().GetGraphics(); + EXIT_IF(level_count == 0 || base_level + level_count > vk_obj.mip_levels); const bool layered_texture = TextureIsLayeredTexture(type); const bool volume_texture = TextureIs3DTexture(type); @@ -559,9 +556,9 @@ void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj, create_info.sType = vk::StructureType::eImageViewCreateInfo; create_info.pNext = (usage_info.usage ? &usage_info : nullptr); create_info.flags = {}; - create_info.image = vk_obj->image; + create_info.image = vk_obj.image; create_info.viewType = vk::ImageViewType::e2D; - create_info.format = vk_obj->format; + create_info.format = vk_obj.format; create_info.components = components; create_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; create_info.subresourceRange.baseArrayLayer = (layered_texture ? base_array : 0); @@ -581,8 +578,8 @@ void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj, auto create_view = [&](int index) { const auto result = - ctx->device.createImageView(&create_info, nullptr, &vk_obj->image_view[index]); - if (result != vk::Result::eSuccess || vk_obj->image_view[index] == nullptr) { + graphics.device.createImageView(&create_info, nullptr, &vk_obj.image_view[index]); + if (result != vk::Result::eSuccess || vk_obj.image_view[index] == nullptr) { EXIT("failed to create texture image view: result=%d format=%d index=%d\n", static_cast(result), static_cast(create_info.format), index); } @@ -854,7 +851,7 @@ static uint64_t FmaskRegionCopySize(const BufferImageCopy& region) { sizeof(uint32_t); } -static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj, +static void UploadFmaskIdentity(VulkanImage& vk_obj, const std::vector& regions, vk::ImageLayout dst_layout, const char* owner) { constexpr uint32_t kIdentityFmaskPattern = 0x76543210u; @@ -878,7 +875,8 @@ static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj, words[i] = kIdentityFmaskPattern; } - Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), upload_size, upload_regions, dst_layout); + Transfer::UploadImage(vk_obj, temp_buf.Data(), upload_size, upload_regions, + dst_layout); } struct GpuTileElementLayout { @@ -887,31 +885,30 @@ struct GpuTileElementLayout { uint32_t tall = 1; }; -static bool GetGpuTileElementLayout(uint32_t fmt, GpuTileElementLayout* out) { - EXIT_IF(out == nullptr); +static bool GetGpuTileElementLayout(uint32_t fmt, GpuTileElementLayout& out) { if (const auto bytes = Prospero::NumBytesPerElement(fmt); bytes != 0) { - *out = {bytes, 1, 1}; + out = {bytes, 1, 1}; return true; } if (const auto bytes = Prospero::BlockCompressedBytesPerBlock(fmt); bytes != 0) { - *out = {bytes, 4, 4}; + out = {bytes, 4, 4}; return true; } return false; } -static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity, uint64_t* size) { - if (size == nullptr || offset > capacity || length > capacity - offset) { +static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity, uint64_t& size) { + if (offset > capacity || length > capacity - offset) { return false; } - *size = length; + size = length; return true; } bool TextureBuildGpuTileInfos(uint64_t size, const std::vector& regions, const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth, - uint64_t levels, std::vector* out_infos) { - if (out_infos == nullptr || size == 0 || levels == 0 || levels > 16 || depth == 0 || + uint64_t levels, std::vector& out_infos) { + if (size == 0 || levels == 0 || levels > 16 || depth == 0 || regions.size() != GetTextureRegionCount(depth, levels, layout.volume_texture) || Prospero::IsFmaskTextureFormat(fmt)) { return false; @@ -921,7 +918,7 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector& if (layout.tile_family == TileBlockFamily::RenderTarget64KB || layout.tile_family == TileBlockFamily::Depth64KB) { element.bytes = Prospero::RenderTargetBytesPerElement(fmt); - } else if (!GetGpuTileElementLayout(fmt, &element)) { + } else if (!GetGpuTileElementLayout(fmt, element)) { return false; } if (element.bytes == 0) { @@ -933,12 +930,12 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector& if (layout.volume_texture) { TileVolumeLayout volume {}; if (!TileGetTextureVolumeLayout(fmt, regions[0].width, regions[0].height, depth, - static_cast(levels), layout.tile, &volume)) { + static_cast(levels), layout.tile, volume)) { return false; } element = {volume.bytes_per_element, volume.texel_width, volume.texel_height}; TileBlockLayout block {}; - if (!TileGetBlockLayout(volume.family, element.bytes, &block)) return false; + if (!TileGetBlockLayout(volume.family, element.bytes, block)) return false; size_t region_base = 0; for (uint32_t level = 0; level < levels; ++level) { @@ -958,9 +955,9 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector& const uint64_t linear_span = static_cast(copy_depth - 1u) * linear_stride + layout.level_sizes[level].size; - if (!SetGpuTileSize(info.linear_offset, linear_span, size, &info.linear_size) || + if (!SetGpuTileSize(info.linear_offset, linear_span, size, info.linear_size) || !SetGpuTileSize(info.tiled_offset, volume.level_sizes[level], size, - &info.tiled_size)) { + info.tiled_size)) { return false; } info.linear_slice_stride = linear_stride; @@ -990,7 +987,7 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector& const bool tail = level >= layout.first_tail_level; const auto family = base_family; TileBlockLayout block {}; - if (!TileGetBlockLayout(family, element.bytes, &block)) { + if (!TileGetBlockLayout(family, element.bytes, block)) { return false; } const auto level_depth = GetTextureLevelDepth(depth, level, layout.volume_texture); @@ -1001,9 +998,9 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector& info.bytes_per_element = block.bytes_per_element; info.linear_offset = region.offset; info.tiled_offset = TextureUploadSliceSourceOffset(layout, level, z); - if (!SetGpuTileSize(info.linear_offset, level_size.size, size, &info.linear_size) || + if (!SetGpuTileSize(info.linear_offset, level_size.size, size, info.linear_size) || !SetGpuTileSize(info.tiled_offset, GetLevelSrcSize(level_size), size, - &info.tiled_size)) { + info.tiled_size)) { return false; } info.width = std::max((region.width + element.wide - 1u) / element.wide, 1u); @@ -1036,11 +1033,11 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector& if (infos.empty()) { return false; } - *out_infos = std::move(infos); + out_infos = std::move(infos); return true; } -void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data, +void TextureUploadGuestImage(VulkanImage& vk_obj, const void* src_data, uint64_t size, const std::vector& regions, const TextureUploadLayout& layout, uint32_t fmt, uint64_t width, uint64_t height, uint32_t depth, uint64_t levels, const char* owner, @@ -1051,21 +1048,21 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi owner, layout.tile, size, width, height, depth, layout.pitch, levels); } if (static_cast(layout.tile) == Prospero::TileMode::kLinear) { - Transfer::UploadImage(ctx, vk_obj, src_data, size, regions, dst_layout); + Transfer::UploadImage(vk_obj, src_data, size, regions, dst_layout); return; } if (layout.tile_family == TileBlockFamily::Depth64KB && Prospero::IsFmaskTextureFormat(fmt)) { - UploadFmaskIdentity(ctx, vk_obj, regions, dst_layout, owner); + UploadFmaskIdentity(vk_obj, regions, dst_layout, owner); return; } std::vector infos; - if (!TextureBuildGpuTileInfos(size, regions, layout, fmt, depth, levels, &infos)) { + if (!TextureBuildGpuTileInfos(size, regions, layout, fmt, depth, levels, infos)) { EXIT("%s: GPU tiled upload unsupported: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n", owner, fmt, layout.tile, size, width, height, depth, layout.pitch, levels); } - Transfer::UploadTiledImage(ctx, vk_obj, src_data, size, size, infos, regions, dst_layout); + Transfer::UploadTiledImage(vk_obj, src_data, size, size, infos, regions, dst_layout); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/objects/textureCommon.h b/src/graphics/host_gpu/objects/textureCommon.h index 777a26738..63ff5801f 100644 --- a/src/graphics/host_gpu/objects/textureCommon.h +++ b/src/graphics/host_gpu/objects/textureCommon.h @@ -83,8 +83,8 @@ struct TextureImageCreateParams { vk::ComponentSwizzle TextureGetComponentSwizzle(uint8_t s); vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle); -bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info); -bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components); +bool TextureCheckFormat(vk::ImageCreateInfo& image_info); +bool TextureCheckStorageSwizzle(vk::ImageCreateInfo& image_info, vk::ComponentMapping& components); vk::ImageUsageFlags TextureGetUsage(TextureFormatUsage usage); vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage); vk::Format TextureGetFormat(uint32_t fmt); @@ -99,9 +99,9 @@ bool TextureIs3DTexture(uint64_t type); bool TextureIsCubeTexture(uint64_t type); bool TextureIsLayeredTexture(uint64_t type); bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer_count); -vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* image, +vk::ComponentMapping TextureCreateImage(VulkanImage& image, const TextureImageCreateParams& params); -void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj, +void TextureCreateImageViews(VulkanImage& vk_obj, vk::ComponentMapping components, uint64_t type, uint32_t base_array, uint32_t base_level, uint32_t level_count, uint32_t depth, bool allow_cube_view, TextureFormatUsage view_usage); @@ -125,8 +125,8 @@ std::vector TextureBuildDownloadRegions(const std::vector& upload_regions); bool TextureBuildGpuTileInfos(uint64_t size, const std::vector& regions, const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth, - uint64_t levels, std::vector* infos); -void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data, + uint64_t levels, std::vector& infos); +void TextureUploadGuestImage(VulkanImage& vk_obj, const void* src_data, uint64_t size, const std::vector& regions, const TextureUploadLayout& layout, uint32_t fmt, uint64_t width, uint64_t height, uint32_t depth, uint64_t levels, const char* owner, diff --git a/src/graphics/host_gpu/renderer/bufferCache.cpp b/src/graphics/host_gpu/renderer/bufferCache.cpp index 08b5607ec..834cd3fbb 100644 --- a/src/graphics/host_gpu/renderer/bufferCache.cpp +++ b/src/graphics/host_gpu/renderer/bufferCache.cpp @@ -7,6 +7,7 @@ #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/objects/label.h" #include "graphics/host_gpu/renderer/render.h" +#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/resourceMutex.h" #include "graphics/host_gpu/renderer/textureCache.h" #include "graphics/host_gpu/transfer.h" @@ -38,22 +39,20 @@ constexpr uint64_t AlignReadbackCopySize(uint64_t size) noexcept { } struct SharedVulkanBufferOwner { - explicit SharedVulkanBufferOwner(GraphicContext* context): ctx(context) { - EXIT_IF(ctx == nullptr); - } + explicit SharedVulkanBufferOwner(GraphicContext& graphics): graphics(graphics) {} ~SharedVulkanBufferOwner() { if (buffer.buffer != nullptr) { - VulkanDeleteBuffer(ctx, &buffer); + graphics.DeleteBuffer(buffer); } } - GraphicContext* ctx = nullptr; + GraphicContext& graphics; VulkanBuffer buffer; }; -std::shared_ptr MakeSharedVulkanBuffer(GraphicContext* ctx) { - auto owner = std::make_shared(ctx); +std::shared_ptr MakeSharedVulkanBuffer() { + auto owner = std::make_shared(GetRenderContext().GetGraphics()); return {owner, &owner->buffer}; } @@ -149,21 +148,21 @@ bool PageOverlaps(uint64_t left, uint64_t left_size, uint64_t right, uint64_t ri } } // namespace -bool MergeOverlappingBufferCacheRange(BufferCacheRange* merged, +bool MergeOverlappingBufferCacheRange(BufferCacheRange& merged, BufferCacheRange candidate) noexcept { - if (merged == nullptr || merged->address == 0 || merged->size == 0 || candidate.address == 0 || - candidate.size == 0 || merged->size > UINT64_MAX - merged->address || + if (merged.address == 0 || merged.size == 0 || candidate.address == 0 || candidate.size == 0 || + merged.size > UINT64_MAX - merged.address || candidate.size > UINT64_MAX - candidate.address) { EXIT("BufferCache: invalid overlap-merge range\n"); } - const auto merged_end = merged->address + merged->size; + const auto merged_end = merged.address + merged.size; const auto candidate_end = candidate.address + candidate.size; - if (merged->address >= candidate_end || candidate.address >= merged_end) { + if (merged.address >= candidate_end || candidate.address >= merged_end) { return false; } - const auto address = std::min(merged->address, candidate.address); + const auto address = std::min(merged.address, candidate.address); const auto end = std::max(merged_end, candidate_end); - *merged = {.address = address, .size = end - address}; + merged = {.address = address, .size = end - address}; return true; } @@ -175,7 +174,6 @@ struct BufferCache::CachedBuffer { uint64_t vaddr = 0; uint64_t size = 0; uint64_t queue_mask = 0; - GraphicContext* ctx = nullptr; std::shared_ptr buffer; }; @@ -220,10 +218,7 @@ struct BufferCache::ReadbackWorker { } } - void Prepare(GraphicContext* graphic_context) { - if (graphic_context == nullptr) { - EXIT("BufferCache: cannot prepare readback without a graphics context\n"); - } + void Prepare() { auto current = state.load(std::memory_order_acquire); while (current == State::InitRequested || (current == State::Claimed && @@ -236,15 +231,11 @@ struct BufferCache::ReadbackWorker { EXIT("BufferCache: cannot prepare a stopping readback worker, state=%u\n", static_cast(current)); } - if (ctx != graphic_context || command == nullptr || mapped == nullptr || - readback.buffer == nullptr) { + if (command == nullptr || mapped == nullptr || readback.buffer == nullptr) { EXIT("BufferCache: initialized readback worker has invalid resources, state=%u " - "ctx=%p requested=%p " "command=%p mapped=%p buffer=%p\n", - static_cast(current), static_cast(ctx), - static_cast(graphic_context), - static_cast(command.get()), static_cast(mapped), - static_cast(readback.buffer)); + static_cast(current), static_cast(command.get()), + static_cast(mapped), static_cast(readback.buffer)); } return; } @@ -253,7 +244,6 @@ struct BufferCache::ReadbackWorker { EXIT("BufferCache: readback prepare requires uninitialized state, state=%u\n", static_cast(expected)); } - ctx = graphic_context; state.store(State::InitRequested, std::memory_order_release); state.notify_all(); while ((current = state.load(std::memory_order_acquire)) != State::Idle) { @@ -276,16 +266,15 @@ struct BufferCache::ReadbackWorker { const bool submissions_prepaused_now = GraphicsRunSubmissionLockHeld() || command_thread; const bool unsafe_gpu_lock = GraphicsRunGpuLockHeld() && !submissions_prepaused_now; if (unsafe_gpu_lock || LabelInCallback() || g_cache_lock_owner != nullptr || - ctx == nullptr || command == nullptr || mapped == nullptr || - readback.buffer == nullptr) { + command == nullptr || mapped == nullptr || readback.buffer == nullptr) { EXIT("BufferCache: unsafe readback request context, command_thread=%d " "submission_lock=%d " - "gpu_lock=%d label_callback=%d cache_lock=%p ctx=%p command=%p mapped=%p " + "gpu_lock=%d label_callback=%d cache_lock=%p command=%p mapped=%p " "buffer=%p\n", command_thread, GraphicsRunSubmissionLockHeld(), GraphicsRunGpuLockHeld(), LabelInCallback(), static_cast(g_cache_lock_owner), - static_cast(ctx), static_cast(command.get()), - static_cast(mapped), static_cast(readback.buffer)); + static_cast(command.get()), static_cast(mapped), + static_cast(readback.buffer)); } State expected = State::Idle; while (!state.compare_exchange_weak(expected, State::Claimed, std::memory_order_acq_rel)) { @@ -386,48 +375,46 @@ struct BufferCache::ReadbackWorker { if (current == State::Stopping) { command.reset(); if (mapped != nullptr) { - VulkanUnmapMemory(ctx, &readback.memory); + cache.m_graphics.UnmapMemory(readback.memory); mapped = nullptr; } if (readback.buffer != nullptr) { - VulkanDeleteBuffer(ctx, &readback); + cache.m_graphics.DeleteBuffer(readback); } state.store(State::Stopped, std::memory_order_release); state.notify_all(); return; } if (current == State::InitRequested) { - if (ctx == nullptr || command != nullptr || mapped != nullptr || - readback.buffer != nullptr) { - EXIT("BufferCache: invalid resources before readback initialization, ctx=%p " + if (command != nullptr || mapped != nullptr || readback.buffer != nullptr) { + EXIT("BufferCache: invalid resources before readback initialization, " "command=%p mapped=%p buffer=%p\n", - static_cast(ctx), static_cast(command.get()), - static_cast(mapped), + static_cast(command.get()), static_cast(mapped), static_cast(readback.buffer)); } - const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family; + const auto family = cache.m_graphics.queues[GraphicContext::QUEUE_UTIL].family; if (family == static_cast(-1) || - ctx->queues[GraphicContext::QUEUE_GFX].family != family) { + cache.m_graphics.queues[GraphicContext::QUEUE_GFX].family != family) { EXIT("BufferCache: utility and graphics queues must share a valid family, " "util=%u " "gfx=%u\n", - family, ctx->queues[GraphicContext::QUEUE_GFX].family); + family, cache.m_graphics.queues[GraphicContext::QUEUE_GFX].family); } for (int i = GraphicContext::QUEUE_COMPUTE_START; i < GraphicContext::QUEUE_COMPUTE_START + GraphicContext::QUEUE_COMPUTE_NUM; i++) { - if (ctx->queues[i].family != family) { + if (cache.m_graphics.queues[i].family != family) { EXIT("BufferCache: compute queue %d family mismatch, expected=%u " "actual=%u\n", - i, family, ctx->queues[i].family); + i, family, cache.m_graphics.queues[i].family); } } readback.usage = vk::BufferUsageFlagBits::eTransferDst; readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached; - VulkanCreateBuffer(ctx, READBACK_CAPACITY, &readback); - VulkanMapMemory(ctx, &readback.memory, &mapped); + cache.m_graphics.CreateBuffer(READBACK_CAPACITY, readback); + cache.m_graphics.MapMemory(readback.memory, mapped); command = std::make_unique(GraphicContext::QUEUE_UTIL); state.store(State::Idle, std::memory_order_release); state.notify_all(); @@ -528,7 +515,6 @@ struct BufferCache::ReadbackWorker { BufferCache& cache; std::atomic state {State::Uninitialized}; - GraphicContext* ctx = nullptr; VulkanBuffer readback {}; void* mapped = nullptr; std::unique_ptr command; @@ -542,8 +528,9 @@ struct BufferCache::ReadbackWorker { std::thread thread; }; -BufferCache::BufferCache(PageManager& page_manager, ResourceMutex& resource_mutex) - : m_memory_tracker(page_manager), m_page_manager(page_manager), +BufferCache::BufferCache(GraphicContext& graphics, PageManager& page_manager, + ResourceMutex& resource_mutex) + : m_graphics(graphics), m_memory_tracker(page_manager), m_page_manager(page_manager), m_resource_mutex(resource_mutex) { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); m_readback = std::make_unique(*this); @@ -563,7 +550,7 @@ BufferCache::~BufferCache() { } } if (!m_buffers.empty()) { - Transfer::WaitForGraphicsIdle(m_buffers.begin()->second->ctx); + Transfer::WaitForGraphicsIdle(); } m_buffers.clear(); } @@ -629,8 +616,8 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) { const auto ranges = m_gpu_modified_ranges.Intersections(address, bytes); for (const auto& range: ranges) { std::vector data(range.size); - Transfer::DownloadBuffer(cached->ctx, cached->buffer.get(), - range.address - begin, data.data(), range.size); + Transfer::DownloadBuffer(*cached->buffer, range.address - begin, data.data(), + range.size); Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size()); downloaded += range.size; } @@ -659,19 +646,15 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) { } } -std::pair BufferCache::ObtainBuffer(CommandBuffer* command, - GraphicContext* ctx, uint64_t vaddr, - uint64_t size, bool is_written, - bool is_read, bool is_formatted) { - if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr || - vaddr == 0 || size == 0 || size > UINT64_MAX - vaddr || command->GetQueue() < 0 || - command->GetQueue() >= 64) { - EXIT("BufferCache: invalid buffer request, command=%p queue=%d ctx=%p addr=0x%016" PRIx64 +BufferBinding BufferCache::ObtainBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size, + bool is_written, bool is_read, bool is_formatted) { + if (command.IsInvalid() || command.IsExecute() || vaddr == 0 || size == 0 || + size > UINT64_MAX - vaddr || command.GetQueue() < 0 || command.GetQueue() >= 64) { + EXIT("BufferCache: invalid buffer request, queue=%d addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", - static_cast(command), command == nullptr ? -1 : command->GetQueue(), - static_cast(ctx), vaddr, size); + command.GetQueue(), vaddr, size); } - const auto queue = static_cast(command->GetQueue()); + const auto queue = static_cast(command.GetQueue()); const auto queue_mask = uint64_t {1} << queue; ValidateGpuAccess(vaddr, size, is_read, is_written); const auto begin = AlignDown(vaddr); @@ -688,13 +671,13 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com !texture_region.gpu_metadata_bytes) { std::array guest_data; if (Libs::LibKernel::Memory::TryReadBacking(vaddr, guest_data.data(), size)) { - VulkanBuffer* stream_buffer = nullptr; - vk::DeviceSize stream_offset = 0; - vk::DeviceSize stream_range = 0; - const auto stream_alignment = std::max(ctx->StorageMinAlignment(), 16); - if (UploadHostData(command, ctx, guest_data.data(), size, stream_alignment, - &stream_buffer, &stream_offset, &stream_range)) { - return {stream_buffer, stream_offset}; + VulkanBuffer* stream_buffer = nullptr; + vk::DeviceSize stream_offset = 0; + vk::DeviceSize stream_range = 0; + const auto stream_alignment = std::max(m_graphics.StorageMinAlignment(), 16); + if (UploadHostData(command, guest_data.data(), size, stream_alignment, stream_buffer, + stream_offset, stream_range)) { + return {*stream_buffer, stream_offset}; } } } @@ -728,7 +711,7 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com } } if (is_written) { - m_readback->Prepare(ctx); + m_readback->Prepare(); } FaultSafeCacheLock lock(this, m_mutex); @@ -749,7 +732,7 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com if (first != m_buffers.begin()) { auto previous = std::prev(first); if (MergeOverlappingBufferCacheRange( - &merged, {previous->second->vaddr, previous->second->size})) { + merged, {previous->second->vaddr, previous->second->size})) { first = previous; } } @@ -758,7 +741,7 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com break; } if (MergeOverlappingBufferCacheRange( - &merged, {candidate->second->vaddr, candidate->second->size})) { + merged, {candidate->second->vaddr, candidate->second->size})) { overlaps.push_back(candidate); } } @@ -766,11 +749,10 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com if (!overlaps.empty()) { for (const auto& overlap: overlaps) { auto& old = *overlap->second; - if (old.ctx != ctx || old.buffer == nullptr || old.buffer->buffer == nullptr) { + if (old.buffer == nullptr || old.buffer->buffer == nullptr) { EXIT("BufferCache: invalid overlapping buffer owner, addr=0x%016" PRIx64 - " size=0x%016" PRIx64 " owner_ctx=%p requested_ctx=%p buffer=%p\n", - old.vaddr, old.size, static_cast(old.ctx), - static_cast(ctx), static_cast(old.buffer.get())); + " size=0x%016" PRIx64 " buffer=%p\n", + old.vaddr, old.size, static_cast(old.buffer.get())); } if (!CanMergeBufferCacheQueueMask(old.queue_mask, queue)) { EXIT("BufferCache: cross-queue overlap merge is unsupported, " @@ -786,8 +768,8 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com }, [&]() noexcept { for (const auto& [upload_vaddr, upload_size]: uploads) { - Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex, - old.buffer.get(), upload_vaddr - old.vaddr, + Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *old.buffer, + upload_vaddr - old.vaddr, reinterpret_cast(upload_vaddr), upload_size); } @@ -797,16 +779,15 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com auto cached = std::make_unique(); cached->vaddr = merged.address; cached->size = merged.size; - cached->ctx = ctx; - cached->buffer = MakeSharedVulkanBuffer(ctx); + cached->buffer = MakeSharedVulkanBuffer(); cached->buffer->usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eStorageBuffer; cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; - VulkanCreateBuffer(ctx, cached->size, cached->buffer.get()); + m_graphics.CreateBuffer(cached->size, *cached->buffer); if (!overlaps.empty()) { - auto vk_buffer = command->Handle(); + auto vk_buffer = command.Handle(); std::vector before; before.reserve(overlaps.size() + 1); for (const auto& overlap: overlaps) { @@ -854,7 +835,7 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands, vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr); for (const auto& overlap: overlaps) { - command->RetainResourceUntilFence(overlap->second->buffer); + command.RetainResourceUntilFence(overlap->second->buffer); m_buffers.erase(overlap); } } @@ -871,8 +852,8 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com }, [&]() noexcept { for (const auto& [upload_vaddr, upload_size]: ranges) { - Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex, - cached.buffer.get(), upload_vaddr - cached.vaddr, + Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *cached.buffer, + upload_vaddr - cached.vaddr, reinterpret_cast(upload_vaddr), upload_size); } }); @@ -880,47 +861,46 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com m_gpu_modified_ranges.Add(vaddr, size); } cached.queue_mask |= queue_mask; - command->RetainResourceUntilFence(cached.buffer); - return {cached.buffer.get(), vaddr - cached.vaddr}; + command.RetainResourceUntilFence(cached.buffer); + return {*cached.buffer, vaddr - cached.vaddr}; } -bool BufferCache::UploadHostData(CommandBuffer* command, GraphicContext* ctx, const void* src, - uint64_t size, uint64_t alignment, VulkanBuffer** out_buffer, - uint64_t* out_offset, uint64_t* out_range) { - if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr) { +bool BufferCache::UploadHostData(CommandBuffer& command, const void* src, uint64_t size, + uint64_t alignment, VulkanBuffer*& out_buffer, + uint64_t& out_offset, uint64_t& out_range) { + if (command.IsInvalid() || command.IsExecute()) { EXIT("BufferCache: host stream upload requires a recording command buffer\n"); } - return command->m_host_stream.Copy(ctx, src, size, alignment, out_buffer, out_offset, - out_range); + return command.m_host_stream.Copy(src, size, alignment, out_buffer, out_offset, out_range); } -VulkanBuffer* BufferCache::ObtainNullBuffer(CommandBuffer* command, GraphicContext* ctx) { - if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr) { +VulkanBuffer& BufferCache::ObtainNullBuffer(CommandBuffer& command) { + if (command.IsInvalid() || command.IsExecute()) { EXIT("BufferCache: null buffer requires a graphics context\n"); } FaultSafeCacheLock lock(this, m_mutex); if (m_null_buffer == nullptr) { // robustBufferAccess makes every fetch safe; TODO: Use a // persistent 16-byte fallback when Vulkan null vertex descriptors are unavailable. - auto buffer = MakeSharedVulkanBuffer(ctx); + auto buffer = MakeSharedVulkanBuffer(); buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer; buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached; - VulkanCreateBuffer(ctx, 16, buffer.get()); + m_graphics.CreateBuffer(16, *buffer); void* data = nullptr; - VulkanMapMemory(ctx, &buffer->memory, &data); + m_graphics.MapMemory(buffer->memory, data); std::memset(data, 0, 16); - VulkanUnmapMemory(ctx, &buffer->memory); + m_graphics.UnmapMemory(buffer->memory); m_null_buffer = std::move(buffer); } // The buffer remains cache-persistent, while every recorded consumer keeps the allocation // alive until its own fence even if an unrelated command processor resets the global cache. - command->RetainResourceUntilFence(m_null_buffer); - return m_null_buffer.get(); + command.RetainResourceUntilFence(m_null_buffer); + return *m_null_buffer; } BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t size) { @@ -949,8 +929,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t --owner; auto& cached = *owner->second; const auto offset = address - cached.vaddr; - if (offset > cached.size || bytes > cached.size - offset || cached.ctx == nullptr || - cached.buffer == nullptr || cached.buffer->buffer == nullptr) { + if (offset > cached.size || bytes > cached.size - offset || cached.buffer == nullptr || + cached.buffer->buffer == nullptr) { EXIT("BufferCache: GPU image-source bytes have no containing native buffer\n"); } return cached; @@ -964,14 +944,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t vaddr, size, GraphicsRunIsCommandProcessorThread(), GraphicsRunSubmissionLockHeld(), LabelInCallback()); } - std::vector waited; - for (const auto& range: dirty_ranges) { - auto& owner = find_owner(range.address, range.size); - if (std::find(waited.begin(), waited.end(), owner.ctx) == waited.end()) { - Transfer::WaitForGraphicsIdle(owner.ctx); - waited.push_back(owner.ctx); - } - } + Transfer::WaitForGraphicsIdle(); auto backing_writes = ReserveBackingWrites(m_page_manager, dirty_ranges); uint64_t downloaded = 0; m_memory_tracker.ForEachDownloadRange( @@ -990,8 +963,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t auto& owner = find_owner(range.address, range.size); const auto buffer_offset = range.address - owner.vaddr; std::vector data(range.size); - Transfer::DownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset, - data.data(), range.size); + Transfer::DownloadBuffer(*owner.buffer, buffer_offset, data.data(), range.size); Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size()); downloaded += range.size; } @@ -1013,7 +985,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t if (offset > cached.size || size > cached.size - offset) { return {nullptr, 0, vaddr, size, true, cpu_modified}; } - if (cached.ctx == nullptr || cached.buffer == nullptr || cached.buffer->buffer == nullptr) { + if (cached.buffer == nullptr || cached.buffer->buffer == nullptr) { EXIT("BufferCache: containing image source is inconsistent\n"); } if (cpu_modified) { @@ -1025,8 +997,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t }, [&]() noexcept { for (const auto& [address, bytes]: uploads) { - Transfer::UploadBuffer(cached.ctx, Transfer::StagingBufferType::Vertex, - cached.buffer.get(), address - cached.vaddr, + Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *cached.buffer, + address - cached.vaddr, reinterpret_cast(address), bytes); } }); @@ -1047,15 +1019,14 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t } namespace { -vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, uint64_t size, +vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer& buffer, uint64_t offset, uint64_t size, vk::AccessFlags source, vk::AccessFlags destination) { - if (buffer == nullptr || buffer->buffer == nullptr || size == 0 || - offset > buffer->buffer_size || size > buffer->buffer_size - offset) { + if (buffer.buffer == nullptr || size == 0 || offset > buffer.buffer_size || + size > buffer.buffer_size - offset) { EXIT("BufferCache: invalid DMA barrier, buffer=%p handle=%p offset=0x%016" PRIx64 " size=0x%016" PRIx64 " buffer_size=0x%016" PRIx64 "\n", - static_cast(buffer), - buffer == nullptr ? nullptr : static_cast(buffer->buffer), offset, size, - buffer == nullptr ? 0 : buffer->buffer_size); + static_cast(&buffer), static_cast(buffer.buffer), offset, + size, buffer.buffer_size); } vk::BufferMemoryBarrier barrier {}; barrier.sType = vk::StructureType::eBufferMemoryBarrier; @@ -1063,23 +1034,19 @@ vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, ui barrier.dstAccessMask = destination; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.buffer = buffer->buffer; + barrier.buffer = buffer.buffer; barrier.offset = offset; barrier.size = size; return barrier; } -vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer* command) { - if (command == nullptr) { - EXIT("BufferCache: invalid DMA command buffer, command=%p\n", - static_cast(command)); - } - return command->Handle(); +vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer& command) { + return command.Handle(); } } // namespace -void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, - uint64_t size, uint32_t value) { +void BufferCache::FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, + uint32_t value) { if ((vaddr & 3u) != 0 || (size & 3u) != 0) { EXIT("BufferCache: fill range must be dword aligned, addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", @@ -1114,15 +1081,16 @@ void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64 vaddr, size); } } - const auto [dst, dst_offset] = ObtainBuffer(command, ctx, vaddr, size, true, false); + EXIT_IF(command == nullptr); + const auto [dst, dst_offset] = ObtainBuffer(*command, vaddr, size, true, false); const auto before = MakeDmaBarrier( dst, dst_offset, size, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferWrite); - const auto vk_buffer = GetDmaCommandBuffer(command); + const auto vk_buffer = GetDmaCommandBuffer(*command); vk_buffer.pipelineBarrier( vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &before, 0, nullptr); - vk_buffer.fillBuffer(dst->buffer, dst_offset, size, value); + vk_buffer.fillBuffer(dst.buffer, dst_offset, size, value); const auto after = MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite); @@ -1131,8 +1099,8 @@ void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64 vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr); } -void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t dst_vaddr, - uint64_t src_vaddr, uint64_t size) { +void BufferCache::CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, + uint64_t size) { if (dst_vaddr == 0 || src_vaddr == 0 || size == 0 || ((dst_vaddr | src_vaddr | size) & 3u) != 0 || size > UINT64_MAX - dst_vaddr || size > UINT64_MAX - src_vaddr || @@ -1195,10 +1163,11 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64 src_vaddr, dst_vaddr, size); } } - const auto [src, src_offset] = ObtainBuffer(command, ctx, src_vaddr, size, false, true); + EXIT_IF(command == nullptr); + const auto [src, src_offset] = ObtainBuffer(*command, src_vaddr, size, false, true); const auto [dst, dst_offset] = - ObtainBuffer(command, ctx, dst_vaddr, size, true, false, dst_image_transition); - if (src == dst && src_offset < dst_offset + size && dst_offset < src_offset + size) { + ObtainBuffer(*command, dst_vaddr, size, true, false, dst_image_transition); + if (&src == &dst && src_offset < dst_offset + size && dst_offset < src_offset + size) { EXIT("BufferCache: resolved Vulkan copy ranges overlap, src_offset=0x%016" PRIx64 " dst_offset=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", src_offset, dst_offset, size); @@ -1210,12 +1179,12 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64 MakeDmaBarrier(src, src_offset, size, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead), }; - const auto vk_buffer = GetDmaCommandBuffer(command); + const auto vk_buffer = GetDmaCommandBuffer(*command); vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion, 0, nullptr, 2, before, 0, nullptr); const vk::BufferCopy copy {src_offset, dst_offset, size}; - vk_buffer.copyBuffer(src->buffer, dst->buffer, 1, ©); + vk_buffer.copyBuffer(src.buffer, dst.buffer, 1, ©); const vk::BufferMemoryBarrier after[] = { MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite), diff --git a/src/graphics/host_gpu/renderer/bufferCache.h b/src/graphics/host_gpu/renderer/bufferCache.h index a53c65345..27db90576 100644 --- a/src/graphics/host_gpu/renderer/bufferCache.h +++ b/src/graphics/host_gpu/renderer/bufferCache.h @@ -35,7 +35,12 @@ struct BufferCacheRange { uint64_t size = 0; }; -[[nodiscard]] bool MergeOverlappingBufferCacheRange(BufferCacheRange* merged, +struct BufferBinding { + VulkanBuffer& buffer; + uint64_t offset; +}; + +[[nodiscard]] bool MergeOverlappingBufferCacheRange(BufferCacheRange& merged, BufferCacheRange candidate) noexcept; [[nodiscard]] bool CanMergeBufferCacheQueueMask(uint64_t queue_mask, uint32_t queue) noexcept; @@ -46,27 +51,25 @@ public: return vaddr & (CACHING_PAGE_SIZE - 1); } - BufferCache(PageManager& page_manager, ResourceMutex& resource_mutex); + BufferCache(GraphicContext& graphics, PageManager& page_manager, ResourceMutex& resource_mutex); ~BufferCache(); KYTY_CLASS_NO_COPY(BufferCache); [[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size, PageFaultPhase phase) noexcept; void UnmapMemory(uint64_t vaddr, uint64_t size); - [[nodiscard]] std::pair - ObtainBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, uint64_t size, - bool is_written = false, bool is_read = true, bool is_formatted = false); + [[nodiscard]] BufferBinding ObtainBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size, + bool is_written = false, bool is_read = true, + bool is_formatted = false); // Emulator-owned, CPU-current scratch only. Guest ranges must use ObtainBuffer so page // ownership is resolved before any CPU access. - [[nodiscard]] bool UploadHostData(CommandBuffer* command, GraphicContext* ctx, const void* src, - uint64_t size, uint64_t alignment, VulkanBuffer** out_buffer, - uint64_t* out_offset, uint64_t* out_range); - [[nodiscard]] VulkanBuffer* ObtainNullBuffer(CommandBuffer* command, GraphicContext* ctx); + [[nodiscard]] bool UploadHostData(CommandBuffer& command, const void* src, uint64_t size, + uint64_t alignment, VulkanBuffer*& out_buffer, + uint64_t& out_offset, uint64_t& out_range); + [[nodiscard]] VulkanBuffer& ObtainNullBuffer(CommandBuffer& command); [[nodiscard]] BufferImageCopySource ObtainBufferForImage(uint64_t vaddr, uint64_t size); - void FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, uint64_t size, - uint32_t value); - void CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t dst_vaddr, - uint64_t src_vaddr, uint64_t size); + void FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, uint32_t value); + void CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size); [[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size); [[nodiscard]] bool IsRegionCpuModified(uint64_t vaddr, uint64_t size); [[nodiscard]] bool IsRegionGpuModified(uint64_t vaddr, uint64_t size); @@ -80,6 +83,7 @@ private: struct CachedBuffer; struct ReadbackWorker; + GraphicContext& m_graphics; Common::Mutex m_mutex; std::shared_ptr m_null_buffer; // TODO: add LRU cache diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp index 39652b3c3..17e7f680c 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp @@ -25,15 +25,13 @@ namespace Libs::Graphics { static std::atomic g_render_color_log_count = 0; // NOLINTNEXTLINE(readability-function-cognitive-complexity) -void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, - RenderColorInfo* r, uint32_t render_target_slice_offset, - uint32_t render_target_slot, bool ignore_target_mask, - bool reuse_existing_render_texture) { +void ResolveRenderColorTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderColorInfo& r, + uint32_t render_target_slice_offset, uint32_t render_target_slot, + bool ignore_target_mask, bool reuse_existing_render_texture) { KYTY_PROFILER_FUNCTION(); + const auto& hw = buffer.GetRegisters(); - EXIT_IF(r == nullptr); - - const auto rt_slot = (render_target_slot == UINT32_MAX ? render_target_first_bound_slot(hw) + const auto rt_slot = (render_target_slot == UINT32_MAX ? render_target_first_bound_slot(buffer) : render_target_slot); const auto& rt = hw.GetRenderTarget(rt_slot); auto mask = render_target_mask_slot(hw.GetRenderTargetMask(), rt_slot); @@ -41,8 +39,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H mask = 0x0f; } - r->target_slot = rt_slot; - r->export_mapping = {}; + r.target_slot = rt_slot; + r.export_mapping = {}; if (rt.base.addr == 0 || mask == 0) { if (graphics_debug_dump_enabled()) { @@ -58,17 +56,17 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H } // No color output - r->type = RenderColorType::NoColorOutput; - r->base_addr = 0; - r->vulkan_buffer = nullptr; - r->vulkan_view = nullptr; - r->format = vk::Format::eUndefined; - r->extent = {}; - r->base_mip_level = 0; - r->buffer_size = 0; - r->samples = 1; - r->color_clear_enable = false; - r->color_clear_value = {}; + r.type = RenderColorType::NoColorOutput; + r.base_addr = 0; + r.vulkan_buffer = nullptr; + r.vulkan_view = nullptr; + r.format = vk::Format::eUndefined; + r.extent = {}; + r.base_mip_level = 0; + r.buffer_size = 0; + r.samples = 1; + r.color_clear_enable = false; + r.color_clear_value = {}; return; } const auto samples = render_sample_count(rt.attrib.num_fragments); @@ -88,7 +86,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H rt.view.base_array_slice_index, rt.view.last_array_slice_index, render_target_slice_offset); } - r->base_array_layer = view.base_layer; + r.base_array_layer = view.base_layer; const uint32_t levels = rt.attrib2.num_mip_levels + 1u; if (levels == 0 || levels > 16 || rt.view.current_mip_level >= levels) { EXIT("unsupported render-target mip range: current=%u levels=%u\n", @@ -113,8 +111,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H // SRGB clear words are still encoded as normalized component values. // Fast color clears are metadata driven and must be handled explicitly when // that metadata path is implemented; render-pass load must preserve contents. - r->color_clear_enable = false; - r->color_clear_value = {}; + r.color_clear_enable = false; + r.color_clear_value = {}; uint32_t width = 0; uint32_t height = 0; @@ -189,9 +187,9 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H } else { valid_layout = levels == 1 ? TileGetRenderTargetSize(width, height, pitch, bytes_per_element, - &layout, rt.attrib.num_fragments) + layout, rt.attrib.num_fragments) : TileGetRenderTargetMipLayout(width, height, pitch, bytes_per_element, - levels, &layout, nullptr, nullptr); + levels, layout, nullptr, nullptr); } if (!valid_layout) { EXIT("unsupported render-target layout: %ux%u pitch=%u bytes=%u levels=%u\n", width, @@ -257,23 +255,22 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H target.levels = levels; target.layers = view.image_layers; target.samples = samples; - auto* texture_cache = g_render_ctx->GetTextureCache(); - auto* buffer_vulkan = - texture_cache->FindRenderTarget(buffer, g_render_ctx->GetGraphicCtx(), target); - r->type = RenderColorType::RenderTexture; - r->base_addr = rt.base.addr; - r->vulkan_buffer = buffer_vulkan; - r->vulkan_view = texture_cache->GetRenderTargetAttachmentView( - g_render_ctx->GetGraphicCtx(), buffer_vulkan, target.format, rt.view.current_mip_level, - view.base_layer, view.layer_count); - r->format = target.format; - r->extent = view_extent; - r->base_mip_level = rt.view.current_mip_level; - r->buffer_size = backing_size; - r->samples = samples; - r->export_mapping = target_format.export_mapping; - r->color_clear_enable = buffer_vulkan->initial_clear_pending; - r->color_clear_value = {}; + auto& texture_cache = GetRenderContext().GetTextureCache(); + auto& buffer_vulkan = texture_cache.FindRenderTarget(buffer, target); + r.type = RenderColorType::RenderTexture; + r.base_addr = rt.base.addr; + r.vulkan_buffer = &buffer_vulkan; + r.vulkan_view = texture_cache.GetRenderTargetAttachmentView( + buffer_vulkan, target.format, rt.view.current_mip_level, view.base_layer, + view.layer_count); + r.format = target.format; + r.extent = view_extent; + r.base_mip_level = rt.view.current_mip_level; + r.buffer_size = backing_size; + r.samples = samples; + r.export_mapping = target_format.export_mapping; + r.color_clear_enable = buffer_vulkan.initial_clear_pending; + r.color_clear_value = {}; } else { if (samples != 1) { EXIT("multisampled display render targets are unsupported\n"); @@ -305,16 +302,16 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H } EXIT_NOT_IMPLEMENTED(video_image.size < size); EXIT_NOT_IMPLEMENTED(video_image.pitch != pitch); - r->type = RenderColorType::DisplayBuffer; - r->base_addr = rt.base.addr; - r->vulkan_buffer = video_image.image; - r->vulkan_view = video_image.image->image_view[VulkanImage::VIEW_DEFAULT]; - r->format = video_image.image->format; - r->extent = video_image.image->extent; - r->base_mip_level = 0; - r->buffer_size = video_image.size; - r->samples = 1; - r->export_mapping = target_format.export_mapping; + r.type = RenderColorType::DisplayBuffer; + r.base_addr = rt.base.addr; + r.vulkan_buffer = video_image.image; + r.vulkan_view = video_image.image->image_view[VulkanImage::VIEW_DEFAULT]; + r.format = video_image.image->format; + r.extent = video_image.image->extent; + r.base_mip_level = 0; + r.buffer_size = video_image.size; + r.samples = 1; + r.export_mapping = target_format.export_mapping; } } @@ -324,7 +321,7 @@ void MarkRenderTargetGpuWritten(const RenderColorInfo& target) { if (with_color) { if (target.type == RenderColorType::RenderTexture || target.type == RenderColorType::DisplayBuffer) { - g_render_ctx->GetTextureCache()->MarkGpuWritten(target.vulkan_buffer); + GetRenderContext().GetTextureCache().MarkGpuWritten(*target.vulkan_buffer); } else { EXIT("unknown writable render-color resource type\n"); } diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.h b/src/graphics/host_gpu/renderer/colorRenderTarget.h index b99346b37..d97aa9d69 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.h +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.h @@ -9,13 +9,9 @@ namespace Libs::Graphics { -class CommandBuffer; +class RenderCommandBuffer; struct VulkanImage; -namespace HW { -class Context; -} // namespace HW - enum class RenderColorType { NoColorOutput, DisplayBuffer, @@ -39,8 +35,8 @@ struct RenderColorInfo { vk::ClearColorValue color_clear_value {}; }; -void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, - RenderColorInfo* r, uint32_t render_target_slice_offset = 0, +void ResolveRenderColorTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderColorInfo& r, + uint32_t render_target_slice_offset = 0, uint32_t render_target_slot = UINT32_MAX, bool ignore_target_mask = false, bool reuse_existing_render_texture = false); diff --git a/src/graphics/host_gpu/renderer/context.cpp b/src/graphics/host_gpu/renderer/context.cpp index 6a669be5b..bd318edff 100644 --- a/src/graphics/host_gpu/renderer/context.cpp +++ b/src/graphics/host_gpu/renderer/context.cpp @@ -23,8 +23,11 @@ #include #include #include +#include namespace Libs::Graphics { static std::atomic g_command_buffer_submit_seq = 0; +static bool g_render_initialized = false; +static std::mutex g_render_init_mutex; static void RequireValidQueueId(int queue_id) { EXIT_IF(queue_id < 0 || queue_id >= GraphicContext::QUEUES_NUM); @@ -65,9 +68,18 @@ private: std::array m_pools {}; }; -RenderContext* g_render_ctx = nullptr; +static RenderContext* g_render_ctx = nullptr; static thread_local CommandPool g_command_pool; +bool HasRenderContext() noexcept { + return g_render_ctx != nullptr; +} + +RenderContext& GetRenderContext() { + EXIT_IF(g_render_ctx == nullptr); + return *g_render_ctx; +} + FenceResourceRetainer::~FenceResourceRetainer() { if (!m_resources.empty()) { EXIT("fence resource retainer destroyed before release\n"); @@ -90,9 +102,9 @@ void FenceResourceRetainer::ReleaseAfterFence() noexcept { } void GraphicsRenderInit() { - EXIT_IF(g_render_ctx != nullptr); - - g_render_ctx = new RenderContext; + std::scoped_lock lock(g_render_init_mutex); + EXIT_IF(g_render_initialized || g_render_ctx != nullptr); + g_render_initialized = true; } void GraphicsRenderReleaseThreadCommandPools() { @@ -102,32 +114,43 @@ void GraphicsRenderReleaseThreadCommandPools() { } void GraphicsRenderCreateContext() { - EXIT_IF(g_render_ctx == nullptr); + std::scoped_lock lock(g_render_init_mutex); + EXIT_IF(!g_render_initialized); + if (g_render_ctx == nullptr) { + g_render_ctx = new RenderContext(WindowGetGraphicContext()); + } +} - g_render_ctx->SetGraphicCtx(WindowGetGraphicContext()); +void GraphicsRenderSetContext(RenderContext& context) { + std::scoped_lock lock(g_render_init_mutex); + EXIT_IF(!g_render_initialized || g_render_ctx != nullptr); + g_render_ctx = &context; +} + +CommandBuffer::CommandBuffer(int queue) + : m_graphics(GetRenderContext().GetGraphics()), m_queue(queue), m_host_stream(m_graphics) { + Allocate(); } void CommandPool::Create(int queue_id) { RequireValidQueueId(queue_id); - EXIT_IF(g_render_ctx == nullptr); - auto* ctx = g_render_ctx->GetGraphicCtx(); - auto*& pool = m_pools[queue_id]; + auto& graphics = GetRenderContext().GetGraphics(); + auto*& pool = m_pools[queue_id]; EXIT_IF(pool != nullptr); - EXIT_IF(ctx == nullptr); - EXIT_IF(ctx->device == nullptr); - EXIT_IF(ctx->queues[queue_id].family == static_cast(-1)); + EXIT_IF(graphics.device == nullptr); + EXIT_IF(graphics.queues[queue_id].family == static_cast(-1)); pool = new VulkanCommandPool; vk::CommandPoolCreateInfo pool_info {}; pool_info.sType = vk::StructureType::eCommandPoolCreateInfo; pool_info.pNext = nullptr; - pool_info.queueFamilyIndex = ctx->queues[queue_id].family; + pool_info.queueFamilyIndex = graphics.queues[queue_id].family; pool_info.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer; - const auto result = ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool); + const auto result = graphics.device.createCommandPool(&pool_info, nullptr, &pool->pool); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool->pool == nullptr); pool->buffers_count = 8; @@ -142,7 +165,7 @@ void CommandPool::Create(int queue_id) { alloc_info.level = vk::CommandBufferLevel::ePrimary; alloc_info.commandBufferCount = pool->buffers_count; - if (ctx->device.allocateCommandBuffers(&alloc_info, pool->buffers.get()) != + if (graphics.device.allocateCommandBuffers(&alloc_info, pool->buffers.get()) != vk::Result::eSuccess) { EXIT("Can't allocate command buffers"); } @@ -155,7 +178,7 @@ void CommandPool::Create(int queue_id) { fence_info.pNext = nullptr; fence_info.flags = vk::FenceCreateFlagBits::eSignaled; - if (ctx->device.createFence(&fence_info, nullptr, &pool->fences[i]) != + if (graphics.device.createFence(&fence_info, nullptr, &pool->fences[i]) != vk::Result::eSuccess) { EXIT("Can't create fence"); } @@ -165,7 +188,7 @@ void CommandPool::Create(int queue_id) { semaphore_info.pNext = nullptr; semaphore_info.flags = {}; - if (ctx->device.createSemaphore(&semaphore_info, nullptr, &pool->semaphores[i]) != + if (graphics.device.createSemaphore(&semaphore_info, nullptr, &pool->semaphores[i]) != vk::Result::eSuccess) { EXIT("Can't create semaphore"); } @@ -177,21 +200,21 @@ void CommandPool::Create(int queue_id) { } void CommandPool::DeleteAll() { - auto* ctx = g_render_ctx->GetGraphicCtx(); + auto& graphics = GetRenderContext().GetGraphics(); for (auto& pool: m_pools) { if (pool != nullptr) { - EXIT_IF(ctx == nullptr); - EXIT_IF(ctx->device == nullptr); + EXIT_IF(graphics.device == nullptr); for (uint32_t i = 0; i < pool->buffers_count; i++) { - ctx->device.destroySemaphore(pool->semaphores[i], nullptr); - ctx->device.destroyFence(pool->fences[i], nullptr); + graphics.device.destroySemaphore(pool->semaphores[i], nullptr); + graphics.device.destroyFence(pool->fences[i], nullptr); } - ctx->device.freeCommandBuffers(pool->pool, pool->buffers_count, pool->buffers.get()); + graphics.device.freeCommandBuffers(pool->pool, pool->buffers_count, + pool->buffers.get()); - ctx->device.destroyCommandPool(pool->pool, nullptr); + graphics.device.destroyCommandPool(pool->pool, nullptr); delete pool; pool = nullptr; @@ -200,8 +223,6 @@ void CommandPool::DeleteAll() { } bool CommandBuffer::IsInvalid() const { - EXIT_IF(g_render_ctx == nullptr); - if (m_pool != nullptr) { Common::LockGuard lock(m_pool->mutex); @@ -255,10 +276,8 @@ void CommandBuffer::Free() { EXIT_NOT_IMPLEMENTED(!IsInvalid()); } -void CommandBuffer::DeleteAfterFence(VulkanBuffer* buffer) { - EXIT_IF(buffer == nullptr); - - m_delete_after_fence.push_back(buffer); +void CommandBuffer::DeleteAfterFence(VulkanBuffer& buffer) { + m_delete_after_fence.push_back(&buffer); } void CommandBuffer::RetainResourceUntilFence(std::shared_ptr resource) { @@ -268,15 +287,13 @@ void CommandBuffer::RetainResourceUntilFence(std::shared_ptr resource) { m_fence_resources.Retain(std::move(resource)); } -void CommandBuffer::RecycleDescriptorAfterFence(VulkanDescriptorSet* set) { - EXIT_IF(set == nullptr); - - m_descriptor_sets_after_fence.push_back(set); +void CommandBuffer::RecycleDescriptorAfterFence(VulkanDescriptorSet& set) { + m_descriptor_sets_after_fence.push_back(&set); } void CommandBuffer::RecycleDescriptorsAfterFence() { for (auto* set: m_descriptor_sets_after_fence) { - g_render_ctx->GetDescriptorCache()->Recycle(set); + GetRenderContext().GetDescriptorCache().Recycle(*set); } m_descriptor_sets_after_fence.clear(); } @@ -351,12 +368,11 @@ void CommandBuffer::Submit(vk::Semaphore wait_semaphore, vk::PipelineStageFlags submit_info.signalSemaphoreCount = has_signal ? 1u : 0u; submit_info.pSignalSemaphores = has_signal ? &signal_semaphore : nullptr; - auto* ctx = g_render_ctx->GetGraphicCtx(); - EXIT_IF(ctx == nullptr); - EXIT_IF(ctx->device == nullptr); - const auto& queue = ctx->queues[m_queue]; + auto& graphics = GetRenderContext().GetGraphics(); + EXIT_IF(graphics.device == nullptr); + const auto& queue = graphics.queues[m_queue]; - auto result = ctx->device.resetFences(1, &fence); + auto result = graphics.device.resetFences(1, &fence); if (result != vk::Result::eSuccess) { LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(), static_cast(result)); @@ -412,7 +428,7 @@ void CommandBuffer::WaitForFenceOnly() { if (!m_execute || m_fence_waited) { return; } - auto device = g_render_ctx->GetGraphicCtx()->device; + auto device = GetRenderContext().GetGraphics().device; auto result = device.waitForFences(1, &m_pool->fences[m_index], VK_TRUE, UINT64_MAX); if (result != vk::Result::eSuccess) { LOGF("vkWaitForFences failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64 @@ -456,21 +472,20 @@ void CommandBuffer::ReleaseResourcesAfterFence() { void CommandBuffer::DeleteBuffersAfterFence() { for (auto* buffer: m_delete_after_fence) { - VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer); + GetRenderContext().GetGraphics().DeleteBuffer(*buffer); delete buffer; } m_delete_after_fence.clear(); } -void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors, - uint32_t requested_color_count, RenderDepthInfo* depth) const { +void CommandBuffer::BeginRenderPass(VulkanFramebuffer& framebuffer, RenderColorInfo* colors, + uint32_t requested_color_count, RenderDepthInfo& depth) const { auto buffer = Handle(); - EXIT_IF(framebuffer == nullptr); EXIT_IF(colors == nullptr); EXIT_IF(requested_color_count > RENDER_COLOR_ATTACHMENTS_MAX); - bool with_depth = (depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr); + bool with_depth = (depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr); uint32_t color_count = 0; for (uint32_t i = 0; i < requested_color_count; i++) { if (colors[i].vulkan_buffer == nullptr) { @@ -486,22 +501,22 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI for (uint32_t i = 0; i < color_count; i++) { clears[i].color = colors[i].color_clear_value; } - clears[color_count].depthStencil = {depth->depth_clear_value, depth->stencil_clear_value}; + clears[color_count].depthStencil = {depth.depth_clear_value, depth.stencil_clear_value}; - vk::Extent2D extent = (with_color ? colors[0].extent : depth->vulkan_buffer->extent); + vk::Extent2D extent = (with_color ? colors[0].extent : depth.vulkan_buffer->extent); vk::RenderPassBeginInfo render_pass_info {}; render_pass_info.sType = vk::StructureType::eRenderPassBeginInfo; render_pass_info.pNext = nullptr; - render_pass_info.renderPass = framebuffer->render_pass; - render_pass_info.framebuffer = framebuffer->framebuffer; + render_pass_info.renderPass = framebuffer.render_pass; + render_pass_info.framebuffer = framebuffer.framebuffer; render_pass_info.renderArea.offset = {0, 0}; render_pass_info.renderArea.extent = extent; render_pass_info.clearValueCount = color_count + (with_depth ? 1u : 0u); render_pass_info.pClearValues = clears; for (uint32_t i = 0; i < color_count; i++) { - const auto color_initial_layout = framebuffer->color_layout[i]; + const auto color_initial_layout = framebuffer.color_layout[i]; if (colors[i].vulkan_buffer->layout != color_initial_layout) { if (graphics_debug_dump_enabled()) { LOGF("BeginRenderPass: color%u initial barrier image=%p mem=%" PRIu64 " %s -> %s\n", @@ -543,10 +558,9 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI } const auto depth_layout = - (with_depth && framebuffer != nullptr ? framebuffer->depth_layout - : vk::ImageLayout::eDepthStencilAttachmentOptimal); + with_depth ? framebuffer.depth_layout : vk::ImageLayout::eDepthStencilAttachmentOptimal; - if (with_depth && depth->vulkan_buffer->layout != depth_layout) { + if (with_depth && depth.vulkan_buffer->layout != depth_layout) { vk::ImageMemoryBarrier image_memory_barrier {}; image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; image_memory_barrier.pNext = nullptr; @@ -556,24 +570,24 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI (depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal ? vk::AccessFlagBits::eMemoryRead : vk::AccessFlagBits::eMemoryWrite); - image_memory_barrier.oldLayout = depth->vulkan_buffer->layout; + image_memory_barrier.oldLayout = depth.vulkan_buffer->layout; image_memory_barrier.newLayout = depth_layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.image = depth->vulkan_buffer->image; + image_memory_barrier.image = depth.vulkan_buffer->image; image_memory_barrier.subresourceRange.aspectMask = - ImageViewOps::DepthAspectMask(depth->vulkan_buffer->format); + ImageViewOps::DepthAspectMask(depth.vulkan_buffer->format); image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = 1; image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = depth->vulkan_buffer->layers; + image_memory_barrier.subresourceRange.layerCount = depth.vulkan_buffer->layers; buffer.pipelineBarrier( vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); - depth->vulkan_buffer->layout = image_memory_barrier.newLayout; + depth.vulkan_buffer->layout = image_memory_barrier.newLayout; } buffer.beginRenderPass(&render_pass_info, vk::SubpassContents::eInline); @@ -586,8 +600,8 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI } } if (with_depth) { - depth->vulkan_buffer->initial_depth_clear_pending = false; - depth->vulkan_buffer->initial_stencil_clear_pending = false; + depth.vulkan_buffer->initial_depth_clear_pending = false; + depth.vulkan_buffer->initial_stencil_clear_pending = false; } } diff --git a/src/graphics/host_gpu/renderer/debug.cpp b/src/graphics/host_gpu/renderer/debug.cpp index 9dde2f476..e566bd197 100644 --- a/src/graphics/host_gpu/renderer/debug.cpp +++ b/src/graphics/host_gpu/renderer/debug.cpp @@ -25,8 +25,9 @@ static bool RenderTargetMaskHasMrt(uint32_t mask) { return (mask & ~0x0fu) != 0; } -static bool RenderTargetMaskHasBoundMrt(const HW::Context& hw) { - const auto mask = hw.GetRenderTargetMask(); +static bool RenderTargetMaskHasBoundMrt(const RenderCommandBuffer& buffer) { + const auto& hw = buffer.GetRegisters(); + const auto mask = hw.GetRenderTargetMask(); if (!RenderTargetMaskHasMrt(mask)) { return false; @@ -42,8 +43,9 @@ static bool RenderTargetMaskHasBoundMrt(const HW::Context& hw) { return bound_targets > 1; } -uint32_t render_target_first_bound_slot(const HW::Context& hw) { - const auto mask = hw.GetRenderTargetMask(); +uint32_t render_target_first_bound_slot(const RenderCommandBuffer& buffer) { + const auto& hw = buffer.GetRegisters(); + const auto mask = hw.GetRenderTargetMask(); for (uint32_t i = 0; i < 8; i++) { if (render_target_mask_slot(mask, i) != 0 && hw.GetRenderTarget(i).base.addr != 0) { return i; @@ -1241,8 +1243,9 @@ ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeC return ScissorRectClamp(final, extent.width, extent.height); } -void hw_check(const HW::Context& hw) { - const auto rt_slot = render_target_first_bound_slot(hw); +void hw_check(const RenderCommandBuffer& buffer) { + const auto& hw = buffer.GetRegisters(); + const auto rt_slot = render_target_first_bound_slot(buffer); const auto& rt = hw.GetRenderTarget(rt_slot); const auto& bc = hw.GetBlendControl(rt_slot); const auto& bclr = hw.GetBlendColor(); @@ -1291,7 +1294,7 @@ void hw_check(const HW::Context& hw) { AaCheck(aa, ac); log_phase("done"); - if (RenderTargetMaskHasBoundMrt(hw)) { + if (RenderTargetMaskHasBoundMrt(buffer)) { LOGF("MRT render target mask: 0x%08" PRIx32 "\n", hw.GetRenderTargetMask()); for (uint32_t i = 0; i < 8; i++) { const auto& mrt = hw.GetRenderTarget(i); @@ -1312,8 +1315,9 @@ void hw_check(const HW::Context& hw) { // EXIT_NOT_IMPLEMENTED(hw.GetStencilClearValue() != 0); } -void hw_print(const HW::Context& hw) { - const auto rt_slot = render_target_first_bound_slot(hw); +void hw_print(const RenderCommandBuffer& buffer) { + const auto& hw = buffer.GetRegisters(); + const auto rt_slot = render_target_first_bound_slot(buffer); const auto& rt = hw.GetRenderTarget(rt_slot); const auto& bc = hw.GetBlendControl(rt_slot); const auto& bclr = hw.GetBlendColor(); diff --git a/src/graphics/host_gpu/renderer/debug.h b/src/graphics/host_gpu/renderer/debug.h index 29b46d810..53d3de2ee 100644 --- a/src/graphics/host_gpu/renderer/debug.h +++ b/src/graphics/host_gpu/renderer/debug.h @@ -9,6 +9,8 @@ namespace Libs::Graphics { +class RenderCommandBuffer; + namespace HW { class Context; class Shader; @@ -26,7 +28,7 @@ struct ScissorRect { }; uint32_t render_target_mask_slot(uint32_t mask, uint32_t slot); -uint32_t render_target_first_bound_slot(const HW::Context& hw); +uint32_t render_target_first_bound_slot(const RenderCommandBuffer& buffer); bool graphics_debug_dump_enabled(); void uc_print(const char* func, const HW::UserConfig& uc); void uc_check(const HW::UserConfig& uc); @@ -34,8 +36,8 @@ void sh_print(const char* func, const HW::Shader& uc); void sh_check(const HW::Shader& uc); std::vector rt_print(const char* func, const HW::RenderTarget& rt); bool RenderIsColorTileModeLinear(uint32_t tile_mode); -void hw_print(const HW::Context& hw); -void hw_check(const HW::Context& hw); +void hw_print(const RenderCommandBuffer& buffer); +void hw_check(const RenderCommandBuffer& buffer); void LogDrawPhase(const char* draw_name, const char* phase); ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc, vk::Extent2D extent); diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp index 4076c80d2..f1ab6b3b5 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp @@ -61,20 +61,18 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) { depth_fail == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp); } -[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(GraphicContext* ctx, - const DepthFormatPolicy& policy, +[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(const RenderCommandBuffer& buffer, + const DepthFormatPolicy& policy, bool has_stencil, uint32_t samples) { - if (ctx == nullptr) { - return vk::Format::eUndefined; - } + auto& graphics = buffer.GetGraphics(); const auto required_samples = vulkan_sample_count(samples); const auto supports = [&](vk::Format format) { vk::ImageFormatProperties properties {}; return format != vk::Format::eUndefined && - ctx->GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, - DepthTargetImageUsage(), vk::ImageCreateFlags {}, - &properties) == vk::Result::eSuccess && + graphics.GetImageFormatProperties( + format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, DepthTargetImageUsage(), + vk::ImageCreateFlags {}, &properties) == vk::Result::eSuccess && static_cast(properties.sampleCounts & required_samples); }; if (!has_stencil) { @@ -90,12 +88,10 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) { } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, - RenderDepthInfo* r) { +void ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderDepthInfo& r) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(r == nullptr); (void)submit_id; - (void)buffer; + const auto& hw = buffer.GetRegisters(); const auto& z = hw.GetDepthRenderTarget(); const auto& rc = hw.GetRenderControl(); const auto& dc = hw.GetDepthControl(); @@ -232,9 +228,8 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H DepthFatal("unsupported depth/stencil format pair"); } const auto ideal_format = DepthAttachmentFormat(*policy, has_stencil); - r->format = ResolveHostDepthAttachmentFormat(g_render_ctx->GetGraphicCtx(), *policy, - has_stencil, samples); - if (r->format == vk::Format::eUndefined) { + r.format = ResolveHostDepthAttachmentFormat(buffer, *policy, has_stencil, samples); + if (r.format == vk::Format::eUndefined) { DepthFatal("no host depth/stencil format supports required usage for %s", VulkanToString(ideal_format).c_str()); } @@ -250,7 +245,7 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H TileSizeAlign stencil_size {}; TileSizeAlign htile_size {}; if (!TileGetDepthSize(width, height, 0, z.z_info.format, z.stencil_info.format, has_htile, - &stencil_size, &htile_size, &depth_size, z.z_info.num_samples) || + stencil_size, htile_size, depth_size, z.z_info.num_samples) || depth_size.align != 65536 || depth_size.size == 0 || (has_stencil != (stencil_size.align == 65536 && stencil_size.size != 0)) || (has_htile != (htile_size.align == 32768 && htile_size.size != 0))) { @@ -277,41 +272,40 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H (has_htile && htile_backing_size > TRACKER_ADDRESS_SIZE - z.htile_data_base_addr)) { DepthFatal("layered depth backing range is invalid"); } - r->htile = has_htile; - r->width = width; - r->height = height; - r->samples = samples; - r->depth_buffer_size = depth_backing_size; - r->depth_buffer_vaddr = z.z_read_base_addr; - r->stencil_buffer_size = has_stencil ? stencil_backing_size : 0; - r->stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0; - r->htile_buffer_size = has_htile ? htile_backing_size : 0; - r->htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0; - auto* cache = g_render_ctx->GetTextureCache(); + r.htile = has_htile; + r.width = width; + r.height = height; + r.samples = samples; + r.depth_buffer_size = depth_backing_size; + r.depth_buffer_vaddr = z.z_read_base_addr; + r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0; + r.stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0; + r.htile_buffer_size = has_htile ? htile_backing_size : 0; + r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0; + auto& cache = GetRenderContext().GetTextureCache(); if (has_htile) { - cache->RegisterMeta(g_render_ctx->GetGraphicCtx(), r->htile_buffer_vaddr, - r->htile_buffer_size, view.image_layers); + cache.RegisterMeta(r.htile_buffer_vaddr, r.htile_buffer_size, view.image_layers); } - if (has_htile && rc.depth_clear_enable && !cache->ClearMeta(z.htile_data_base_addr)) { + if (has_htile && rc.depth_clear_enable && !cache.ClearMeta(z.htile_data_base_addr)) { DepthFatal("failed to acquire HTile metadata for a depth clear"); } const bool meta_clear = - has_htile && cache->IsMetaCleared(z.htile_data_base_addr, z.depth_view.slice_start); - r->depth_clear_enable = rc.depth_clear_enable; - r->depth_meta_clear_enable = meta_clear; - r->depth_load_clear_enable = r->depth_clear_enable || r->depth_meta_clear_enable; - r->depth_clear_value = hw.GetDepthClearValue(); - r->depth_test_enable = dc.z_enable; - r->depth_write_enable = dc.z_write_enable && !z.depth_view.depth_write_disable; - r->depth_compare_op = static_cast(dc.zfunc); + has_htile && cache.IsMetaCleared(z.htile_data_base_addr, z.depth_view.slice_start); + r.depth_clear_enable = rc.depth_clear_enable; + r.depth_meta_clear_enable = meta_clear; + r.depth_load_clear_enable = r.depth_clear_enable || r.depth_meta_clear_enable; + r.depth_clear_value = hw.GetDepthClearValue(); + r.depth_test_enable = dc.z_enable; + r.depth_write_enable = dc.z_write_enable && !z.depth_view.depth_write_disable; + r.depth_compare_op = static_cast(dc.zfunc); - r->depth_bounds_test_enable = dc.depth_bounds_enable; - r->depth_min_bounds = hw.GetDepthBoundsMin(); - r->depth_max_bounds = hw.GetDepthBoundsMax(); + r.depth_bounds_test_enable = dc.depth_bounds_enable; + r.depth_min_bounds = hw.GetDepthBoundsMin(); + r.depth_max_bounds = hw.GetDepthBoundsMax(); - r->stencil_clear_enable = rc.stencil_clear_enable; - r->stencil_clear_value = hw.GetStencilClearValue(); - r->stencil_test_enable = dc.stencil_enable; + r.stencil_clear_enable = rc.stencil_clear_enable; + r.stencil_clear_value = hw.GetStencilClearValue(); + r.stencil_test_enable = dc.stencil_enable; if (dc.stencil_enable) { if (dc.stencilfunc > static_cast(vk::CompareOp::eAlways) || (dc.backface_enable && @@ -323,40 +317,40 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H sm.stencil_opval_bf != sm.stencil_testval_bf)) { DepthFatal("unsupported stencil compare or replacement state"); } - r->stencil_static_front = { + r.stencil_static_front = { ConvertStencilOp(sc.stencil_fail), ConvertStencilOp(sc.stencil_zpass), ConvertStencilOp(sc.stencil_zfail), static_cast(dc.stencilfunc)}; - r->stencil_dynamic_front = {sm.stencil_mask, - rc.stencil_clear_enable ? 0u : sm.stencil_writemask, - sm.stencil_testval}; + r.stencil_dynamic_front = {sm.stencil_mask, + rc.stencil_clear_enable ? 0u : sm.stencil_writemask, + sm.stencil_testval}; if (dc.backface_enable) { - r->stencil_static_back = {ConvertStencilOp(sc.stencil_fail_bf), - ConvertStencilOp(sc.stencil_zpass_bf), - ConvertStencilOp(sc.stencil_zfail_bf), - static_cast(dc.stencilfunc_bf)}; - r->stencil_dynamic_back = {sm.stencil_mask_bf, - rc.stencil_clear_enable ? 0u : sm.stencil_writemask_bf, - sm.stencil_testval_bf}; + r.stencil_static_back = {ConvertStencilOp(sc.stencil_fail_bf), + ConvertStencilOp(sc.stencil_zpass_bf), + ConvertStencilOp(sc.stencil_zfail_bf), + static_cast(dc.stencilfunc_bf)}; + r.stencil_dynamic_back = {sm.stencil_mask_bf, + rc.stencil_clear_enable ? 0u : sm.stencil_writemask_bf, + sm.stencil_testval_bf}; } else { - r->stencil_static_back = r->stencil_static_front; - r->stencil_dynamic_back = r->stencil_dynamic_front; + r.stencil_static_back = r.stencil_static_front; + r.stencil_dynamic_back = r.stencil_dynamic_front; } } - r->vaddr_num = has_stencil ? 2 : 1; - r->vaddr[0] = r->depth_buffer_vaddr; - r->size[0] = r->depth_buffer_size; + r.vaddr_num = has_stencil ? 2 : 1; + r.vaddr[0] = r.depth_buffer_vaddr; + r.size[0] = r.depth_buffer_size; if (has_stencil) { - r->vaddr[1] = r->stencil_buffer_vaddr; - r->size[1] = r->stencil_buffer_size; + r.vaddr[1] = r.stencil_buffer_vaddr; + r.size[1] = r.stencil_buffer_size; } DepthTargetInfo info {}; - info.address = r->depth_buffer_vaddr; - info.size = r->depth_buffer_size; - info.stencil_address = r->stencil_buffer_vaddr; - info.stencil_size = r->stencil_buffer_size; - info.htile_address = r->htile_buffer_vaddr; - info.htile_size = r->htile_buffer_size; - info.format = r->format; + info.address = r.depth_buffer_vaddr; + info.size = r.depth_buffer_size; + info.stencil_address = r.stencil_buffer_vaddr; + info.stencil_size = r.stencil_buffer_size; + info.htile_address = r.htile_buffer_vaddr; + info.htile_size = r.htile_buffer_size; + info.format = r.format; info.guest_format = guest_format; info.width = width; info.height = height; @@ -365,28 +359,28 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H info.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kDepth); info.layers = view.image_layers; info.samples = samples; - info.depth_load_clear = r->depth_load_clear_enable; + info.depth_load_clear = r.depth_load_clear_enable; info.depth_access = depth_active; info.stencil_load_clear = rc.stencil_clear_enable; info.stencil_access = - r->stencil_clear_enable || - (r->stencil_test_enable && - (stencil_face_accesses_attachment(r->stencil_static_front, r->stencil_dynamic_front) || - stencil_face_accesses_attachment(r->stencil_static_back, r->stencil_dynamic_back))); + r.stencil_clear_enable || + (r.stencil_test_enable && + (stencil_face_accesses_attachment(r.stencil_static_front, r.stencil_dynamic_front) || + stencil_face_accesses_attachment(r.stencil_static_back, r.stencil_dynamic_back))); info.stencil_htile_compressed = has_stencil && has_htile && !z.stencil_info.tile_stencil_disable; - r->vulkan_buffer = cache->FindDepthTarget(buffer, g_render_ctx->GetGraphicCtx(), info); - r->vulkan_view = cache->GetDepthTargetAttachmentView( - g_render_ctx->GetGraphicCtx(), r->vulkan_buffer, view.base_layer, view.layer_count); - if (r->vulkan_buffer->initial_depth_clear_pending) { - r->depth_load_clear_enable = true; - r->depth_clear_value = 0.0f; + r.vulkan_buffer = &cache.FindDepthTarget(buffer, info); + r.vulkan_view = + cache.GetDepthTargetAttachmentView(*r.vulkan_buffer, view.base_layer, view.layer_count); + if (r.vulkan_buffer->initial_depth_clear_pending) { + r.depth_load_clear_enable = true; + r.depth_clear_value = 0.0f; } - if (r->vulkan_buffer->initial_stencil_clear_pending) { - r->stencil_clear_enable = true; - r->stencil_clear_value = 0; + if (r.vulkan_buffer->initial_stencil_clear_pending) { + r.stencil_clear_enable = true; + r.stencil_clear_value = 0; } - if (meta_clear && !cache->TouchMeta(z.htile_data_base_addr, z.depth_view.slice_start, false)) { + if (meta_clear && !cache.TouchMeta(z.htile_data_base_addr, z.depth_view.slice_start, false)) { DepthFatal("failed to consume HTile clear state"); } } @@ -395,8 +389,8 @@ void MarkRenderTargetGpuWritten(const RenderDepthInfo& target) { const bool with_depth = target.format != vk::Format::eUndefined && target.vulkan_buffer != nullptr; - if (with_depth && !depth_attachment_read_only(&target)) { - g_render_ctx->GetTextureCache()->MarkGpuWritten(target.vulkan_buffer); + if (with_depth && !depth_attachment_read_only(target)) { + GetRenderContext().GetTextureCache().MarkGpuWritten(*target.vulkan_buffer); } } diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.h b/src/graphics/host_gpu/renderer/depthRenderTarget.h index 4211a6d2e..e7ac09871 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.h +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.h @@ -9,13 +9,9 @@ namespace Libs::Graphics { -class CommandBuffer; +class RenderCommandBuffer; struct DepthStencilVulkanImage; -namespace HW { -class Context; -} // namespace HW - inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stencil, bool has_htile, bool acceleration_disabled) { return acceleration_disabled || (has_stencil && has_htile); @@ -60,22 +56,20 @@ struct RenderDepthInfo { int vaddr_num = 0; }; -inline bool depth_attachment_read_only(const RenderDepthInfo* depth) { - EXIT_IF(depth == nullptr); +inline bool depth_attachment_read_only(const RenderDepthInfo& depth) { const bool stencil_write = - depth->stencil_test_enable && - (depth->stencil_dynamic_front.writeMask != 0 || depth->stencil_dynamic_back.writeMask != 0); - return !depth->depth_load_clear_enable && !depth->stencil_clear_enable && - !depth->depth_write_enable && !stencil_write; + depth.stencil_test_enable && + (depth.stencil_dynamic_front.writeMask != 0 || depth.stencil_dynamic_back.writeMask != 0); + return !depth.depth_load_clear_enable && !depth.stencil_clear_enable && + !depth.depth_write_enable && !stencil_write; } -inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo* depth) { +inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) { return depth_attachment_read_only(depth) ? vk::ImageLayout::eDepthStencilReadOnlyOptimal : vk::ImageLayout::eDepthStencilAttachmentOptimal; } -void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, - RenderDepthInfo* r); +void ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderDepthInfo& r); void MarkRenderTargetGpuWritten(const RenderDepthInfo& target); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/descriptorCache.cpp b/src/graphics/host_gpu/renderer/descriptorCache.cpp index c681a3659..7a9d1429f 100644 --- a/src/graphics/host_gpu/renderer/descriptorCache.cpp +++ b/src/graphics/host_gpu/renderer/descriptorCache.cpp @@ -76,13 +76,12 @@ std::vector LayoutKey(DescriptorCache::Stage stage, return key; } -vk::ImageLayout SampledLayout(const VulkanImage* image) { - EXIT_IF(image == nullptr); - switch (image->layout) { +vk::ImageLayout SampledLayout(const VulkanImage& image) { + switch (image.layout) { case vk::ImageLayout::eTransferDstOptimal: case vk::ImageLayout::eTransferSrcOptimal: case vk::ImageLayout::eColorAttachmentOptimal: return vk::ImageLayout::eGeneral; - default: return image->layout; + default: return image.layout; } } @@ -103,9 +102,8 @@ vk::DescriptorImageInfo MakeDescriptorImageInfo(const DescriptorCache::TextureBi } // namespace vk::DescriptorSetLayout -DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage, +DescriptorCache::GetDescriptorSetLayoutInternal(Stage stage, const ShaderRecompiler::IR::Program& program) { - EXIT_IF(gctx == nullptr); const auto key = LayoutKey(stage, program); if (const auto found = m_descriptor_set_layouts.find(key); found != m_descriptor_set_layouts.end()) { @@ -127,15 +125,14 @@ DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stag info.bindingCount = static_cast(bindings.size()); info.pBindings = bindings.data(); vk::DescriptorSetLayout layout = nullptr; - const auto result = gctx->device.createDescriptorSetLayout(&info, nullptr, &layout); + const auto result = m_graphics.device.createDescriptorSetLayout(&info, nullptr, &layout); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || layout == nullptr); m_descriptor_set_layouts.emplace(key, layout); return layout; } -void DescriptorCache::CreatePool(GraphicContext* gctx) { +void DescriptorCache::CreatePool() { KYTY_PROFILER_FUNCTION(); - EXIT_IF(gctx == nullptr); constexpr uint32_t MaxSets = 512; const vk::DescriptorPoolSize sizes[] = { {vk::DescriptorType::eStorageBuffer, @@ -152,7 +149,7 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) { info.maxSets = MaxSets; const auto pool_id = static_cast(m_pools.size()); auto& pool = m_pools.emplace_back(); - const auto result = gctx->device.createDescriptorPool(&info, nullptr, &pool.pool); + const auto result = m_graphics.device.createDescriptorPool(&info, nullptr, &pool.pool); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool.pool == nullptr); pool.next_free_pool = m_first_free_pool; m_first_free_pool = pool_id; @@ -161,10 +158,8 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) { VulkanDescriptorSet* DescriptorCache::Allocate(Stage stage, const ShaderRecompiler::IR::Program& program) { KYTY_PROFILER_FUNCTION(); - auto* gctx = g_render_ctx->GetGraphicCtx(); - EXIT_IF(gctx == nullptr); Common::LockGuard lock(m_mutex); - const auto layout = GetDescriptorSetLayoutInternal(gctx, stage, program); + const auto layout = GetDescriptorSetLayoutInternal(stage, program); EXIT_IF(layout == nullptr); auto& free_sets = m_free_sets_by_layout[layout]; if (!free_sets.empty()) { @@ -186,7 +181,8 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage info.descriptorPool = pool.pool; info.descriptorSetCount = Batch; info.pSetLayouts = layouts.data(); - if (gctx->device.allocateDescriptorSets(&info, sets.data()) == vk::Result::eSuccess) { + if (m_graphics.device.allocateDescriptorSets(&info, sets.data()) == + vk::Result::eSuccess) { free_sets.reserve(free_sets.size() + Batch - 1u); for (uint32_t i = 0; i + 1u < Batch; i++) { free_sets.push_back(new VulkanDescriptorSet {sets[i], layout, pool_id}); @@ -196,18 +192,18 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage m_first_free_pool = pool.next_free_pool; break; } - CreatePool(gctx); + CreatePool(); } return nullptr; } -void DescriptorCache::Recycle(VulkanDescriptorSet* set) { - EXIT_IF(set == nullptr || set->set == nullptr || set->layout == nullptr); +void DescriptorCache::Recycle(VulkanDescriptorSet& set) { + EXIT_IF(set.set == nullptr || set.layout == nullptr); Common::LockGuard lock(m_mutex); - m_free_sets_by_layout[set->layout].push_back(set); + m_free_sets_by_layout[set.layout].push_back(&set); } -VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage, +VulkanDescriptorSet& DescriptorCache::GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program, const NativeDescriptors& data) { KYTY_PROFILER_FUNCTION(); @@ -215,8 +211,6 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage data.images.size() != program.info.images.size() || data.samplers.size() != program.info.samplers.size() || data.addresses.size() != program.info.addresses.size()); - auto* gctx = g_render_ctx->GetGraphicCtx(); - EXIT_IF(gctx == nullptr); auto* set = Allocate(stage, program); EXIT_NOT_IMPLEMENTED(set == nullptr); @@ -268,7 +262,7 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage const auto& texture = data.images.at(resource); image_infos.push_back(MakeDescriptorImageInfo( texture, - IsSampledImage(binding.kind) ? SampledLayout(texture.image) : layout)); + IsSampledImage(binding.kind) ? SampledLayout(*texture.image) : layout)); } break; } @@ -281,17 +275,15 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage } writes.push_back(write); } - gctx->device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, - nullptr); - return set; + m_graphics.device.updateDescriptorSets(static_cast(writes.size()), writes.data(), 0, + nullptr); + return *set; } vk::DescriptorSetLayout DescriptorCache::GetDescriptorSetLayout(Stage stage, const ShaderRecompiler::IR::Program& program) { - auto* gctx = g_render_ctx->GetGraphicCtx(); - EXIT_IF(gctx == nullptr); Common::LockGuard lock(m_mutex); - return GetDescriptorSetLayoutInternal(gctx, stage, program); + return GetDescriptorSetLayoutInternal(stage, program); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/descriptorCache.h b/src/graphics/host_gpu/renderer/descriptorCache.h index cd11a623e..73a7cf4f4 100644 --- a/src/graphics/host_gpu/renderer/descriptorCache.h +++ b/src/graphics/host_gpu/renderer/descriptorCache.h @@ -63,14 +63,16 @@ public: BufferView user_data; }; - DescriptorCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } + explicit DescriptorCache(GraphicContext& graphics): m_graphics(graphics) { + EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); + } ~DescriptorCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(DescriptorCache); vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage, const ShaderRecompiler::IR::Program& program); - void Recycle(VulkanDescriptorSet* set); - VulkanDescriptorSet* GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program, + void Recycle(VulkanDescriptorSet& set); + VulkanDescriptorSet& GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program, const NativeDescriptors& descriptors); private: @@ -79,12 +81,12 @@ private: int next_free_pool = -1; }; - void CreatePool(GraphicContext* gctx); + void CreatePool(); VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program); vk::DescriptorSetLayout - GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage, - const ShaderRecompiler::IR::Program& program); + GetDescriptorSetLayoutInternal(Stage stage, const ShaderRecompiler::IR::Program& program); + GraphicContext& m_graphics; Common::Mutex m_mutex; std::vector m_pools; int m_first_free_pool = -1; @@ -93,7 +95,7 @@ private: std::map, vk::DescriptorSetLayout> m_descriptor_set_layouts; }; -void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, +void BindDescriptors(uint64_t submit_id, CommandBuffer& buffer, vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout, const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage, DescriptorCache::Stage stage); diff --git a/src/graphics/host_gpu/renderer/descriptors.cpp b/src/graphics/host_gpu/renderer/descriptors.cpp index 4dae9c0ef..13e67ebcd 100644 --- a/src/graphics/host_gpu/renderer/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/descriptors.cpp @@ -49,13 +49,10 @@ namespace Libs::Graphics { using TextureVariant = DescriptorCache::TextureVariant; -static void BindNullStorageBuffer(CommandBuffer* cmd_buffer, BufferView* dst) { - EXIT_IF(cmd_buffer == nullptr || dst == nullptr); - - dst->buffer = - g_render_ctx->GetBufferCache()->ObtainNullBuffer(cmd_buffer, g_render_ctx->GetGraphicCtx()); - dst->offset = 0; - dst->range = 16; +static void BindNullStorageBuffer(CommandBuffer& cmd_buffer, BufferView& dst) { + dst.buffer = &GetRenderContext().GetBufferCache().ObtainNullBuffer(cmd_buffer); + dst.offset = 0; + dst.range = 16; } // NOLINTNEXTLINE(readability-function-cognitive-complexity) @@ -71,21 +68,19 @@ static const char* VulkanImageTypeName(VulkanImageType type) { } } -static int SampledArrayViewIndex(const VulkanImage* image, int view_index) { - EXIT_IF(image == nullptr); - +static int SampledArrayViewIndex(const VulkanImage& image, int view_index) { switch (view_index) { case VulkanImage::VIEW_DEFAULT: return VulkanImage::VIEW_DEFAULT_ARRAY; default: return view_index; } } -static int SelectSampledTextureArrayView(const VulkanImage* image, int base_view) { +static int SelectSampledTextureArrayView(const VulkanImage& image, int base_view) { const int array_view = SampledArrayViewIndex(image, base_view); - if (image->image_view[array_view] == nullptr) { + if (image.image_view[array_view] == nullptr) { EXIT("missing sampled array image view: image_type=%s base_view=%d array_view=%d " "layers=%u\n", - VulkanImageTypeName(image->type), base_view, array_view, image->layers); + VulkanImageTypeName(image.type), base_view, array_view, image.layers); } return array_view; } @@ -108,14 +103,14 @@ static int TextureVariantDefaultView(TextureVariant variant) { : VulkanImage::VIEW_DEFAULT; } -static VulkanImage* GetDummySampledTexture(TextureVariant variant) { - return g_render_ctx->GetTextureCache()->GetDummySampledTexture(TextureVariantIsUint(variant), - TextureVariantIs3D(variant)); +static VulkanImage& GetDummySampledTexture(TextureVariant variant) { + return GetRenderContext().GetTextureCache().GetDummySampledTexture( + TextureVariantIsUint(variant), TextureVariantIs3D(variant)); } -static VulkanImage* GetDummyStorageTexture(TextureVariant variant) { - return g_render_ctx->GetTextureCache()->GetDummyStorageTexture(TextureVariantIsUint(variant), - TextureVariantIs3D(variant)); +static VulkanImage& GetDummyStorageTexture(TextureVariant variant) { + return GetRenderContext().GetTextureCache().GetDummyStorageTexture( + TextureVariantIsUint(variant), TextureVariantIs3D(variant)); } static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& source, @@ -124,63 +119,11 @@ static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& so std::copy_n(source.dwords.begin(), destination.size(), destination.begin()); } -static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command_buffer, +static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer& command_buffer, const ShaderBufferResource& descriptor, const ShaderRecompiler::IR::BufferResource& resource) { BufferView result; - // Regression - // Bind a null buffer when these four dwords are - // the tracked prefix of an active image sharp. Image validity is encoded by dword 3 bit 31. - /*if (resource.image_alias != ShaderRecompiler::IR::BufferResource::NoImageAlias && - (descriptor.Type() & 2u) != 0) { - BindNullStorageBuffer(command_buffer, &result); - return result; - } - // Buffer TYPE is zero. A nonzero value means a buffer instruction received the first four - // dwords of an image sharp without a tracked image alias; support the known write-only path. - if (descriptor.Type() != 0) { - ShaderTextureResource texture {}; - std::copy_n(descriptor.fields, 4, texture.fields); - const auto width = static_cast(texture.Width5()) + 1u; - const auto height = static_cast(texture.Height5()) + 1u; - const auto format = texture.Format(); - const auto tile = texture.TileMode(); - const auto type = texture.Type(); - const auto address = texture.Base40(); - const auto pitch = TileGetTexturePitch(format, width, 1, tile); - TileSizeAlign footprint {}; - TileGetTextureTotalSize(format, width, height, 1, pitch, 1, tile, false, &footprint); - const bool supported = - resource.formatted && resource.written && !resource.read && !resource.atomic && - format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8UInt) && - tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) && - type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && - texture.DstSelXYZW() == DstSel(4, 5, 6, 7) && address != 0 && footprint.size != 0 && - footprint.align == 65536; - if (!supported) { - EXIT("unsupported texture descriptor used as storage buffer: type=%u format=%u" - " tile=%u swizzle=0x%03x extent=%ux%u read=%d written=%d formatted=%d atomic=%d\n", - type, format, tile, texture.DstSelXYZW(), width, height, resource.read, - resource.written, resource.formatted, resource.atomic); - } - auto* ctx = g_render_ctx->GetGraphicCtx(); - g_render_ctx->GetBufferCache()->ValidateGpuAccess(address, footprint.size, false, true); - auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer( - command_buffer, ctx, address, footprint.size, true, false, true); - const auto alignment = ctx->StorageMinAlignment(); - if (alignment == 0 || binding.second % alignment != 0 || - footprint.size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange) { - EXIT("texture-backed storage buffer binding is unsupported: addr=0x%016" PRIx64 - " size=0x%016" PRIx64 " offset=0x%016" PRIx64 " alignment=0x%016" PRIx64 "\n", - address, footprint.size, static_cast(binding.second), - static_cast(alignment)); - } - result.buffer = binding.first; - result.offset = binding.second; - result.range = footprint.size; - return result; - }*/ const auto address = descriptor.Base48(); const auto stride = descriptor.Stride(); const auto records = descriptor.NumRecords(); @@ -189,34 +132,35 @@ static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command } const auto size = stride != 0 ? static_cast(stride) * records : records; if (address == 0 || size == 0) { - BindNullStorageBuffer(command_buffer, &result); + BindNullStorageBuffer(command_buffer, result); return result; } - auto* const ctx = g_render_ctx->GetGraphicCtx(); - const auto alignment = ctx->StorageMinAlignment(); - if (alignment == 0 || size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange || + const auto& graphics = GetRenderContext().GetGraphics(); + const auto alignment = graphics.StorageMinAlignment(); + if (alignment == 0 || + size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange || BufferCache::CACHING_PAGE_SIZE % alignment != 0) { EXIT("storage buffer range or device alignment is unsupported\n"); } (void)submit_id; - auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer( - command_buffer, ctx, address, size, resource.written, resource.read, resource.formatted); - if (binding.second % alignment != 0) { + auto binding = GetRenderContext().GetBufferCache().ObtainBuffer( + command_buffer, address, size, resource.written, resource.read, resource.formatted); + if (binding.offset % alignment != 0) { EXIT("storage buffer binding is not device-aligned\n"); } - result.buffer = binding.first; - result.offset = binding.second; + result.buffer = &binding.buffer; + result.offset = binding.offset; result.range = static_cast(size); return result; } static BufferView -NativeAddressBuffer(uint64_t submit_id, CommandBuffer* command_buffer, +NativeAddressBuffer(uint64_t submit_id, CommandBuffer& command_buffer, const ShaderRecompiler::IR::AddressResource& resource, const ShaderRecompiler::IR::ResourceSnapshot::Address& address) { BufferView result; if (address.binding_base == 0) { - BindNullStorageBuffer(command_buffer, &result); + BindNullStorageBuffer(command_buffer, result); return result; } if (resource.written) { @@ -224,26 +168,28 @@ NativeAddressBuffer(uint64_t submit_id, CommandBuffer* command_buffer, } const auto limit = resource.kind == ShaderRecompiler::IR::ResourceKind::Flat ? ShaderRecompiler::IR::FlatAddressWindowSize - : static_cast(g_render_ctx->GetGraphicCtx() - ->GetPhysicalDeviceProperties() + : static_cast(GetRenderContext() + .GetGraphics() + .GetPhysicalDeviceProperties() .limits.maxStorageBufferRange); uint64_t size = 0; const auto access = HostMemoryAccess::Mapped; - if (!HostMemoryQueryRange(address.binding_base, limit, access, &size)) { + if (!HostMemoryQueryRange(address.binding_base, limit, access, size)) { EXIT("address resource is not host-accessible: base=0x%016" PRIx64 "\n", address.binding_base); } - auto* const ctx = g_render_ctx->GetGraphicCtx(); - const auto alignment = ctx->StorageMinAlignment(); - if (alignment == 0 || size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange || + const auto& graphics = GetRenderContext().GetGraphics(); + const auto alignment = graphics.StorageMinAlignment(); + if (alignment == 0 || + size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange || BufferCache::GetBufferOffset(address.binding_base) % alignment != 0) { EXIT("address resource range or alignment is unsupported\n"); } (void)submit_id; - auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(command_buffer, ctx, - address.binding_base, size); - result.buffer = binding.first; - result.offset = binding.second; + auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(command_buffer, + address.binding_base, size); + result.buffer = &binding.buffer; + result.offset = binding.offset; result.range = static_cast(size); return result; } @@ -529,7 +475,7 @@ void ValidateMetadataReuseTexture(const ShaderRecompiler::IR::ImageResource& res } static DescriptorCache::TextureBinding -NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, +NativeTexture(uint64_t submit_id, CommandBuffer& command_buffer, const ShaderRecompiler::IR::ImageResource& resource, const ShaderRecompiler::IR::DescriptorValue& value) { ShaderTextureResource descriptor; @@ -541,9 +487,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, ValidateStorageImageResource(resource); } if (descriptor.IsNull()) { - return storage ? DescriptorCache::TextureBinding {GetDummyStorageTexture(variant), + return storage ? DescriptorCache::TextureBinding {&GetDummyStorageTexture(variant), TextureVariantDefaultView(variant)} - : DescriptorCache::TextureBinding {GetDummySampledTexture(variant), + : DescriptorCache::TextureBinding {&GetDummySampledTexture(variant), TextureVariantDefaultView(variant)}; } const auto address = descriptor.Base40(); @@ -578,13 +524,13 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, const auto swizzle = descriptor.DstSelXYZW(); TileSizeAlign size; TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile, - type == Prospero::ImageType::kColor3D, &size); + type == Prospero::ImageType::kColor3D, size); EXIT_NOT_IMPLEMENTED(size.size == 0 || (address & (static_cast(size.align) - 1u)) != 0); if (storage) { ValidateStorageTexture(resource, descriptor, size.size); - g_render_ctx->GetBufferCache()->ValidateGpuAccess(address, size.size, resource.read, - resource.written); + GetRenderContext().GetBufferCache().ValidateGpuAccess(address, size.size, resource.read, + resource.written); } VulkanImage* image = nullptr; @@ -594,11 +540,11 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, descriptor.MsaaDepth(); if (image == nullptr) { if (check_depth) { - image = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(command_buffer, address, - size.size, true); + image = GetRenderContext().GetTextureCache().FindDepthTargetByRange( + command_buffer, address, size.size, true); } else { - image = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(command_buffer, - address, size.size); + image = GetRenderContext().GetTextureCache().FindRenderTargetByRange( + command_buffer, address, size.size); } if (image != nullptr) { if (check_depth) { @@ -628,10 +574,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, static_cast(resource.dimension), descriptor.Type(), descriptor.BaseArray5(), image->layers); } - image_view = g_render_ctx->GetTextureCache()->GetDepthTargetSampledView( - g_render_ctx->GetGraphicCtx(), static_cast(image), - view_format, swizzle, 0, 1, depth_view.type, depth_view.base_layer, - depth_view.layer_count); + image_view = GetRenderContext().GetTextureCache().GetDepthTargetSampledView( + *static_cast(image), view_format, swizzle, 0, 1, + depth_view.type, depth_view.base_layer, depth_view.layer_count); } } else { if (!(storage ? IsSupportedStorageImageResource(resource) @@ -657,23 +602,21 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, } if (storage) { view = SelectStorageColorView(image->format, view_format, swizzle); - image_view = g_render_ctx->GetTextureCache()->GetRenderTargetStorageView( - g_render_ctx->GetGraphicCtx(), - static_cast(image), view_format, base_level, + image_view = GetRenderContext().GetTextureCache().GetRenderTargetStorageView( + *static_cast(image), view_format, base_level, view_levels, target_view.type, target_view.base_layer, target_view.layer_count); } else { - image_view = g_render_ctx->GetTextureCache()->GetSampledColorView( - g_render_ctx->GetGraphicCtx(), image, view_format, swizzle, base_level, - view_levels, target_view.type, target_view.base_layer, - target_view.layer_count); + image_view = GetRenderContext().GetTextureCache().GetSampledColorView( + *image, view_format, swizzle, base_level, view_levels, target_view.type, + target_view.base_layer, target_view.layer_count); } } if (image != nullptr && image_view == nullptr && image->image_view[view] == nullptr) { EXIT("required cached texture image view is missing\n"); } if (storage && image != nullptr) { - g_render_ctx->GetTextureCache()->MarkGpuWritten(image); + GetRenderContext().GetTextureCache().MarkGpuWritten(*image); } } } @@ -701,7 +644,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, } image = video.image; view = VulkanImage::VIEW_STORAGE; - g_render_ctx->GetTextureCache()->MarkGpuWritten(image); + GetRenderContext().GetTextureCache().MarkGpuWritten(*image); } else { const bool exact = IsSupportedSampledVideoOutView(resource, descriptor, *video.image) && @@ -721,15 +664,14 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, static_cast(type), size.size, video.size, pitch, video.pitch); } image = video.image; - image_view = g_render_ctx->GetTextureCache()->GetSampledColorView( - g_render_ctx->GetGraphicCtx(), video.image, view_format, swizzle, 0, 1, - vk::ImageViewType::e2D, 0, 1); + image_view = GetRenderContext().GetTextureCache().GetSampledColorView( + *video.image, view_format, swizzle, 0, 1, vk::ImageViewType::e2D, 0, 1); } } } if (image == nullptr) { - auto* texture_cache = g_render_ctx->GetTextureCache(); - const bool metadata_read = texture_cache->QueryRegion(address, size.size).metadata_pages; + auto& texture_cache = GetRenderContext().GetTextureCache(); + const bool metadata_read = texture_cache.QueryRegion(address, size.size).metadata_pages; if (storage && metadata_read) { EXIT("storage texture overlaps surface metadata\n"); } @@ -754,19 +696,15 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, info.type = descriptor.Type(); info.base_array = descriptor.BaseArray5(); if (storage) { - image = texture_cache->FindStorageTexture(command_buffer, g_render_ctx->GetGraphicCtx(), - info); - view = VulkanImage::VIEW_DEFAULT; - image_view = texture_cache->GetStorageTextureStorageView( - g_render_ctx->GetGraphicCtx(), static_cast(image), - base_level); + image = &texture_cache.FindStorageTexture(command_buffer, info); + view = VulkanImage::VIEW_DEFAULT; + image_view = texture_cache.GetStorageTextureStorageView( + *static_cast(image), base_level); } else { - image = texture_cache->FindTexture(command_buffer, g_render_ctx->GetGraphicCtx(), info, - metadata_read); + image = &texture_cache.FindTexture(command_buffer, info, metadata_read); if (image->type == VulkanImageType::StorageTexture) { - image_view = texture_cache->GetStorageTextureSampledView( - g_render_ctx->GetGraphicCtx(), static_cast(image), - info); + image_view = texture_cache.GetStorageTextureSampledView( + *static_cast(image), info); } } } @@ -774,7 +712,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, if (NeedsStaticSampledArrayView(resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray, image_view != nullptr)) { - view = SelectSampledTextureArrayView(image, view); + view = SelectSampledTextureArrayView(*image, view); } return {image, view, image_view}; } @@ -792,31 +730,31 @@ static vk::Sampler NativeSampler(const ShaderRecompiler::IR::Program& program, u if (!depth_compare) { descriptor.fields[0] &= ~(0x7u << 12u); } - return g_render_ctx->GetSamplerCache()->GetSampler(descriptor); + return GetRenderContext().GetSamplerCache().GetSampler(descriptor); } -static BufferView NativeUpload(CommandBuffer* command_buffer, std::span data) { +static BufferView NativeUpload(CommandBuffer& command_buffer, std::span data) { EXIT_IF(data.empty()); BufferView result; - EXIT_IF(!g_render_ctx->GetBufferCache()->UploadHostData( - command_buffer, g_render_ctx->GetGraphicCtx(), data.data(), data.size_bytes(), 256, - &result.buffer, &result.offset, &result.range)); + EXIT_IF(!GetRenderContext().GetBufferCache().UploadHostData( + command_buffer, data.data(), data.size_bytes(), 256, result.buffer, result.offset, + result.range)); return result; } -void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, +void BindDescriptors(uint64_t submit_id, CommandBuffer& buffer, vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout, const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage, DescriptorCache::Stage stage) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(buffer == nullptr || !runtime); + EXIT_IF(!runtime); const auto& program = *runtime.program; const auto& snapshot = *runtime.resources; std::string error; if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) { EXIT("invalid native shader runtime snapshot: %s\n", error.c_str()); } - auto vk_buffer = buffer->Handle(); + auto vk_buffer = buffer.Handle(); const auto shader_stages = ShaderPipelineStages(vk_stage); DescriptorCache::NativeDescriptors descriptors; @@ -864,9 +802,8 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, } if (ShaderRecompiler::IR::FindBinding( program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) { - descriptors.gds.buffer = - g_render_ctx->GetGdsBuffer()->GetBuffer(g_render_ctx->GetGraphicCtx()); - const auto barrier = MakeGdsDependency(*descriptors.gds.buffer); + descriptors.gds.buffer = &GetRenderContext().GetGdsBuffer().GetBuffer(); + const auto barrier = MakeGdsDependency(*descriptors.gds.buffer); vk_buffer.pipelineBarrier( vk::PipelineStageFlagBits::eHost | vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader, @@ -880,14 +817,14 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) { switch (image->type) { case VulkanImageType::DepthStencil: - GraphicsRenderDepthStencilBarrier(vk_buffer, image); + GraphicsRenderDepthStencilBarrier(vk_buffer, *image); break; case VulkanImageType::RenderTexture: case VulkanImageType::StorageTexture: - GraphicsRenderTextureBarrier(vk_buffer, image); + GraphicsRenderTextureBarrier(vk_buffer, *image); break; case VulkanImageType::VideoOut: - GraphicsRenderColorImageBarrier(vk_buffer, image, RENDER_COLOR_IMAGE_LAYOUT); + GraphicsRenderColorImageBarrier(vk_buffer, *image, RENDER_COLOR_IMAGE_LAYOUT); break; default: break; } @@ -901,11 +838,11 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, } if (!program.bindings.descriptors.empty()) { - auto* set = g_render_ctx->GetDescriptorCache()->GetDescriptor(stage, program, descriptors); - EXIT_IF(set == nullptr); + auto& set = + GetRenderContext().GetDescriptorCache().GetDescriptor(stage, program, descriptors); vk_buffer.bindDescriptorSets(pipeline_bind_point, layout, program.bindings.descriptor_set, - 1, &set->set, 0, nullptr); - buffer->RecycleDescriptorAfterFence(set); + 1, &set.set, 0, nullptr); + buffer.RecycleDescriptorAfterFence(set); } if (program.bindings.push_constant_size != 0) { EXIT_IF(program.bindings.push_constant_size != user_data.size() * sizeof(uint32_t)); diff --git a/src/graphics/host_gpu/renderer/dummyTextureCache.cpp b/src/graphics/host_gpu/renderer/dummyTextureCache.cpp index ec3614061..cd7125a37 100644 --- a/src/graphics/host_gpu/renderer/dummyTextureCache.cpp +++ b/src/graphics/host_gpu/renderer/dummyTextureCache.cpp @@ -4,6 +4,8 @@ #include "graphics/host_gpu/renderer/image.h" #include "graphics/host_gpu/transfer.h" +#include + namespace Libs::Graphics { namespace { @@ -16,15 +18,17 @@ namespace { DummyTextureCache::~DummyTextureCache() { Common::LockGuard lock(m_mutex); - if (m_ctx == nullptr) { + const auto populated = [](const auto& slots) { + return std::ranges::any_of(slots, [](const auto& slot) { return slot.image != nullptr; }); + }; + if (!populated(m_sampled) && !populated(m_storage)) { return; } - - Transfer::WaitForGraphicsIdle(m_ctx); - const auto destroy = [this](auto& slots) { + Transfer::WaitForGraphicsIdle(); + const auto destroy = [](auto& slots) { for (auto& slot: slots) { if (slot.image != nullptr) { - ImageOps::Destroy(m_ctx, slot.image); + ImageOps::Destroy(*slot.image); slot.image = nullptr; } } @@ -33,26 +37,15 @@ DummyTextureCache::~DummyTextureCache() { destroy(m_storage); } -VulkanImage* DummyTextureCache::Get(GraphicContext* ctx, Usage usage, bool uint_format, - bool image_3d) { +VulkanImage& DummyTextureCache::Get(Usage usage, bool uint_format, bool image_3d) { Common::LockGuard lock(m_mutex); - if (ctx == nullptr) { - EXIT("TextureCache: dummy texture requires a graphics context\n"); - } - if (m_ctx != nullptr && m_ctx != ctx) { - EXIT("TextureCache: dummy texture context changed, previous=%p current=%p usage=%u\n", - static_cast(m_ctx), static_cast(ctx), - static_cast(usage)); - } - m_ctx = ctx; - - auto& slots = usage == Usage::Storage ? m_storage : m_sampled; - auto& slot = slots[DummyTextureIndex(uint_format, image_3d)]; + auto& slots = usage == Usage::Storage ? m_storage : m_sampled; + auto& slot = slots[DummyTextureIndex(uint_format, image_3d)]; if (slot.image == nullptr) { - slot.image = - ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, usage == Usage::Storage); + slot.image = ImageOps::CreateDummyTexture(uint_format, image_3d, + usage == Usage::Storage); } - return slot.image; + return *slot.image; } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/dummyTextureCache.h b/src/graphics/host_gpu/renderer/dummyTextureCache.h index 7a394d19e..fe697fd1c 100644 --- a/src/graphics/host_gpu/renderer/dummyTextureCache.h +++ b/src/graphics/host_gpu/renderer/dummyTextureCache.h @@ -18,8 +18,7 @@ public: ~DummyTextureCache(); KYTY_CLASS_NO_COPY(DummyTextureCache); - [[nodiscard]] VulkanImage* Get(GraphicContext* ctx, Usage usage, bool uint_format, - bool image_3d); + [[nodiscard]] VulkanImage& Get(Usage usage, bool uint_format, bool image_3d); private: struct Slot { @@ -29,7 +28,6 @@ private: Common::Mutex m_mutex; std::array m_sampled {}; std::array m_storage {}; - GraphicContext* m_ctx = nullptr; }; } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/framebufferCache.cpp b/src/graphics/host_gpu/renderer/framebufferCache.cpp index 6e081e130..629a8eed7 100644 --- a/src/graphics/host_gpu/renderer/framebufferCache.cpp +++ b/src/graphics/host_gpu/renderer/framebufferCache.cpp @@ -15,17 +15,15 @@ namespace Libs::Graphics { VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, uint32_t requested_color_count, - RenderDepthInfo* depth) { + RenderDepthInfo& depth) { KYTY_PROFILER_FUNCTION(); Common::LockGuard lock(m_mutex); EXIT_IF(colors == nullptr); - EXIT_IF(depth == nullptr); - EXIT_IF(g_render_ctx == nullptr); EXIT_IF(requested_color_count > RENDER_COLOR_ATTACHMENTS_MAX); - bool with_depth = (depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr); + bool with_depth = (depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr); bool with_color[RENDER_COLOR_ATTACHMENTS_MAX] = {}; uint32_t color_count = 0; VulkanImage* first_color = nullptr; @@ -58,16 +56,16 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, color_count++; } if (with_depth) { - if (depth->samples != depth->vulkan_buffer->samples) { + if (depth.samples != depth.vulkan_buffer->samples) { EXIT("Framebuffer: depth attachment sample identity mismatch, requested=%u image=%u\n", - depth->samples, depth->vulkan_buffer->samples); + depth.samples, depth.vulkan_buffer->samples); } if (attachment_samples == 0) { - attachment_samples = depth->samples; - } else if (attachment_samples != depth->samples) { + attachment_samples = depth.samples; + } else if (attachment_samples != depth.samples) { EXIT( "Framebuffer: mixed color/depth sample counts are unsupported, color=%u depth=%u\n", - attachment_samples, depth->samples); + attachment_samples, depth.samples); } } if (!with_depth && color_count == 0) { @@ -87,29 +85,29 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, (with_depth && depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal); if (with_depth && first_color != nullptr && - (first_color_extent.width != depth->vulkan_buffer->extent.width || - first_color_extent.height != depth->vulkan_buffer->extent.height)) { + (first_color_extent.width != depth.vulkan_buffer->extent.width || + first_color_extent.height != depth.vulkan_buffer->extent.height)) { static std::atomic log_count {0}; if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { LOGF("Framebuffer: temporary: dropping mismatched PS5 depth attachment color=%ux%u " "depth=%ux%u format=%s\n", first_color_extent.width, first_color_extent.height, - depth->vulkan_buffer->extent.width, depth->vulkan_buffer->extent.height, - VulkanToString(depth->format).c_str()); + depth.vulkan_buffer->extent.width, depth.vulkan_buffer->extent.height, + VulkanToString(depth.format).c_str()); } - depth->format = vk::Format::eUndefined; - depth->vulkan_buffer = nullptr; - depth->vulkan_view = nullptr; - depth->depth_test_enable = false; - depth->depth_write_enable = false; - depth->depth_bounds_test_enable = false; - depth->stencil_test_enable = false; - depth->depth_clear_enable = false; - depth->depth_load_clear_enable = false; - depth->stencil_clear_enable = false; - with_depth = false; - depth_layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; - depth_read_only = false; + depth.format = vk::Format::eUndefined; + depth.vulkan_buffer = nullptr; + depth.vulkan_view = nullptr; + depth.depth_test_enable = false; + depth.depth_write_enable = false; + depth.depth_bounds_test_enable = false; + depth.stencil_test_enable = false; + depth.depth_clear_enable = false; + depth.depth_load_clear_enable = false; + depth.stencil_clear_enable = false; + with_depth = false; + depth_layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; + depth_read_only = false; } for (auto& f: m_framebuffers) { @@ -125,22 +123,21 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, (i < color_count && with_color[i] && colors[i].color_clear_enable) && f.color_layout[i] == color_layout[i]; } - if (color_match && - f.depth_id == (with_depth ? depth->vulkan_buffer->memory.unique_id : 0) && - f.depth_view == (with_depth ? depth->vulkan_view : nullptr) && - f.depth_clear_enable == depth->depth_load_clear_enable && - f.stencil_clear_enable == depth->stencil_clear_enable && + if (color_match && f.depth_id == (with_depth ? depth.vulkan_buffer->memory.unique_id : 0) && + f.depth_view == (with_depth ? depth.vulkan_view : nullptr) && + f.depth_clear_enable == depth.depth_load_clear_enable && + f.stencil_clear_enable == depth.stencil_clear_enable && f.depth_read_only == depth_read_only) { return f.framebuffer; } } EXIT_NOT_IMPLEMENTED(with_depth && first_color != nullptr && - (first_color_extent.width != depth->vulkan_buffer->extent.width || - first_color_extent.height != depth->vulkan_buffer->extent.height)); + (first_color_extent.width != depth.vulkan_buffer->extent.width || + first_color_extent.height != depth.vulkan_buffer->extent.height)); if (first_color == nullptr) { - first_color_extent = depth->vulkan_buffer->extent; + first_color_extent = depth.vulkan_buffer->extent; } auto* framebuffer = new VulkanFramebuffer; @@ -152,10 +149,6 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, } framebuffer->depth_layout = depth_layout; - auto* gctx = g_render_ctx->GetGraphicCtx(); - - EXIT_IF(gctx == nullptr); - vk::AttachmentDescription attachments[RENDER_COLOR_ATTACHMENTS_MAX + 1] = {}; for (uint32_t i = 0; i < color_count; i++) { attachments[i].flags = {}; @@ -172,14 +165,14 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, const uint32_t depth_attachment = color_count; attachments[depth_attachment].flags = {}; - attachments[depth_attachment].format = depth->format; + attachments[depth_attachment].format = depth.format; attachments[depth_attachment].samples = vulkan_sample_count(attachment_samples); attachments[depth_attachment].loadOp = - (depth->depth_load_clear_enable ? vk::AttachmentLoadOp::eClear - : vk::AttachmentLoadOp::eLoad); + (depth.depth_load_clear_enable ? vk::AttachmentLoadOp::eClear + : vk::AttachmentLoadOp::eLoad); attachments[depth_attachment].storeOp = vk::AttachmentStoreOp::eStore; attachments[depth_attachment].stencilLoadOp = - (depth->stencil_clear_enable ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad); + (depth.stencil_clear_enable ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad); attachments[depth_attachment].stencilStoreOp = vk::AttachmentStoreOp::eStore; attachments[depth_attachment].initialLayout = depth_layout; attachments[depth_attachment].finalLayout = depth_layout; @@ -246,7 +239,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, render_pass_info.pDependencies = dependencies; auto result = - gctx->device.createRenderPass(&render_pass_info, nullptr, &framebuffer->render_pass); + m_graphics.device.createRenderPass(&render_pass_info, nullptr, &framebuffer->render_pass); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); vk::Format color_formats[RENDER_COLOR_ATTACHMENTS_MAX] = {}; @@ -254,7 +247,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, color_formats[i] = colors[i].format; } framebuffer->render_pass_id = render_pass_compat_id( - color_count, color_formats, with_depth, depth->format, depth_layout, attachment_samples); + color_count, color_formats, with_depth, depth.format, depth_layout, attachment_samples); EXIT_NOT_IMPLEMENTED(framebuffer->render_pass == nullptr); @@ -266,10 +259,10 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, views[i] = colors[i].vulkan_view; } if (with_depth) { - if (depth->vulkan_view == nullptr) { + if (depth.vulkan_view == nullptr) { EXIT("Framebuffer: depth attachment view is missing\n"); } - views[color_count] = depth->vulkan_view; + views[color_count] = depth.vulkan_view; } vk::FramebufferCreateInfo framebuffer_info {}; @@ -283,7 +276,8 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, framebuffer_info.height = first_color_extent.height; framebuffer_info.layers = 1; - result = gctx->device.createFramebuffer(&framebuffer_info, nullptr, &framebuffer->framebuffer); + result = + m_graphics.device.createFramebuffer(&framebuffer_info, nullptr, &framebuffer->framebuffer); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); EXIT_NOT_IMPLEMENTED(framebuffer->framebuffer == nullptr); @@ -298,10 +292,10 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, (i < color_count && with_color[i] && colors[i].color_clear_enable); fnew.color_layout[i] = color_layout[i]; } - fnew.depth_id = (with_depth ? depth->vulkan_buffer->memory.unique_id : 0); - fnew.depth_view = (with_depth ? depth->vulkan_view : nullptr); - fnew.depth_clear_enable = depth->depth_load_clear_enable; - fnew.stencil_clear_enable = depth->stencil_clear_enable; + fnew.depth_id = (with_depth ? depth.vulkan_buffer->memory.unique_id : 0); + fnew.depth_view = (with_depth ? depth.vulkan_view : nullptr); + fnew.depth_clear_enable = depth.depth_load_clear_enable; + fnew.stencil_clear_enable = depth.stencil_clear_enable; fnew.depth_read_only = depth_read_only; bool updated = false; @@ -321,28 +315,21 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, return framebuffer; } -void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(image == nullptr); - +void FramebufferCache::FreeFramebufferByColor(VulkanImage& image) { Common::LockGuard lock(m_mutex); for (auto& f: m_framebuffers) { bool uses_image = false; for (auto image_id: f.image_id) { - if (image_id == image->memory.unique_id) { + if (image_id == image.memory.unique_id) { uses_image = true; break; } } if (f.framebuffer != nullptr && uses_image) { - auto* gctx = g_render_ctx->GetGraphicCtx(); + m_graphics.device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr); - EXIT_IF(gctx == nullptr); - - gctx->device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr); - - gctx->device.destroyRenderPass(f.framebuffer->render_pass, nullptr); + m_graphics.device.destroyRenderPass(f.framebuffer->render_pass, nullptr); delete f.framebuffer; @@ -351,21 +338,14 @@ void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) { } } -void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage* image) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(image == nullptr); - +void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage& image) { Common::LockGuard lock(m_mutex); for (auto& f: m_framebuffers) { - if (f.framebuffer != nullptr && f.depth_id == image->memory.unique_id) { - auto* gctx = g_render_ctx->GetGraphicCtx(); + if (f.framebuffer != nullptr && f.depth_id == image.memory.unique_id) { + m_graphics.device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr); - EXIT_IF(gctx == nullptr); - - gctx->device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr); - - gctx->device.destroyRenderPass(f.framebuffer->render_pass, nullptr); + m_graphics.device.destroyRenderPass(f.framebuffer->render_pass, nullptr); delete f.framebuffer; diff --git a/src/graphics/host_gpu/renderer/framebufferCache.h b/src/graphics/host_gpu/renderer/framebufferCache.h index e467ce836..6ebbf4d32 100644 --- a/src/graphics/host_gpu/renderer/framebufferCache.h +++ b/src/graphics/host_gpu/renderer/framebufferCache.h @@ -50,14 +50,16 @@ inline uint64_t render_pass_compat_id(uint32_t color_count, const vk::Format* co class FramebufferCache { public: - FramebufferCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } + explicit FramebufferCache(GraphicContext& graphics): m_graphics(graphics) { + EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); + } ~FramebufferCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(FramebufferCache); VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count, - RenderDepthInfo* depth); - void FreeFramebufferByColor(VulkanImage* image); - void FreeFramebufferByDepth(DepthStencilVulkanImage* image); + RenderDepthInfo& depth); + void FreeFramebufferByColor(VulkanImage& image); + void FreeFramebufferByDepth(DepthStencilVulkanImage& image); private: struct Framebuffer { @@ -73,6 +75,7 @@ private: bool depth_read_only = false; }; + GraphicContext& m_graphics; Common::Mutex m_mutex; std::vector m_framebuffers; }; diff --git a/src/graphics/host_gpu/renderer/gdsBuffer.cpp b/src/graphics/host_gpu/renderer/gdsBuffer.cpp index b89e33be7..9c9ce504d 100644 --- a/src/graphics/host_gpu/renderer/gdsBuffer.cpp +++ b/src/graphics/host_gpu/renderer/gdsBuffer.cpp @@ -6,7 +6,7 @@ namespace Libs::Graphics { -void GdsBuffer::Init(GraphicContext* ctx) { +void GdsBuffer::Init() { if (m_buffer == nullptr) { m_buffer = std::make_unique(); @@ -14,57 +14,54 @@ void GdsBuffer::Init(GraphicContext* ctx) { m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached; - VulkanCreateBuffer(ctx, DW_SIZE * 4, m_buffer.get()); + m_graphics.CreateBuffer(DW_SIZE * 4, *m_buffer); } } -void GdsBuffer::Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num, - uint32_t clear_value) { - EXIT_IF(ctx == nullptr); - +void GdsBuffer::Clear(uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value) { Common::LockGuard lock(m_mutex); - Init(ctx); + Init(); EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE); EXIT_NOT_IMPLEMENTED(dw_offset + dw_num > DW_SIZE); void* data = nullptr; - VulkanMapMemory(ctx, &m_buffer->memory, &data); + m_graphics.MapMemory(m_buffer->memory, data); for (uint32_t i = 0; i < dw_num; i++) { static_cast(data)[dw_offset + i] = clear_value; } - VulkanUnmapMemory(ctx, &m_buffer->memory); + m_graphics.UnmapMemory(m_buffer->memory); } -void GdsBuffer::Read(GraphicContext* ctx, uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) { +void GdsBuffer::Read(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) { EXIT_IF(dst == nullptr); Common::LockGuard lock(m_mutex); - Init(ctx); + Init(); EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE); EXIT_NOT_IMPLEMENTED(dw_offset + dw_size > DW_SIZE); void* data = nullptr; - VulkanMapMemory(ctx, &m_buffer->memory, &data); + m_graphics.MapMemory(m_buffer->memory, data); for (uint32_t i = 0; i < dw_size; i++) { dst[i] = static_cast(data)[dw_offset + i]; } - VulkanUnmapMemory(ctx, &m_buffer->memory); + m_graphics.UnmapMemory(m_buffer->memory); } -VulkanBuffer* GdsBuffer::GetBuffer(GraphicContext* ctx) { +VulkanBuffer& GdsBuffer::GetBuffer() { Common::LockGuard lock(m_mutex); - Init(ctx); + Init(); - return m_buffer.get(); + return *m_buffer; } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/gdsBuffer.h b/src/graphics/host_gpu/renderer/gdsBuffer.h index 265c9eae9..754d2b353 100644 --- a/src/graphics/host_gpu/renderer/gdsBuffer.h +++ b/src/graphics/host_gpu/renderer/gdsBuffer.h @@ -13,20 +13,23 @@ namespace Libs::Graphics { class GdsBuffer { public: - GdsBuffer() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } + explicit GdsBuffer(GraphicContext& graphics): m_graphics(graphics) { + EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); + } ~GdsBuffer() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(GdsBuffer); - void Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value); - void Read(GraphicContext* ctx, uint32_t* dst, uint32_t dw_offset, uint32_t dw_size); + void Clear(uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value); + void Read(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size); - VulkanBuffer* GetBuffer(GraphicContext* ctx); + VulkanBuffer& GetBuffer(); private: static constexpr uint64_t DW_SIZE = 0x3000; - void Init(GraphicContext* ctx); + void Init(); + GraphicContext& m_graphics; Common::Mutex m_mutex; std::unique_ptr m_buffer; }; diff --git a/src/graphics/host_gpu/renderer/gpuResourceManager.cpp b/src/graphics/host_gpu/renderer/gpuResourceManager.cpp index 7fbf757b6..682389f37 100644 --- a/src/graphics/host_gpu/renderer/gpuResourceManager.cpp +++ b/src/graphics/host_gpu/renderer/gpuResourceManager.cpp @@ -9,9 +9,9 @@ namespace Libs::Graphics { -GpuResourceManager::GpuResourceManager() - : m_page_manager(FaultThunk, this), m_buffer_cache(m_page_manager, m_resource_mutex), - m_texture_cache(m_page_manager, m_buffer_cache, m_resource_mutex) { +GpuResourceManager::GpuResourceManager(GraphicContext& graphics) + : m_page_manager(FaultThunk, this), m_buffer_cache(graphics, m_page_manager, m_resource_mutex), + m_texture_cache(graphics, m_page_manager, m_buffer_cache, m_resource_mutex) { m_buffer_cache.SetTextureCache(m_texture_cache); } @@ -72,8 +72,7 @@ void GpuResourceManager::PrepareHostWrite(uint64_t vaddr, uint64_t size) { } const auto handle_range = [this, vaddr, size]() { if (!m_page_manager.HandleWriteRange(vaddr, size)) { - EXIT("failed to prepare host write, addr=0x%016" PRIx64 " size=0x%016" PRIx64 - "\n", + EXIT("failed to prepare host write, addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", vaddr, size); } }; @@ -113,22 +112,22 @@ void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size, GpuAccess ac m_page_manager.OnGpuUnmap(vaddr, size, access); } -void GpuResourceManager::FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, +void GpuResourceManager::FillBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size, uint32_t value) { - if (g_render_ctx == nullptr || command == nullptr || command->IsInvalid()) { + if (command.IsInvalid()) { EXIT("cannot fill a buffer without a valid render command context\n"); } - Common::LockGuard lock(g_render_ctx->GetMutex()); - m_buffer_cache.FillBuffer(command, g_render_ctx->GetGraphicCtx(), vaddr, size, value); + Common::LockGuard lock(GetRenderContext().GetMutex()); + m_buffer_cache.FillBuffer(&command, vaddr, size, value); } -void GpuResourceManager::CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, +void GpuResourceManager::CopyBuffer(CommandBuffer& command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size) { - if (g_render_ctx == nullptr || command == nullptr || command->IsInvalid()) { + if (command.IsInvalid()) { EXIT("cannot copy a buffer without a valid render command context\n"); } - Common::LockGuard lock(g_render_ctx->GetMutex()); - m_buffer_cache.CopyBuffer(command, g_render_ctx->GetGraphicCtx(), dst_vaddr, src_vaddr, size); + Common::LockGuard lock(GetRenderContext().GetMutex()); + m_buffer_cache.CopyBuffer(&command, dst_vaddr, src_vaddr, size); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/gpuResourceManager.h b/src/graphics/host_gpu/renderer/gpuResourceManager.h index e2d94c21e..2ef0b6faa 100644 --- a/src/graphics/host_gpu/renderer/gpuResourceManager.h +++ b/src/graphics/host_gpu/renderer/gpuResourceManager.h @@ -16,20 +16,20 @@ class CommandBuffer; class GpuResourceManager { public: - GpuResourceManager(); + explicit GpuResourceManager(GraphicContext& graphics); ~GpuResourceManager(); KYTY_CLASS_NO_COPY(GpuResourceManager); - [[nodiscard]] BufferCache* GetBufferCache() { return &m_buffer_cache; } - [[nodiscard]] TextureCache* GetTextureCache() { return &m_texture_cache; } + [[nodiscard]] BufferCache& GetBufferCache() { return m_buffer_cache; } + [[nodiscard]] TextureCache& GetTextureCache() { return m_texture_cache; } [[nodiscard]] bool HandleFault(PageFaultAccess access, uint64_t fault_vaddr) noexcept; void PrepareHostWrite(uint64_t vaddr, uint64_t size); [[nodiscard]] bool IsMapped(uint64_t vaddr, uint64_t size) const noexcept; void MapMemory(uint64_t vaddr, uint64_t size, GpuAccess access); void UnmapMemory(uint64_t vaddr, uint64_t size, GpuAccess access); - void FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, uint32_t value); - void CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size); + void FillBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size, uint32_t value); + void CopyBuffer(CommandBuffer& command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size); private: static bool FaultThunk(void* context, PageFaultAccess access, uint64_t vaddr, uint64_t size, diff --git a/src/graphics/host_gpu/renderer/image.cpp b/src/graphics/host_gpu/renderer/image.cpp index fdd8a220e..c33b73274 100644 --- a/src/graphics/host_gpu/renderer/image.cpp +++ b/src/graphics/host_gpu/renderer/image.cpp @@ -50,15 +50,15 @@ TextureImageCreateParams MakeImageParams(const ImageInfo& info, bool storage) { return params; } -bool RenderTargetSupportsStorage(GraphicContext* ctx, vk::Format format, +bool RenderTargetSupportsStorage(vk::Format format, vk::ImageCreateFlags flags) { const auto compatible = SrgbStorageViewFormat(format); const auto required_flags = vk::ImageCreateFlagBits::eMutableFormat | vk::ImageCreateFlagBits::eExtendedUsage; const bool compatible_views = (flags & required_flags) == required_flags; - return ImageViewOps::FormatSupportsStorage(ctx, format) || + return ImageViewOps::FormatSupportsStorage(format) || (compatible_views && compatible != vk::Format::eUndefined && - ImageViewOps::FormatSupportsStorage(ctx, compatible)); + ImageViewOps::FormatSupportsStorage(compatible)); } vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) { @@ -72,20 +72,21 @@ vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) { : vk::ImageCreateFlags {0}; } -vk::ImageUsageFlags RenderTargetUsage(GraphicContext* ctx, vk::Format format, +vk::ImageUsageFlags RenderTargetUsage(vk::Format format, vk::ImageCreateFlags flags, uint32_t samples) { + auto& graphics = GetRenderContext().GetGraphics(); auto usage = static_cast(vk::ImageUsageFlagBits::eColorAttachment) | static_cast(vk::ImageUsageFlagBits::eTransferSrc) | static_cast(vk::ImageUsageFlagBits::eTransferDst); if (samples == 1) { usage |= vk::ImageUsageFlagBits::eSampled; - if (RenderTargetSupportsStorage(ctx, format, flags)) { + if (RenderTargetSupportsStorage(format, flags)) { usage |= vk::ImageUsageFlagBits::eStorage; } } vk::ImageFormatProperties properties {}; - if (ctx->GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, usage, - flags, &properties) != vk::Result::eSuccess || + if (graphics.GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, + usage, flags, &properties) != vk::Result::eSuccess || !static_cast(properties.sampleCounts & vulkan_sample_count(samples))) { EXIT("TextureCache: render-target format does not support required usage, format=%d " "usage=0x%x samples=%u supported=0x%x\n", @@ -146,44 +147,42 @@ uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element) { return RenderTargetTransferFormatImpl(bytes_per_element); } -GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage, - vk::ComponentMapping* components) { - if (components == nullptr) { - EXIT("TextureCache: invalid texture component output\n"); - } +GpuTextureVulkanImage* CreateTexture(const ImageInfo& info, bool storage, + vk::ComponentMapping& components) { auto* image = storage ? static_cast(new StorageTextureVulkanImage) : new TextureVulkanImage; - *components = TextureCreateImage(ctx, image, MakeImageParams(info, storage)); + components = TextureCreateImage(*image, MakeImageParams(info, storage)); return image; } -void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, - bool storage, vk::ComponentMapping components) { +void CreateTextureViews(GpuTextureVulkanImage& image, + const ImageInfo& info, bool storage, vk::ComponentMapping components) { if (storage) { - TextureCreateImageViews(ctx, image, components, info.type, 0, 0, 1, info.depth, false, + TextureCreateImageViews(image, components, info.type, 0, 0, 1, info.depth, false, TextureFormatUsage::Sampled | TextureFormatUsage::Storage); } else { - TextureCreateImageViews(ctx, image, components, info.type, info.base_array, info.base_level, - info.view_levels, info.depth, true, TextureFormatUsage::Sampled); + TextureCreateImageViews(image, components, info.type, info.base_array, + info.base_level, info.view_levels, info.depth, true, + TextureFormatUsage::Sampled); } } -void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image, +void UploadRenderTargetLayers(RenderTextureVulkanImage& image, const RenderTargetInfo& info, uint32_t base_layer, uint32_t layer_count, bool refresh) { if (info.layers == 0 || info.size % info.layers != 0 || layer_count == 0 || - base_layer >= info.layers || layer_count > info.layers - base_layer || image == nullptr || - base_layer >= image->layers || layer_count > image->layers - base_layer) { + base_layer >= info.layers || layer_count > info.layers - base_layer || + base_layer >= image.layers || layer_count > image.layers - base_layer) { EXIT("TextureCache: invalid render-target layer upload, base=%u count=%u " "info_layers=%u image_layers=%u size=0x%016" PRIx64 "\n", - base_layer, layer_count, info.layers, image != nullptr ? image->layers : 0, info.size); + base_layer, layer_count, info.layers, image.layers, info.size); } - if (info.samples != 1 || image->samples != 1) { + if (info.samples != 1 || image.samples != 1) { EXIT("TextureCache: multisampled render-target upload is unsupported, samples=%u/%u\n", - info.samples, image->samples); + info.samples, image.samples); } if (refresh) { - Transfer::WaitForGraphicsIdle(ctx); + Transfer::WaitForGraphicsIdle(); } const auto slice_size = info.size / info.layers; const auto upload_size = slice_size * layer_count; @@ -208,7 +207,7 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima region.dst_layer += base_layer; } const auto source_address = info.address + slice_size * base_layer; - TextureUploadGuestImage(ctx, image, reinterpret_cast(source_address), + TextureUploadGuestImage(image, reinterpret_cast(source_address), upload_size, regions, layout, format, info.width, info.height, layer_count, info.levels, "TextureCache render target", vk::ImageLayout::eGeneral); @@ -222,21 +221,23 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima "TextureCache render target"); auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1, true, false, TextureUploadDestination::MipLevels); - TextureUploadGuestImage(ctx, image, reinterpret_cast(info.address), slice_size, - regions, layout, format, info.width, info.height, 1, 1, + TextureUploadGuestImage(image, reinterpret_cast(info.address), + slice_size, regions, layout, format, info.width, info.height, 1, 1, "TextureCache render target", vk::ImageLayout::eGeneral); } else { - Transfer::UploadImage(ctx, image, reinterpret_cast(info.address), slice_size, - info.pitch, vk::ImageLayout::eGeneral); + Transfer::UploadImage(image, reinterpret_cast(info.address), + slice_size, info.pitch, vk::ImageLayout::eGeneral); } } -void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image, +void UploadRenderTarget(RenderTextureVulkanImage& image, const RenderTargetInfo& info, bool refresh) { - UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh); + UploadRenderTargetLayers(image, info, 0, info.layers, refresh); } -RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info) { +RenderTextureVulkanImage* CreateRenderTarget( + const RenderTargetInfo& info) { + auto& graphics = GetRenderContext().GetGraphics(); auto* image = new RenderTextureVulkanImage; image->extent.width = info.width; image->extent.height = info.height; @@ -255,20 +256,21 @@ RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTa create.format = info.format; create.tiling = vk::ImageTiling::eOptimal; create.initialLayout = vk::ImageLayout::eUndefined; - create.usage = RenderTargetUsage(ctx, info.format, create.flags, info.samples); + create.usage = RenderTargetUsage(info.format, create.flags, info.samples); create.sharingMode = vk::SharingMode::eExclusive; create.samples = vulkan_sample_count(info.samples); image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; - if (!VulkanCreateImage(ctx, create, image)) { + if (!graphics.CreateImage(create, *image)) { EXIT("TextureCache: failed to create render target, addr=0x%016" PRIx64 " extent=%ux%u format=%d\n", info.address, info.width, info.height, static_cast(info.format)); } - ImageViewOps::CreateRenderTargetViews(ctx, image); + ImageViewOps::CreateRenderTargetViews(*image); return image; } -DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info) { +DepthStencilVulkanImage* CreateDepthTarget(const DepthTargetInfo& info) { + auto& graphics = GetRenderContext().GetGraphics(); vk::ImageCreateInfo create {}; create.sType = vk::StructureType::eImageCreateInfo; create.imageType = vk::ImageType::e2D; @@ -282,9 +284,9 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge create.sharingMode = vk::SharingMode::eExclusive; create.samples = vulkan_sample_count(info.samples); vk::ImageFormatProperties properties {}; - if (ctx->GetImageFormatProperties(info.format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, - create.usage, vk::ImageCreateFlags {}, - &properties) != vk::Result::eSuccess || + if (graphics.GetImageFormatProperties( + info.format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, create.usage, + vk::ImageCreateFlags {}, &properties) != vk::Result::eSuccess || !static_cast(properties.sampleCounts & create.samples)) { EXIT("TextureCache: depth format does not support required usage, format=%d usage=0x%x " "samples=%u supported=0x%x\n", @@ -302,16 +304,16 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge image->layout = vk::ImageLayout::eUndefined; image->compressed = false; image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; - if (!VulkanCreateImage(ctx, create, image)) { + if (!graphics.CreateImage(create, *image)) { EXIT("TextureCache: failed to create depth target, addr=0x%016" PRIx64 " extent=%ux%u format=%d\n", info.address, info.width, info.height, static_cast(info.format)); } - ImageViewOps::CreateDepthViews(ctx, image); + ImageViewOps::CreateDepthViews(*image); return image; } -void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) { +void ValidateVideoOut(const VideoOutInfo& info) { const auto compression = ClassifyVideoOutCompression(info.compression != VideoOutCompression::Uncompressed, info.metadata_address, info.dcc_control, 0); @@ -320,23 +322,23 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) { (info.metadata_address >= TRACKER_ADDRESS_SIZE || (info.metadata_address >= info.address && info.metadata_address < info.address + info.size)); - if (ctx == nullptr || info.address == 0 || info.size == 0 || - info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address || - (info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 || - info.width > 16384 || info.height > 16384 || info.pitch < info.width || + if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE || + info.size > TRACKER_ADDRESS_SIZE - info.address || (info.address & 0xffffu) != 0 || + info.width == 0 || info.height == 0 || info.width > 16384 || info.height > 16384 || + info.pitch < info.width || info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || compression == VideoOutCompression::Unsupported || compression != info.compression || metadata_invalid || !IsSupportedVideoOutFormat(info)) { - EXIT("TextureCache: unsupported video-out surface, ctx=%p addr=0x%016" PRIx64 - " size=0x%016" PRIx64 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32 + EXIT("TextureCache: unsupported video-out surface, addr=0x%016" PRIx64 " size=0x%016" PRIx64 + " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32 " extent=%ux%u pitch=%u tile=%u guest_format=%u bpe=%u vk_format=%d\n", - static_cast(ctx), info.address, info.size, info.metadata_address, - info.dcc_control, info.width, info.height, info.pitch, info.tile_mode, - info.guest_format, info.bytes_per_element, static_cast(info.format)); + info.address, info.size, info.metadata_address, info.dcc_control, info.width, + info.height, info.pitch, info.tile_mode, info.guest_format, info.bytes_per_element, + static_cast(info.format)); } TileSizeAlign exact {}; TileGetTextureTotalSize(info.guest_format, info.width, info.height, 1, info.pitch, 1, - info.tile_mode, false, &exact); + info.tile_mode, false, exact); if (exact.align != 65536 || exact.size != info.size || TileGetTexturePitch(info.guest_format, info.width, 1, info.tile_mode) != info.pitch) { EXIT("TextureCache: video-out tile layout mismatch, addr=0x%016" PRIx64 @@ -344,10 +346,11 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) { " pitch=%u\n", info.address, info.size, exact.size, exact.align, info.pitch); } - (void)RenderTargetUsage(ctx, info.format, vk::ImageCreateFlags {}, 1); + (void)RenderTargetUsage(info.format, vk::ImageCreateFlags {}, 1); } -VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) { +VideoOutVulkanImage* CreateVideoOut(const VideoOutInfo& info) { + auto& graphics = GetRenderContext().GetGraphics(); auto* image = new VideoOutVulkanImage; image->extent.width = info.width; image->extent.height = info.height; @@ -363,20 +366,20 @@ VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& inf create.tiling = vk::ImageTiling::eOptimal; create.initialLayout = vk::ImageLayout::eUndefined; create.flags = RenderTargetCreateFlags(info.format); - create.usage = RenderTargetUsage(ctx, info.format, create.flags, 1); + create.usage = RenderTargetUsage(info.format, create.flags, 1); create.sharingMode = vk::SharingMode::eExclusive; create.samples = vk::SampleCountFlagBits::e1; image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; - if (!VulkanCreateImage(ctx, create, image)) { + if (!graphics.CreateImage(create, *image)) { EXIT("TextureCache: failed to create video-out image, addr=0x%016" PRIx64 " extent=%ux%u format=%d\n", info.address, info.width, info.height, static_cast(info.format)); } - ImageViewOps::CreateVideoOutViews(ctx, image); + ImageViewOps::CreateVideoOutViews(*image); return image; } -void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info, +void UploadVideoOut(VideoOutVulkanImage& image, const VideoOutInfo& info, bool refresh) { if (info.compression != VideoOutCompression::Uncompressed) { EXIT("TextureCache: compressed video-out guest upload is unsupported, " @@ -384,24 +387,24 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video info.address, info.metadata_address, info.dcc_control); } if (refresh) { - Transfer::WaitForGraphicsIdle(ctx); + Transfer::WaitForGraphicsIdle(); } - image->layout = vk::ImageLayout::eUndefined; + image.layout = vk::ImageLayout::eUndefined; if (!info.bgra16) { auto layout = TextureCalcUploadLayout(info.guest_format, info.width, info.height, 1, 1, info.pitch, info.tile_mode, info.size, false, false, "VideoOut"); auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1, false, false, TextureUploadDestination::MipLevels); - TextureUploadGuestImage(ctx, image, reinterpret_cast(info.address), info.size, - regions, layout, info.guest_format, info.width, info.height, 1, 1, - "VideoOut", vk::ImageLayout::eGeneral); + TextureUploadGuestImage(image, reinterpret_cast(info.address), + info.size, regions, layout, info.guest_format, info.width, + info.height, 1, 1, "VideoOut", vk::ImageLayout::eGeneral); return; } Transfer::ScratchBuffer scratch(info.size); TileBlockLayout block {}; EXIT_NOT_IMPLEMENTED( - !TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, info.bytes_per_element, &block)); + !TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, info.bytes_per_element, block)); const GpuTileInfo tile_info {block.family, block.bytes_per_element, 0, @@ -413,10 +416,10 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video info.height, 1, info.pitch}; - GpuDetile(ctx, reinterpret_cast(info.address), scratch.Data(), info.size, + GpuDetile(reinterpret_cast(info.address), scratch.Data(), info.size, info.size, std::span(&tile_info, 1)); SwapVideoOutBgra16(scratch.Data(), info.size); - Transfer::UploadImage(ctx, image, scratch.Data(), info.size, info.pitch, + Transfer::UploadImage(image, scratch.Data(), info.size, info.pitch, vk::ImageLayout::eGeneral); } @@ -427,7 +430,7 @@ void SwapVideoOutBgra16(void* data, uint64_t size) { } } -GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, bool image_3d, +GpuTextureVulkanImage* CreateDummyTexture(bool uint_format, bool image_3d, bool storage) { auto* image = storage ? static_cast(new StorageTextureVulkanImage) : new TextureVulkanImage; @@ -436,48 +439,47 @@ GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture"; auto params = MakeDummyTextureParams(uint_format, image_3d, usage, owner); - auto components = TextureCreateImage(ctx, image, params); + auto components = TextureCreateImage(*image, params); static constexpr uint32_t zero = 0; - Transfer::UploadImage(ctx, image, &zero, sizeof(zero), 1, layout); - TextureCreateImageViews(ctx, image, components, params.type, 0, params.base_level, + Transfer::UploadImage(*image, &zero, sizeof(zero), 1, layout); + TextureCreateImageViews(*image, components, params.type, 0, params.base_level, params.levels, params.depth, params.allow_cube_view, params.view_usage); return image; } -void Destroy(GraphicContext* ctx, VulkanImage* image) { +void Destroy(VulkanImage& image) { + auto& graphics = GetRenderContext().GetGraphics(); KYTY_PROFILER_BLOCK("TextureCache::DeleteImage"); - EXIT_IF(ctx == nullptr || image == nullptr || g_render_ctx == nullptr); - - switch (image->type) { + switch (image.type) { case VulkanImageType::RenderTexture: case VulkanImageType::VideoOut: - g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image); + GetRenderContext().GetFramebufferCache().FreeFramebufferByColor(image); break; case VulkanImageType::DepthStencil: - g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth( - static_cast(image)); + GetRenderContext().GetFramebufferCache().FreeFramebufferByDepth( + static_cast(image)); break; case VulkanImageType::Texture: case VulkanImageType::StorageTexture: break; case VulkanImageType::Unknown: EXIT("cannot destroy an untyped Vulkan image\n"); } - ImageViewOps::DestroyViews(ctx, image); - VulkanDeleteImage(ctx, image); + ImageViewOps::DestroyViews(image); + graphics.DeleteImage(image); - switch (image->type) { - case VulkanImageType::Texture: delete static_cast(image); break; + switch (image.type) { + case VulkanImageType::Texture: delete &static_cast(image); break; case VulkanImageType::StorageTexture: - delete static_cast(image); + delete &static_cast(image); break; case VulkanImageType::RenderTexture: - delete static_cast(image); + delete &static_cast(image); break; case VulkanImageType::DepthStencil: - delete static_cast(image); + delete &static_cast(image); break; - case VulkanImageType::VideoOut: delete static_cast(image); break; + case VulkanImageType::VideoOut: delete &static_cast(image); break; case VulkanImageType::Unknown: EXIT("cannot delete an untyped Vulkan image\n"); } } diff --git a/src/graphics/host_gpu/renderer/image.h b/src/graphics/host_gpu/renderer/image.h index 2b044b6dd..57d8b4e33 100644 --- a/src/graphics/host_gpu/renderer/image.h +++ b/src/graphics/host_gpu/renderer/image.h @@ -100,33 +100,34 @@ private: namespace ImageOps { -[[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, - bool storage, vk::ComponentMapping* components); -void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, - bool storage, vk::ComponentMapping components); +[[nodiscard]] GpuTextureVulkanImage* CreateTexture(const ImageInfo& info, + bool storage, vk::ComponentMapping& components); +void CreateTextureViews(GpuTextureVulkanImage& image, + const ImageInfo& info, bool storage, vk::ComponentMapping components); -[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, +[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget( const RenderTargetInfo& info); [[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element); -void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image, +void UploadRenderTargetLayers(RenderTextureVulkanImage& image, const RenderTargetInfo& info, uint32_t base_layer, uint32_t layer_count, bool refresh); -void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image, +void UploadRenderTarget(RenderTextureVulkanImage& image, const RenderTargetInfo& info, bool refresh); -[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, +[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget( const DepthTargetInfo& info); -void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info); -[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info); +void ValidateVideoOut(const VideoOutInfo& info); +[[nodiscard]] VideoOutVulkanImage* CreateVideoOut( + const VideoOutInfo& info); void SwapVideoOutBgra16(void* data, uint64_t size); -void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info, +void UploadVideoOut(VideoOutVulkanImage& image, const VideoOutInfo& info, bool refresh); -[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, +[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(bool uint_format, bool image_3d, bool storage); -void Destroy(GraphicContext* ctx, VulkanImage* image); +void Destroy(VulkanImage& image); } // namespace ImageOps diff --git a/src/graphics/host_gpu/renderer/imageInfo.h b/src/graphics/host_gpu/renderer/imageInfo.h index 0f089ac36..d8ee17f69 100644 --- a/src/graphics/host_gpu/renderer/imageInfo.h +++ b/src/graphics/host_gpu/renderer/imageInfo.h @@ -316,13 +316,10 @@ inline constexpr std::array VIDEO_OUT_FORMAT_POLICIES { }}; [[nodiscard]] inline bool DecodeVideoOutPixelFormat(uint64_t pixel_format, - VideoOutPixelFormatInfo* info) { - if (info == nullptr) { - return false; - } + VideoOutPixelFormatInfo& info) { for (const auto& policy: VIDEO_OUT_FORMAT_POLICIES) { if (policy.pixel_format == pixel_format) { - *info = policy.info; + info = policy.info; return true; } } @@ -388,9 +385,8 @@ enum class BufferImageWrite : uint8_t { [[nodiscard]] inline constexpr bool HasGuestCurrentImageOwnership(bool image_gpu_modified, bool buffer_modified, bool cpu_dirty, - bool tracker_gpu_modified, bool same_context) noexcept { - return !image_gpu_modified && !buffer_modified && !cpu_dirty && !tracker_gpu_modified && - same_context; + bool tracker_gpu_modified) noexcept { + return !image_gpu_modified && !buffer_modified && !cpu_dirty && !tracker_gpu_modified; } enum class StorageBufferRebind : uint8_t { Reuse, RefreshFromBacking, Unsupported }; @@ -398,11 +394,11 @@ enum class MetaImageOverlap : uint8_t { RetainSampled, RetireImage, Unsupported [[nodiscard]] inline constexpr bool CanRetireGuestCurrentDepthForMetadataReuse( bool depth_gpu_modified, bool depth_buffer_modified, bool depth_tracker_gpu_modified, - bool metadata_gpu_modified, bool metadata_tracker_gpu_modified, uint32_t metadata_clear_mask, - bool same_context) noexcept { + bool metadata_gpu_modified, bool metadata_tracker_gpu_modified, + uint32_t metadata_clear_mask) noexcept { return !metadata_gpu_modified && !metadata_tracker_gpu_modified && metadata_clear_mask == 0 && HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false, - depth_tracker_gpu_modified, same_context); + depth_tracker_gpu_modified); } [[nodiscard]] inline constexpr uint32_t SelectImageBackingBaseLevel(bool storage, @@ -493,12 +489,12 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available [[nodiscard]] inline MetaImageOverlap ClassifyMetaImageOverlap(bool sampled, bool writable_image, bool gpu_modified, - bool buffer_modified, bool cpu_dirty, - bool same_context) { + bool buffer_modified, + bool cpu_dirty) { if (sampled && !gpu_modified) { return MetaImageOverlap::RetainSampled; } - if (writable_image && !gpu_modified && !buffer_modified && !cpu_dirty && same_context) { + if (writable_image && !gpu_modified && !buffer_modified && !cpu_dirty) { return MetaImageOverlap::RetireImage; } return MetaImageOverlap::Unsupported; @@ -510,10 +506,7 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available } [[nodiscard]] inline bool DecodePackedColorClear(vk::Format format, uint32_t packed, - vk::ClearColorValue* clear) { - if (clear == nullptr) { - return false; - } + vk::ClearColorValue& clear) { vk::ClearColorValue next {}; const auto unorm8 = [](uint32_t value) { return static_cast(value & 0xffu) / 255.0f; }; switch (format) { @@ -555,32 +548,28 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available break; default: return false; } - *clear = next; + clear = next; return true; } -[[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t* clear) { - if (clear == nullptr) { - return false; - } +[[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t& clear) { const auto value = static_cast(packed); if (packed != static_cast(value) * 0x01010101u) { return false; } - *clear = value; + clear = value; return true; } -[[nodiscard]] inline bool DecodePackedDepthClear(vk::Format format, uint32_t packed, float* clear) { - if (clear == nullptr || - (format != vk::Format::eD32Sfloat && format != vk::Format::eD32SfloatS8Uint)) { +[[nodiscard]] inline bool DecodePackedDepthClear(vk::Format format, uint32_t packed, float& clear) { + if (format != vk::Format::eD32Sfloat && format != vk::Format::eD32SfloatS8Uint) { return false; } const auto value = std::bit_cast(packed); if (!std::isfinite(value) || value < 0.0f || value > 1.0f) { return false; } - *clear = value; + clear = value; return true; } @@ -643,13 +632,11 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available [[nodiscard]] inline SampledOverlap ClassifySampledOverlap(const ImageInfo& requested, const ImageInfo& cached, - bool cached_gpu_modified, - bool same_context) { + bool cached_gpu_modified) { if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) { return SampledOverlap::None; } - return !cached_gpu_modified && same_context ? SampledOverlap::ReadOnlyAlias - : SampledOverlap::Unsupported; + return !cached_gpu_modified ? SampledOverlap::ReadOnlyAlias : SampledOverlap::Unsupported; } [[nodiscard]] inline bool IsRgba8SrgbReinterpretation(vk::Format cached, @@ -702,7 +689,7 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available [[nodiscard]] inline StorageSampledOverlap ClassifyStorageSampledOverlap( const ImageInfo& requested, const ImageInfo& cached, vk::Format requested_view_format, vk::Format cached_image_format, bool cached_gpu_modified, bool cached_cpu_dirty, - bool same_context, bool exact_mip_subresource = false, bool cached_buffer_modified = false, + bool exact_mip_subresource = false, bool cached_buffer_modified = false, bool tracker_gpu_modified = true) { if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) { return StorageSampledOverlap::None; @@ -718,12 +705,11 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available (requested.format == cached.format && requested_view_format == cached_image_format) || IsRgba8SrgbReinterpretation(cached_image_format, requested_view_format) || IsR32UintFloatReinterpretation(cached_image_format, requested_view_format); - if (same_backing && compatible_format && cached_gpu_modified && !cached_cpu_dirty && - same_context) { + if (same_backing && compatible_format && cached_gpu_modified && !cached_cpu_dirty) { return StorageSampledOverlap::ExactImage; } if (exact_mip_subresource && cached_gpu_modified && tracker_gpu_modified && - !cached_buffer_modified && !cached_cpu_dirty && same_context) { + !cached_buffer_modified && !cached_cpu_dirty) { return StorageSampledOverlap::RetireStorage; } return StorageSampledOverlap::Unsupported; @@ -866,8 +852,7 @@ ClassifyStorageBufferRebind(bool buffer_overlap, bool cached_gpu_modified, [[nodiscard]] inline DepthOverlap ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified, bool storage_buffer_modified, bool storage_cpu_dirty, - bool tracker_gpu_modified, bool same_context, - const DepthTargetInfo& depth) { + bool tracker_gpu_modified, const DepthTargetInfo& depth) { const bool overlaps_depth = ImageRangeOverlaps(storage.address, storage.size, depth.address, depth.size); const bool overlaps_stencil = @@ -876,21 +861,20 @@ ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified, if (!overlaps_depth && !overlaps_stencil) { return DepthOverlap::None; } - const bool guest_current = - HasGuestCurrentImageOwnership(storage_gpu_modified, storage_buffer_modified, - storage_cpu_dirty, tracker_gpu_modified, same_context); + const bool guest_current = HasGuestCurrentImageOwnership( + storage_gpu_modified, storage_buffer_modified, storage_cpu_dirty, tracker_gpu_modified); const bool aspects_discarded = (!overlaps_depth || !depth.depth_access) && (!overlaps_stencil || !depth.stencil_access); - return guest_current || (!storage_buffer_modified && !storage_cpu_dirty && same_context && - aspects_discarded) + return guest_current || (!storage_buffer_modified && !storage_cpu_dirty && aspects_discarded) ? DepthOverlap::RetireStorage : DepthOverlap::Unsupported; } -[[nodiscard]] inline bool CanRetireGuestCurrentDepthForSampled( - const ImageInfo& sampled, const DepthTargetInfo& depth, bool depth_gpu_modified, - bool depth_buffer_modified, bool depth_tracker_gpu_modified, bool stencil_tracker_gpu_modified, - bool same_context) noexcept { +[[nodiscard]] inline bool +CanRetireGuestCurrentDepthForSampled(const ImageInfo& sampled, const DepthTargetInfo& depth, + bool depth_gpu_modified, bool depth_buffer_modified, + bool depth_tracker_gpu_modified, + bool stencil_tracker_gpu_modified) noexcept { const bool overlaps_depth = ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size); const bool overlaps_stencil = @@ -898,15 +882,15 @@ ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified, depth.stencil_address, depth.stencil_size); return (overlaps_depth || overlaps_stencil) && HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false, - depth_tracker_gpu_modified || stencil_tracker_gpu_modified, - same_context); + depth_tracker_gpu_modified || + stencil_tracker_gpu_modified); } [[nodiscard]] inline bool CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTargetInfo& depth, bool sampled_gpu_modified, bool sampled_buffer_modified, bool sampled_cpu_dirty, bool tracker_gpu_modified, - bool same_context, bool guest_source_current) noexcept { + bool guest_source_current) noexcept { const bool overlaps_depth = ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size); const bool overlaps_stencil = @@ -914,11 +898,11 @@ CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTarget depth.stencil_address, depth.stencil_size); return (overlaps_depth || overlaps_stencil) && guest_source_current && HasGuestCurrentImageOwnership(sampled_gpu_modified, sampled_buffer_modified, - sampled_cpu_dirty, tracker_gpu_modified, same_context); + sampled_cpu_dirty, tracker_gpu_modified); } [[nodiscard]] inline RenderTargetOverlap -ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified, bool same_context, +ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified, const RenderTargetInfo& target) { if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) { return RenderTargetOverlap::None; @@ -926,15 +910,15 @@ ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified, if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) { return RenderTargetOverlap::None; } - return !sampled_gpu_modified && same_context ? RenderTargetOverlap::RetireSampled - : RenderTargetOverlap::Unsupported; + return !sampled_gpu_modified ? RenderTargetOverlap::RetireSampled + : RenderTargetOverlap::Unsupported; } [[nodiscard]] inline RenderTargetOverlap ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_format, bool storage_gpu_modified, bool storage_buffer_modified, bool storage_cpu_dirty, bool tracker_gpu_modified, - bool same_context, const RenderTargetInfo& target) { + const RenderTargetInfo& target) { if (!ImagePageRangesOverlap(storage.address, storage.size, target.address, target.size)) { return RenderTargetOverlap::None; } @@ -950,11 +934,11 @@ ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_ storage.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && storage.base_array == 0 && target.levels == 1 && target.layers == 1 && target.samples == 1; if (exact_native_image && storage_gpu_modified && tracker_gpu_modified && - !storage_buffer_modified && !storage_cpu_dirty && same_context) { + !storage_buffer_modified && !storage_cpu_dirty) { return RenderTargetOverlap::PreserveStorage; } return HasGuestCurrentImageOwnership(storage_gpu_modified, storage_buffer_modified, - storage_cpu_dirty, tracker_gpu_modified, same_context) + storage_cpu_dirty, tracker_gpu_modified) ? RenderTargetOverlap::RetireStorage : RenderTargetOverlap::Unsupported; } @@ -988,29 +972,28 @@ ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_ [[nodiscard]] inline RenderTargetOverlap ClassifySampledRenderTargetOverlap(const ImageInfo& sampled, const RenderTargetInfo& target, - bool target_buffer_modified, bool same_context) { + bool target_buffer_modified) { if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) { return RenderTargetOverlap::None; } if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) { return RenderTargetOverlap::None; } - return same_context && !target_buffer_modified ? RenderTargetOverlap::RetireTarget - : RenderTargetOverlap::Unsupported; + return !target_buffer_modified ? RenderTargetOverlap::RetireTarget + : RenderTargetOverlap::Unsupported; } [[nodiscard]] inline StorageImageOverlap ClassifyStorageImageOverlap(uint64_t requested_address, uint64_t requested_size, uint64_t cached_address, uint64_t cached_size, bool sampled, - bool same_context, bool gpu_modified, bool buffer_modified, - bool tracker_gpu_modified) { + bool gpu_modified, bool buffer_modified, bool tracker_gpu_modified) { if (!ImagePageRangesOverlap(requested_address, requested_size, cached_address, cached_size)) { return StorageImageOverlap::None; } if (!ImageRangeOverlaps(requested_address, requested_size, cached_address, cached_size)) { return StorageImageOverlap::PageNeighbor; } - return sampled && same_context && !gpu_modified && !buffer_modified && !tracker_gpu_modified + return sampled && !gpu_modified && !buffer_modified && !tracker_gpu_modified ? StorageImageOverlap::RetireSampled : StorageImageOverlap::Unsupported; } @@ -1068,8 +1051,7 @@ IsCompatibleDepthTargetBacking(const DepthTargetInfo& cached, [[nodiscard]] inline RenderTargetOverlap ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modified, bool cached_buffer_modified, bool tracker_gpu_modified, - bool same_context, bool guest_source_current, - const RenderTargetInfo& requested) { + bool guest_source_current, const RenderTargetInfo& requested) { if (!ImagePageRangesOverlap(cached.address, cached.size, requested.address, requested.size)) { return RenderTargetOverlap::None; } @@ -1079,8 +1061,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi const bool expand = requested.layers > cached.layers && IsCompatibleRenderTargetBacking(requested, cached) && cached.format == requested.format; - if (expand && cached_gpu_modified && tracker_gpu_modified && !cached_buffer_modified && - same_context) { + if (expand && cached_gpu_modified && tracker_gpu_modified && !cached_buffer_modified) { return RenderTargetOverlap::ExpandTarget; } // A clean, page-isolated overlap is allocation-pool reuse, including a contained subrange. @@ -1100,7 +1081,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi cached.size != requested.size || pool_storage_shape_changed; return page_isolated && new_allocation && guest_source_current && HasGuestCurrentImageOwnership(cached_gpu_modified, cached_buffer_modified, false, - tracker_gpu_modified, same_context) + tracker_gpu_modified) ? RenderTargetOverlap::RetireTarget : RenderTargetOverlap::Unsupported; } @@ -1108,7 +1089,6 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi [[nodiscard]] inline DepthOverlap ClassifyDepthTargetOverlap(const DepthTargetInfo& cached, bool cached_gpu_modified, bool cached_buffer_modified, - bool same_context, const DepthTargetInfo& requested) { const auto overlaps = [](uint64_t left, uint64_t left_size, uint64_t right, uint64_t right_size, bool pages) { @@ -1132,12 +1112,12 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi } const bool expand = requested.layers > cached.layers && IsCompatibleDepthTargetBacking(requested, cached); - if (expand && cached_gpu_modified && !cached_buffer_modified && same_context) { + if (expand && cached_gpu_modified && !cached_buffer_modified) { return DepthOverlap::ExpandTarget; } const bool exact_discard = requested.depth_load_clear && cached_gpu_modified && !cached_buffer_modified && - same_context && cached.address == requested.address && cached.size == requested.size && + cached.address == requested.address && cached.size == requested.size && cached.samples == requested.samples && cached.stencil_address == 0 && cached.stencil_size == 0 && cached.htile_address == 0 && cached.htile_size == 0 && requested.stencil_address == 0 && requested.stencil_size == 0 && @@ -1158,7 +1138,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi cached.bytes_per_element == requested.bytes_per_element && cached.tile_mode == requested.tile_mode && cached.layers == 1 && requested.layers == 1 && cached.samples == 1 && requested.samples == 1; - return exact_plane_rebind && same_shape && !cached_buffer_modified && same_context + return exact_plane_rebind && same_shape && !cached_buffer_modified ? DepthOverlap::RecreateTarget : DepthOverlap::Unsupported; } @@ -1166,7 +1146,6 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi [[nodiscard]] inline bool CanRecreateDepthForRenderTarget(const DepthTargetInfo& depth, bool gpu_modified, bool buffer_modified, bool tracker_gpu_modified, - bool same_context, bool guest_source_current, const RenderTargetInfo& target) noexcept { const bool exact_depth = depth.address == target.address && depth.size == target.size; @@ -1189,15 +1168,16 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi const bool ownership_consistent = gpu_modified == tracker_gpu_modified && !buffer_modified; const bool source_available = ((exact_depth || exact_stencil) && gpu_modified) || guest_source_current; - return same_context && ownership_consistent && source_available && + return ownership_consistent && source_available && (exact_depth || exact_stencil || page_isolated_rebind) && depth.layers == 1 && target.levels == 1 && target.layers == 1 && depth.samples == 1 && target.samples == 1; } -[[nodiscard]] inline bool -CanRecreateRenderTargetForDepth(const RenderTargetInfo& target, bool gpu_modified, - bool buffer_modified, bool tracker_gpu_modified, bool same_context, - bool guest_source_current, const DepthTargetInfo& depth) noexcept { +[[nodiscard]] inline bool CanRecreateRenderTargetForDepth(const RenderTargetInfo& target, + bool gpu_modified, bool buffer_modified, + bool tracker_gpu_modified, + bool guest_source_current, + const DepthTargetInfo& depth) noexcept { const bool exact_depth = target.address == depth.address && target.size == depth.size; const bool exact_stencil = target.address == depth.stencil_address && target.size == depth.stencil_size; @@ -1214,10 +1194,9 @@ CanRecreateRenderTargetForDepth(const RenderTargetInfo& target, bool gpu_modifie depth.stencil_size % TRACKER_PAGE_SIZE == 0)); const bool source_available = (gpu_modified && (exact_depth || exact_stencil)) || guest_source_current; - return gpu_modified == tracker_gpu_modified && !buffer_modified && same_context && - source_available && (exact_depth || exact_stencil || page_isolated_rebind) && - target.levels == 1 && target.layers == 1 && depth.layers == 1 && target.samples == 1 && - depth.samples == 1; + return gpu_modified == tracker_gpu_modified && !buffer_modified && source_available && + (exact_depth || exact_stencil || page_isolated_rebind) && target.levels == 1 && + target.layers == 1 && depth.layers == 1 && target.samples == 1 && depth.samples == 1; } [[nodiscard]] inline bool RequiresMultisampleDepthRefresh(const DepthTargetInfo& info, diff --git a/src/graphics/host_gpu/renderer/imageView.cpp b/src/graphics/host_gpu/renderer/imageView.cpp index bd5dcf613..808c225f0 100644 --- a/src/graphics/host_gpu/renderer/imageView.cpp +++ b/src/graphics/host_gpu/renderer/imageView.cpp @@ -2,6 +2,7 @@ #include "common/assert.h" #include "graphics/host_gpu/objects/textureCommon.h" +#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/textureCache.h" #include @@ -10,19 +11,19 @@ namespace Libs::Graphics { namespace { -void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index, +void CreateView(VulkanImage& image, int view_index, vk::ImageViewType view_type, vk::ImageAspectFlags aspect_mask, vk::ComponentMapping components, uint32_t base_array_layer, uint32_t base_mip_level, uint32_t layer_count, uint32_t level_count, vk::Format view_format = vk::Format::eUndefined, - vk::ImageUsageFlags view_usage = {}) { - if (ctx == nullptr || image == nullptr || view_index < 0 || - view_index >= VulkanImage::VIEW_MAX || image->image == nullptr || - image->image_view[view_index] != nullptr) { + vk::ImageUsageFlags view_usage = {}) { + auto& graphics = GetRenderContext().GetGraphics(); + if (view_index < 0 || view_index >= VulkanImage::VIEW_MAX || + image.image_view[view_index] != nullptr) { EXIT("invalid image-view creation target: image=%p index=%d current_view=%d\n", - static_cast(image), view_index, - image != nullptr && view_index >= 0 && view_index < VulkanImage::VIEW_MAX && - image->image_view[view_index] != nullptr); + static_cast(&image), view_index, + view_index >= 0 && view_index < VulkanImage::VIEW_MAX && + image.image_view[view_index] != nullptr); } vk::ImageViewUsageCreateInfo usage_info {}; @@ -32,9 +33,9 @@ void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index, vk::ImageViewCreateInfo create_info {}; create_info.sType = vk::StructureType::eImageViewCreateInfo; create_info.pNext = view_usage ? &usage_info : nullptr; - create_info.image = image->image; + create_info.image = image.image; create_info.viewType = view_type; - create_info.format = view_format != vk::Format::eUndefined ? view_format : image->format; + create_info.format = view_format != vk::Format::eUndefined ? view_format : image.format; create_info.components = components; create_info.subresourceRange.aspectMask = aspect_mask; create_info.subresourceRange.baseArrayLayer = base_array_layer; @@ -43,22 +44,22 @@ void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index, create_info.subresourceRange.levelCount = level_count; const auto result = - ctx->device.createImageView(&create_info, nullptr, &image->image_view[view_index]); - if (result != vk::Result::eSuccess || image->image_view[view_index] == nullptr) { + graphics.device.createImageView(&create_info, nullptr, &image.image_view[view_index]); + if (result != vk::Result::eSuccess || image.image_view[view_index] == nullptr) { EXIT("failed to create image view: result=%d image_format=%d view_format=%d index=%d\n", - static_cast(result), static_cast(image->format), + static_cast(result), static_cast(image.format), static_cast(create_info.format), view_index); } } -void CreateRenderTargetView(GraphicContext* ctx, VulkanImage* image, int index, +void CreateRenderTargetView(VulkanImage& image, int index, vk::ComponentSwizzle r, vk::ComponentSwizzle g, vk::ComponentSwizzle b, vk::ComponentSwizzle a, vk::ImageViewType type = vk::ImageViewType::e2D, vk::Format view_format = vk::Format::eUndefined, vk::ImageUsageFlags view_usage = {}, uint32_t level_count = 0) { - const auto layer_count = type == vk::ImageViewType::e2DArray ? image->layers : 1u; - CreateView(ctx, image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, 0, - layer_count, level_count == 0 ? image->mip_levels : level_count, view_format, + const auto layer_count = type == vk::ImageViewType::e2DArray ? image.layers : 1u; + CreateView(image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, 0, + layer_count, level_count == 0 ? image.mip_levels : level_count, view_format, view_usage); } @@ -78,30 +79,31 @@ vk::ImageAspectFlags DepthAspectMask(vk::Format format) { } } -bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format) { - const auto properties = ctx->GetFormatProperties(format); +bool FormatSupportsStorage(vk::Format format) { + auto& graphics = GetRenderContext().GetGraphics(); + const auto properties = graphics.GetFormatProperties(format); return static_cast(properties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eStorageImage); } -void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image) { - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity, +void CreateRenderTargetViews(RenderTextureVulkanImage& image) { + CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, - vk::ComponentSwizzle::eIdentity); - if (image->layers > 1) { - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY, + vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity); + if (image.layers > 1) { + CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT_ARRAY, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ImageViewType::e2DArray); } - if (image->samples == 1 && FormatSupportsStorage(ctx, image->format)) { - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE, + if (image.samples == 1 && FormatSupportsStorage(image.format)) { + CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ImageViewType::e2D, vk::Format::eUndefined, vk::ImageUsageFlags {}, 1); - if (image->layers > 1) { - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE_ARRAY, + if (image.layers > 1) { + CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE_ARRAY, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ImageViewType::e2DArray, vk::Format::eUndefined, @@ -110,22 +112,21 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag } } -void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) { - CreateView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D, - DepthAspectMask(image->format), +void CreateDepthViews(DepthStencilVulkanImage& image) { + CreateView(image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D, + DepthAspectMask(image.format), {vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity}, 0, 0, 1, 1); } -void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) { - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity, +void CreateVideoOutViews(VideoOutVulkanImage& image) { + CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, - vk::ComponentSwizzle::eIdentity); - if ((image->format == vk::Format::eR8G8B8A8Srgb || - image->format == vk::Format::eB8G8R8A8Srgb) && - FormatSupportsStorage(ctx, vk::Format::eR8G8B8A8Uint)) { - CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE, + vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity); + if ((image.format == vk::Format::eR8G8B8A8Srgb || image.format == vk::Format::eB8G8R8A8Srgb) && + FormatSupportsStorage(vk::Format::eR8G8B8A8Uint)) { + CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ImageViewType::e2D, vk::Format::eR8G8B8A8Uint, @@ -133,20 +134,18 @@ void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) { } } -void DestroyViews(GraphicContext* ctx, VulkanImage* image) { - EXIT_IF(ctx == nullptr); - EXIT_IF(image == nullptr); - - for (auto& cached: image->view_cache.views) { +void DestroyViews(VulkanImage& image) { + auto& graphics = GetRenderContext().GetGraphics(); + for (auto& cached: image.view_cache.views) { if (cached.view != nullptr) { - ctx->device.destroyImageView(cached.view, nullptr); + graphics.device.destroyImageView(cached.view, nullptr); cached.view = nullptr; } } - image->view_cache.views.clear(); - for (auto& view: image->image_view) { + image.view_cache.views.clear(); + for (auto& view: image.image_view) { if (view != nullptr) { - ctx->device.destroyImageView(view, nullptr); + graphics.device.destroyImageView(view, nullptr); view = nullptr; } } @@ -154,54 +153,45 @@ void DestroyViews(GraphicContext* ctx, VulkanImage* image) { } // namespace ImageViewOps -vk::ImageView TextureCache::GetRenderTargetAttachmentView(GraphicContext* ctx, - RenderTextureVulkanImage* image, +vk::ImageView TextureCache::GetRenderTargetAttachmentView(RenderTextureVulkanImage& image, vk::Format format, uint32_t level, uint32_t base_layer, uint32_t layer_count) { - if (ctx == nullptr || image == nullptr || image->image == nullptr || - format == vk::Format::eUndefined || level >= image->mip_levels || level >= 16 || - layer_count == 0 || base_layer >= image->layers || - layer_count > image->layers - base_layer) { + if (image.format == vk::Format::eUndefined || level >= image.mip_levels || level >= 16 || + layer_count == 0 || base_layer >= image.layers || layer_count > image.layers - base_layer) { EXIT("TextureCache: invalid render-target attachment view, image=%p format=%d" " level=%u image_levels=%u base_layer=%u layer_count=%u image_layers=%u\n", - static_cast(image), static_cast(format), level, - image != nullptr ? image->mip_levels : 0, base_layer, layer_count, - image != nullptr ? image->layers : 0); + static_cast(&image), static_cast(format), level, image.mip_levels, + base_layer, layer_count, image.layers); } - if (format != image->format && !IsRgba8SrgbReinterpretation(image->format, format)) { + if (format != image.format && !IsRgba8SrgbReinterpretation(image.format, format)) { EXIT("TextureCache: incompatible render-target attachment view, image_format=%d" " view_format=%d level=%u\n", - static_cast(image->format), static_cast(format), level); + static_cast(image.format), static_cast(format), level); } - return GetImageView(ctx, image, - {format, - layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray, - vk::ImageAspectFlagBits::eColor, level, 1, base_layer, layer_count, - DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eColorAttachment}); + return GetImageView( + image, {format, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray, + vk::ImageAspectFlagBits::eColor, level, 1, base_layer, layer_count, + DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eColorAttachment}); } -vk::ImageView TextureCache::GetDepthTargetAttachmentView(GraphicContext* ctx, - DepthStencilVulkanImage* image, +vk::ImageView TextureCache::GetDepthTargetAttachmentView(DepthStencilVulkanImage& image, uint32_t base_layer, uint32_t layer_count) { - if (ctx == nullptr || image == nullptr || image->image == nullptr || layer_count == 0 || - base_layer >= image->layers || layer_count > image->layers - base_layer) { + if (layer_count == 0 || base_layer >= image.layers || layer_count > image.layers - base_layer) { EXIT("TextureCache: invalid depth-target attachment view, image=%p base_layer=%u " "layer_count=%u image_layers=%u\n", - static_cast(image), base_layer, layer_count, - image != nullptr ? image->layers : 0); + static_cast(&image), base_layer, layer_count, image.layers); } - return GetImageView( - ctx, image, - {image->format, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray, - ImageViewOps::DepthAspectMask(image->format), 0, 1, base_layer, layer_count, - DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eDepthStencilAttachment}); + return GetImageView(image, + {image.format, + layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray, + ImageViewOps::DepthAspectMask(image.format), 0, 1, base_layer, layer_count, + DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eDepthStencilAttachment}); } -vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image, - const ImageViewInfo& info) { +vk::ImageView TextureCache::GetImageView(VulkanImage& image, const ImageViewInfo& info) { const bool supported_type = info.type == vk::ImageViewType::e2D || info.type == vk::ImageViewType::e2DArray || info.type == vk::ImageViewType::e3D; @@ -213,23 +203,22 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image (info.type == vk::ImageViewType::e2D && info.layer_count == 1) || info.type == vk::ImageViewType::e2DArray || (info.type == vk::ImageViewType::e3D && info.base_layer == 0 && info.layer_count == 1); - if (ctx == nullptr || image == nullptr || image->image == nullptr || - info.format == vk::Format::eUndefined || !info.aspect || info.level_count == 0 || - info.base_level >= (image != nullptr ? image->mip_levels : 0) || - info.level_count > image->mip_levels - info.base_level || info.layer_count == 0 || - info.base_layer >= image->layers || info.layer_count > image->layers - info.base_layer || + if (info.format == vk::Format::eUndefined || !info.aspect || info.level_count == 0 || + info.base_level >= (image.mip_levels) || + info.level_count > image.mip_levels - info.base_level || info.layer_count == 0 || + info.base_layer >= image.layers || info.layer_count > image.layers - info.base_layer || !supported_type || !valid_shape || !supported_usage) { EXIT("TextureCache: invalid dynamic image view, image=%p format=%d aspect=0x%x" " swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d usage=0x%x" " image_levels=%u image_layers=%u\n", - static_cast(image), static_cast(info.format), + static_cast(&image), static_cast(info.format), static_cast(info.aspect), info.swizzle, info.base_level, info.level_count, info.base_layer, info.layer_count, static_cast(info.type), static_cast(info.usage), - image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0); + image.mip_levels, image.layers); } - auto& cache = image->view_cache; + auto& cache = image.view_cache; std::lock_guard lock(cache.mutex); for (const auto& cached: cache.views) { if (cached.info == info) { @@ -243,7 +232,7 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image vk::ImageViewCreateInfo create {}; create.sType = vk::StructureType::eImageViewCreateInfo; create.pNext = &usage; - create.image = image->image; + create.image = image.image; create.viewType = info.type; create.format = info.format; create.components = info.usage == vk::ImageUsageFlagBits::eSampled @@ -255,7 +244,7 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image create.subresourceRange.baseArrayLayer = info.base_layer; create.subresourceRange.layerCount = info.layer_count; vk::ImageView view = nullptr; - const auto result = ctx->device.createImageView(&create, nullptr, &view); + const auto result = m_graphics.device.createImageView(&create, nullptr, &view); if (result != vk::Result::eSuccess || view == nullptr) { EXIT("TextureCache: failed to create dynamic image view, result=%d format=%d" " aspect=0x%x swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d usage=0x%x\n", @@ -268,80 +257,68 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image return view; } -vk::ImageView TextureCache::GetDepthTargetSampledView(GraphicContext* ctx, - DepthStencilVulkanImage* image, +vk::ImageView TextureCache::GetDepthTargetSampledView(DepthStencilVulkanImage& image, vk::Format view_format, uint32_t swizzle, uint32_t base_level, uint32_t level_count, vk::ImageViewType type, uint32_t base_layer, uint32_t layer_count) { - if (ctx == nullptr || image == nullptr || image->image == nullptr || - view_format == vk::Format::eUndefined || - !IsSupportedSampledDepthView(image->format, view_format, swizzle)) { + if (view_format == vk::Format::eUndefined || + !IsSupportedSampledDepthView(image.format, view_format, swizzle)) { EXIT("TextureCache: invalid sampled depth-target view, image=%p image_format=%d" " view_format=%d swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d" " image_levels=%u image_layers=%u\n", - static_cast(image), - image != nullptr ? static_cast(image->format) - : static_cast(vk::Format::eUndefined), + static_cast(&image), static_cast(image.format), static_cast(view_format), swizzle, base_level, level_count, base_layer, - layer_count, static_cast(type), image != nullptr ? image->mip_levels : 0, - image != nullptr ? image->layers : 0); + layer_count, static_cast(type), image.mip_levels, image.layers); } - return GetImageView(ctx, image, - {image->format, type, vk::ImageAspectFlagBits::eDepth, base_level, - level_count, base_layer, layer_count, swizzle}); + return GetImageView(image, {image.format, type, vk::ImageAspectFlagBits::eDepth, base_level, + level_count, base_layer, layer_count, swizzle}); } -vk::ImageView TextureCache::GetSampledColorView(GraphicContext* ctx, VulkanImage* image, - vk::Format view_format, uint32_t swizzle, - uint32_t base_level, uint32_t level_count, - vk::ImageViewType type, uint32_t base_layer, - uint32_t layer_count) { - if (ctx == nullptr || image == nullptr || image->image == nullptr || - view_format == vk::Format::eUndefined || base_level >= 16 || +vk::ImageView TextureCache::GetSampledColorView(VulkanImage& image, vk::Format view_format, + uint32_t swizzle, uint32_t base_level, + uint32_t level_count, vk::ImageViewType type, + uint32_t base_layer, uint32_t layer_count) { + if (view_format == vk::Format::eUndefined || base_level >= 16 || (type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray) || - !IsSupportedSampledColorView(image->format, view_format, swizzle)) { + !IsSupportedSampledColorView(image.format, view_format, swizzle)) { EXIT("TextureCache: invalid sampled color view, image=%p swizzle=0x%03x" " view_format=%d mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n", - static_cast(image), swizzle, static_cast(view_format), base_level, - level_count, base_layer, layer_count, static_cast(type), - image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0); + static_cast(&image), swizzle, static_cast(view_format), base_level, + level_count, base_layer, layer_count, static_cast(type), image.mip_levels, + image.layers); } const auto precreated_view = type == vk::ImageViewType::e2DArray ? VulkanImage::VIEW_DEFAULT_ARRAY : VulkanImage::VIEW_DEFAULT; - const bool full_view = - base_level == 0 && level_count == image->mip_levels && base_layer == 0 && - layer_count == (type == vk::ImageViewType::e2DArray ? image->layers : 1u); - if (view_format == image->format && swizzle == DstSel(4, 5, 6, 7) && full_view && - image->image_view[precreated_view] != nullptr) { - return image->image_view[precreated_view]; + const bool full_view = base_level == 0 && level_count == image.mip_levels && base_layer == 0 && + layer_count == (type == vk::ImageViewType::e2DArray ? image.layers : 1u); + if (view_format == image.format && swizzle == DstSel(4, 5, 6, 7) && full_view && + image.image_view[precreated_view] != nullptr) { + return image.image_view[precreated_view]; } - return GetImageView(ctx, image, - {view_format, type, vk::ImageAspectFlagBits::eColor, base_level, - level_count, base_layer, layer_count, swizzle}); + return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, base_level, + level_count, base_layer, layer_count, swizzle}); } -vk::ImageView TextureCache::GetRenderTargetStorageView(GraphicContext* ctx, - RenderTextureVulkanImage* image, +vk::ImageView TextureCache::GetRenderTargetStorageView(RenderTextureVulkanImage& image, vk::Format view_format, uint32_t base_level, uint32_t level_count, vk::ImageViewType type, uint32_t base_layer, uint32_t layer_count) { - if (ctx == nullptr || image == nullptr || image->image == nullptr || - view_format == vk::Format::eUndefined || + if (view_format == vk::Format::eUndefined || (type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray)) { EXIT("TextureCache: invalid render-target storage view, image=%p view_format=%d" " mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n", - static_cast(image), static_cast(view_format), base_level, - level_count, base_layer, layer_count, static_cast(type), - image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0); + static_cast(&image), static_cast(view_format), base_level, + level_count, base_layer, layer_count, static_cast(type), image.mip_levels, + image.layers); } - const bool exact = view_format == image->format; - const bool compatible = view_format == BgraSrgbStorageViewFormat(image->format); + const bool exact = view_format == image.format; + const bool compatible = view_format == BgraSrgbStorageViewFormat(image.format); if (!exact && !compatible) { EXIT("TextureCache: incompatible render-target storage view, image_format=%d" " view_format=%d base=%u count=%u\n", - static_cast(image->format), static_cast(view_format), base_level, + static_cast(image.format), static_cast(view_format), base_level, level_count); } if (exact) { @@ -349,44 +326,40 @@ vk::ImageView TextureCache::GetRenderTargetStorageView(GraphicContext* : VulkanImage::VIEW_STORAGE; const bool full_view = base_level == 0 && level_count == 1 && base_layer == 0 && - layer_count == (type == vk::ImageViewType::e2DArray ? image->layers : 1u); - if (full_view && image->image_view[index] != nullptr) { - return image->image_view[index]; + layer_count == (type == vk::ImageViewType::e2DArray ? image.layers : 1u); + if (full_view && image.image_view[index] != nullptr) { + return image.image_view[index]; } } - if (compatible && !ImageViewOps::FormatSupportsStorage(ctx, view_format)) { + if (compatible && !ImageViewOps::FormatSupportsStorage(view_format)) { EXIT("TextureCache: compatible render-target storage format lacks storage support," " image_format=%d view_format=%d base=%u count=%u\n", - static_cast(image->format), static_cast(view_format), base_level, + static_cast(image.format), static_cast(view_format), base_level, level_count); } - return GetImageView(ctx, image, - {view_format, type, vk::ImageAspectFlagBits::eColor, base_level, - level_count, base_layer, layer_count, DstSel(4, 5, 6, 7), - vk::ImageUsageFlagBits::eStorage}); + return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, base_level, + level_count, base_layer, layer_count, DstSel(4, 5, 6, 7), + vk::ImageUsageFlagBits::eStorage}); } -vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext* ctx, - StorageTextureVulkanImage* image, +vk::ImageView TextureCache::GetStorageTextureSampledView(StorageTextureVulkanImage& image, const ImageInfo& info) { - const auto shape = - SelectStorageSampledViewShape(info.type, info.depth, image != nullptr ? image->layers : 0); - if (ctx == nullptr || image == nullptr || image->image == nullptr || - shape == StorageSampledViewShape::Unsupported || info.base_array != 0 || - info.levels != image->mip_levels || info.base_level >= info.levels || + const auto shape = SelectStorageSampledViewShape(info.type, info.depth, image.layers); + if (image.image == nullptr || shape == StorageSampledViewShape::Unsupported || + info.base_array != 0 || info.levels != image.mip_levels || info.base_level >= info.levels || info.view_levels == 0 || info.base_level + info.view_levels > info.levels) { EXIT("TextureCache: invalid sampled view of storage texture, image=%p type=%u depth=%u" " base=%u levels=%u view_levels=%u image_levels=%u base_array=%u\n", - static_cast(image), info.type, info.depth, info.base_level, info.levels, - info.view_levels, image != nullptr ? image->mip_levels : 0, info.base_array); + static_cast(&image), info.type, info.depth, info.base_level, info.levels, + info.view_levels, image.mip_levels, info.base_array); } const auto view_format = TextureGetFormat(info.format); - if (view_format != image->format && !IsRgba8SrgbReinterpretation(image->format, view_format) && - !IsR32UintFloatReinterpretation(image->format, view_format)) { + if (view_format != image.format && !IsRgba8SrgbReinterpretation(image.format, view_format) && + !IsR32UintFloatReinterpretation(image.format, view_format)) { EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d" " view_format=%d swizzle=0x%03x\n", - static_cast(image->format), static_cast(view_format), info.swizzle); + static_cast(image.format), static_cast(view_format), info.swizzle); } vk::ImageViewType type = static_cast(VK_IMAGE_VIEW_TYPE_MAX_ENUM); @@ -398,26 +371,22 @@ vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext* EXIT("TextureCache: unsupported sampled storage-image view shape\n"); } const auto layer_count = shape == StorageSampledViewShape::Image2DArray ? info.depth : 1u; - return GetImageView(ctx, image, - {view_format, type, vk::ImageAspectFlagBits::eColor, info.base_level, - info.view_levels, 0, layer_count, info.swizzle}); + return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, info.base_level, + info.view_levels, 0, layer_count, info.swizzle}); } -vk::ImageView TextureCache::GetStorageTextureStorageView(GraphicContext* ctx, - StorageTextureVulkanImage* image, +vk::ImageView TextureCache::GetStorageTextureStorageView(StorageTextureVulkanImage& image, uint32_t base_level) { - if (ctx == nullptr || image == nullptr || image->image == nullptr || - base_level >= (image != nullptr ? image->mip_levels : 0)) { + if (image.image == nullptr || base_level >= (image.mip_levels)) { EXIT("TextureCache: invalid storage-texture mip view, image=%p level=%u levels=%u\n", - static_cast(image), base_level, image != nullptr ? image->mip_levels : 0); + static_cast(&image), base_level, image.mip_levels); } if (base_level == 0) { - return image->image_view[VulkanImage::VIEW_DEFAULT]; + return image.image_view[VulkanImage::VIEW_DEFAULT]; } - return GetImageView(ctx, image, - {image->format, vk::ImageViewType::e2D, vk::ImageAspectFlagBits::eColor, - base_level, 1, 0, 1, DstSel(4, 5, 6, 7), - vk::ImageUsageFlagBits::eStorage}); + return GetImageView(image, {image.format, vk::ImageViewType::e2D, + vk::ImageAspectFlagBits::eColor, base_level, 1, 0, 1, + DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eStorage}); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/imageView.h b/src/graphics/host_gpu/renderer/imageView.h index 20399e1f8..41a90ca1f 100644 --- a/src/graphics/host_gpu/renderer/imageView.h +++ b/src/graphics/host_gpu/renderer/imageView.h @@ -216,12 +216,12 @@ ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource namespace ImageViewOps { [[nodiscard]] vk::ImageAspectFlags DepthAspectMask(vk::Format format); -[[nodiscard]] bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format); +[[nodiscard]] bool FormatSupportsStorage(vk::Format format); -void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image); -void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image); -void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image); -void DestroyViews(GraphicContext* ctx, VulkanImage* image); +void CreateRenderTargetViews(RenderTextureVulkanImage& image); +void CreateDepthViews(DepthStencilVulkanImage& image); +void CreateVideoOutViews(VideoOutVulkanImage& image); +void DestroyViews(VulkanImage& image); } // namespace ImageViewOps diff --git a/src/graphics/host_gpu/renderer/pipelineCache.cpp b/src/graphics/host_gpu/renderer/pipelineCache.cpp index f9dd2e6df..ae7c4bd06 100644 --- a/src/graphics/host_gpu/renderer/pipelineCache.cpp +++ b/src/graphics/host_gpu/renderer/pipelineCache.cpp @@ -8,6 +8,7 @@ #include "graphics/host_gpu/renderer/debug.h" #include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/framebufferCache.h" +#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/renderContext.h" #include @@ -39,78 +40,77 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other) return std::memcmp(this, &other, sizeof(*this)) == 0; } -PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline( - VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count, - RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx, - HW::Shader* sh_ctx, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, - bool ps_active, std::span vs_spirv, std::span ps_spirv) { +PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline( + VulkanFramebuffer& framebuffer, RenderColorInfo* colors, uint32_t color_count, + RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info, RenderCommandBuffer& command, + ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool ps_active, + std::span vs_spirv, std::span ps_spirv) { KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Gfx)", profiler::colors::DeepOrangeA200); - EXIT_IF(framebuffer == nullptr); - EXIT_IF(depth == nullptr); EXIT_IF(colors == nullptr); EXIT_IF(color_count > RENDER_COLOR_ATTACHMENTS_MAX); EXIT_IF(vs_spirv.empty()); EXIT_IF(ps_active && ps_spirv.empty()); Common::LockGuard lock(m_mutex); + auto& ctx = command.GetRegisters(); + auto& sh_ctx = command.GetShaders(); - const auto& vertex_info = sh_ctx->GetVs(); - const auto& ps_regs = sh_ctx->GetPs(); - const HW::BlendColor& bclr = ctx->GetBlendColor(); + const auto& vertex_info = sh_ctx.GetVs(); + const auto& ps_regs = sh_ctx.GetPs(); + const HW::BlendColor& bclr = ctx.GetBlendColor(); uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {}; for (uint32_t i = 0; i < color_count; i++) { color_mask[i] = (colors[i].vulkan_buffer != nullptr ? colors[i].export_mapping.ApplyMask(render_target_mask_slot( - ctx->GetRenderTargetMask(), colors[i].target_slot)) + ctx.GetRenderTargetMask(), colors[i].target_slot)) : 0); } - const HW::ModeControl& mc = ctx->GetModeControl(); + const HW::ModeControl& mc = ctx.GetModeControl(); - auto vs_id = ShaderGetIdVS(&vertex_info, vs_input_info, true); + auto vs_id = ShaderGetIdVS(vertex_info, vs_input_info, true); ShaderId ps_id {}; if (ps_active) { - ps_id = ShaderGetIdPS(&ps_regs, ps_input_info, true); + ps_id = ShaderGetIdPS(ps_regs, *ps_input_info, true); } PipelineStaticParameters static_params {}; GraphicsPipeline p {}; - p.render_pass_id = framebuffer->render_pass_id; + p.render_pass_id = framebuffer.render_pass_id; p.ps_shader_id = ps_id; p.vs_shader_id = vs_id; static_params.color_count = color_count; - if (ps_active && depth->depth_test_enable && ps_input_info->ps_execute_on_noop) { + if (ps_active && depth.depth_test_enable && ps_input_info->ps_execute_on_noop) { static std::atomic log_count {0}; if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { LOGF("Pipeline: temporary: accepting EXEC_ON_NOOP with depth test enabled\n"); } } - const auto& clip_control = ctx->GetClipControl(); + const auto& clip_control = ctx.GetClipControl(); EXIT_NOT_IMPLEMENTED(!clip_control.IsZClipModeRepresentable()); static_params.negative_one_to_one = !clip_control.dx_clip_space; static_params.depth_clip_enable = clip_control.IsZClipEnabled(); static_params.topology = topology; - static_params.samples = framebuffer->samples; + static_params.samples = framebuffer.samples; static_params.sample_shading_enable = - ps_active && framebuffer->samples > 1 && ps_input_info->ps_sample_shading; - if (static_params.sample_shading_enable && - !g_render_ctx->GetGraphicCtx()->sample_rate_shading_enabled) { + ps_active && framebuffer.samples > 1 && ps_input_info->ps_sample_shading; + if (static_params.sample_shading_enable && !m_graphics.sample_rate_shading_enabled) { EXIT("Pipeline: sample-rate shading is required but unsupported by the host\n"); } static_params.with_depth = - (depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr); - static_params.depth_test_enable = depth->depth_test_enable; - static_params.depth_write_enable = (depth->depth_write_enable && !depth->depth_clear_enable); - static_params.depth_compare_op = depth->depth_compare_op; - static_params.depth_bounds_test_enable = depth->depth_bounds_test_enable; - static_params.depth_min_bounds = depth->depth_min_bounds; - static_params.depth_max_bounds = depth->depth_max_bounds; - static_params.stencil_test_enable = depth->stencil_test_enable; - static_params.stencil_front = depth->stencil_static_front; - static_params.stencil_back = depth->stencil_static_back; + (depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr); + static_params.depth_test_enable = depth.depth_test_enable; + static_params.depth_write_enable = (depth.depth_write_enable && !depth.depth_clear_enable); + static_params.depth_compare_op = depth.depth_compare_op; + static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable; + static_params.depth_min_bounds = depth.depth_min_bounds; + static_params.depth_max_bounds = depth.depth_max_bounds; + static_params.stencil_test_enable = depth.stencil_test_enable; + static_params.stencil_front = depth.stencil_static_front; + static_params.stencil_back = depth.stencil_static_back; for (uint32_t i = 0; i < RENDER_COLOR_ATTACHMENTS_MAX; i++) { static_params.color_mask[i] = color_mask[i]; } @@ -119,8 +119,8 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline( static_params.face = mc.face; for (uint32_t i = 0; i < color_count; i++) { - const auto& rt = ctx->GetRenderTarget(colors[i].target_slot); - const auto& bc = ctx->GetBlendControl(colors[i].target_slot); + const auto& rt = ctx.GetRenderTarget(colors[i].target_slot); + const auto& bc = ctx.GetBlendControl(colors[i].target_slot); static_params.color_srcblend[i] = bc.color_srcblend; static_params.color_comb_fcn[i] = bc.color_comb_fcn; static_params.color_destblend[i] = bc.color_destblend; @@ -145,13 +145,13 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline( key.static_params = static_params; if (auto iter = m_graphics_pipelines.find(key); iter != m_graphics_pipelines.end()) { - return iter->second.get(); + return *iter->second; } if (graphics_debug_dump_enabled()) { ShaderDbgDumpInputInfo(vs_input_info); if (ps_active) { - ShaderDbgDumpInputInfo(ps_input_info); + ShaderDbgDumpInputInfo(*ps_input_info); } LOGF("PipelineTrace: shader binaries VS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64 " PS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64 "\n", @@ -162,9 +162,9 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline( auto cached = std::make_unique(p); LogPipelineTrace("CreatePipelineInternal begin", vs_id.hash0, vs_id.crc32, ps_id.hash0, ps_id.crc32); - CreatePipelineInternal(cached.get(), framebuffer->render_pass, vs_input_info, vs_spirv, - ps_input_info, ps_spirv, static_params, vs_id.hash0, vs_id.crc32, - ps_id.hash0, ps_id.crc32, ps_active); + CreatePipelineInternal(*cached, framebuffer.render_pass, vs_input_info, vs_spirv, ps_input_info, + ps_spirv, static_params, vs_id.hash0, vs_id.crc32, ps_id.hash0, + ps_id.crc32, ps_active); LogPipelineTrace("CreatePipelineInternal done", vs_id.hash0, vs_id.crc32, ps_id.hash0, ps_id.crc32); @@ -174,16 +174,15 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline( auto [iter, inserted] = m_graphics_pipelines.emplace(std::move(key), std::move(cached)); EXIT_IF(!inserted); - return iter->second.get(); + return *iter->second; } -PipelineCache::ComputePipeline* -PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info, - const HW::ComputeShaderInfo* cs_regs, +PipelineCache::ComputePipeline& +PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info, + const HW::ComputeShaderInfo& cs_regs, std::span cs_spirv) { KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100); - EXIT_IF(cs_regs == nullptr); EXIT_IF(cs_spirv.empty()); Common::LockGuard lock(m_mutex); @@ -197,7 +196,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info, key.cs_shader_id = p.cs_shader_id; if (auto iter = m_compute_pipelines.find(key); iter != m_compute_pipelines.end()) { - return iter->second.get(); + return *iter->second; } if (graphics_debug_dump_enabled()) { @@ -205,7 +204,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info, } auto cached = std::make_unique(p); - CreatePipelineInternal(cached.get(), input_info, cs_spirv); + CreatePipelineInternal(*cached, input_info, cs_spirv); EXIT_NOT_IMPLEMENTED(cached->pipeline == nullptr); EXIT_NOT_IMPLEMENTED(cached->pipeline_layout == nullptr); @@ -213,6 +212,6 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info, auto [iter, inserted] = m_compute_pipelines.emplace(std::move(key), std::move(cached)); EXIT_IF(!inserted); - return iter->second.get(); + return *iter->second; } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/pipelineCache.h b/src/graphics/host_gpu/renderer/pipelineCache.h index 3e61319b6..6dc5a8e16 100644 --- a/src/graphics/host_gpu/renderer/pipelineCache.h +++ b/src/graphics/host_gpu/renderer/pipelineCache.h @@ -17,9 +17,11 @@ namespace Libs::Graphics { +struct GraphicContext; struct RenderColorInfo; struct RenderDepthInfo; struct VulkanFramebuffer; +class RenderCommandBuffer; namespace HW { class Context; @@ -76,7 +78,7 @@ static_assert(std::is_trivially_copyable_v); static_assert(std::is_standard_layout_v); static_assert(alignof(PipelineStaticParameters) == 1); static_assert(sizeof(PipelineStaticParameters) == - sizeof(float[3]) + sizeof(float[3]) + sizeof(bool) * 2 + sizeof(int[4]) + + sizeof(float[3]) + sizeof(float[3]) + sizeof(bool) * 2 + sizeof(int[4]) + sizeof(vk::PrimitiveTopology) + sizeof(uint32_t) + sizeof(bool) * 4 + sizeof(vk::CompareOp) + sizeof(bool) + sizeof(float) * 2 + sizeof(bool) + sizeof(PipelineStencilStaticState) * 2 + sizeof(uint32_t) + @@ -86,7 +88,9 @@ static_assert(sizeof(PipelineStaticParameters) == class PipelineCache { public: - PipelineCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } + explicit PipelineCache(GraphicContext& graphics): m_graphics(graphics) { + EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); + } ~PipelineCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(PipelineCache); @@ -105,13 +109,13 @@ public: ShaderId cs_shader_id; }; - GraphicsPipeline* CreateGraphicsPipeline( - VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count, - RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx, - HW::Shader* sh_ctx, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, - bool ps_active, std::span vs_spirv, std::span ps_spirv); - ComputePipeline* CreateComputePipeline(ShaderComputeInputInfo* input_info, - const HW::ComputeShaderInfo* cs_regs, + GraphicsPipeline& CreateGraphicsPipeline( + VulkanFramebuffer& framebuffer, RenderColorInfo* colors, uint32_t color_count, + RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info, RenderCommandBuffer& command, + ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool ps_active, + std::span vs_spirv, std::span ps_spirv); + ComputePipeline& CreateComputePipeline(ShaderComputeInputInfo& input_info, + const HW::ComputeShaderInfo& cs_regs, std::span cs_spirv); private: @@ -136,12 +140,12 @@ private: }; struct PipelineKeyHash { - static void Mix(std::size_t* hash, std::size_t value) { - *hash ^= value + static_cast(0x9e3779b97f4a7c15ull) + (*hash << 6u) + - (*hash >> 2u); + static void Mix(std::size_t& hash, std::size_t value) { + hash ^= value + static_cast(0x9e3779b97f4a7c15ull) + (hash << 6u) + + (hash >> 2u); } - static void MixShaderId(std::size_t* hash, const ShaderId& id) { + static void MixShaderId(std::size_t& hash, const ShaderId& id) { Mix(hash, id.hash0); Mix(hash, id.crc32); Mix(hash, id.ids.size()); @@ -150,7 +154,7 @@ private: } } - static void MixStaticParams(std::size_t* hash, const PipelineStaticParameters& params) { + static void MixStaticParams(std::size_t& hash, const PipelineStaticParameters& params) { const auto* bytes = reinterpret_cast(¶ms); for (std::size_t i = 0; i < sizeof(params); i++) { Mix(hash, bytes[i]); @@ -161,10 +165,10 @@ private: struct GraphicsPipelineKeyHash { std::size_t operator()(const GraphicsPipelineKey& key) const { std::size_t hash = 0; - PipelineKeyHash::Mix(&hash, key.render_pass_id); - PipelineKeyHash::MixShaderId(&hash, key.vs_shader_id); - PipelineKeyHash::MixShaderId(&hash, key.ps_shader_id); - PipelineKeyHash::MixStaticParams(&hash, key.static_params); + PipelineKeyHash::Mix(hash, key.render_pass_id); + PipelineKeyHash::MixShaderId(hash, key.vs_shader_id); + PipelineKeyHash::MixShaderId(hash, key.ps_shader_id); + PipelineKeyHash::MixStaticParams(hash, key.static_params); return hash; } }; @@ -172,11 +176,12 @@ private: struct ComputePipelineKeyHash { std::size_t operator()(const ComputePipelineKey& key) const { std::size_t hash = 0; - PipelineKeyHash::MixShaderId(&hash, key.cs_shader_id); + PipelineKeyHash::MixShaderId(hash, key.cs_shader_id); return hash; } }; + GraphicContext& m_graphics; std::unordered_map, GraphicsPipelineKeyHash> m_graphics_pipelines; @@ -187,16 +192,16 @@ private: void LogPipelineTrace(const char* phase, uint32_t vs_hash0, uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32); -void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::RenderPass render_pass, - const ShaderVertexInputInfo* vs_input_info, +void CreatePipelineInternal(PipelineCache::GraphicsPipeline& pipeline, vk::RenderPass render_pass, + const ShaderVertexInputInfo& vs_input_info, std::span vs_shader, const ShaderPixelInputInfo* ps_input_info, std::span ps_shader, const PipelineStaticParameters& static_params, uint32_t vs_hash0, uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32, bool ps_active); -void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline, - const ShaderComputeInputInfo* input_info, +void CreatePipelineInternal(PipelineCache::ComputePipeline& pipeline, + const ShaderComputeInputInfo& input_info, std::span cs_shader); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/render.h b/src/graphics/host_gpu/renderer/render.h index c3fc94198..7ae5aab39 100644 --- a/src/graphics/host_gpu/renderer/render.h +++ b/src/graphics/host_gpu/renderer/render.h @@ -33,6 +33,7 @@ struct VulkanFramebuffer; struct RenderDepthInfo; struct RenderColorInfo; class BufferCache; +class RenderContext; struct HtileClearTarget { uint64_t address = 0; @@ -68,7 +69,7 @@ private: class CommandBuffer { public: - explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); } + explicit CommandBuffer(int queue); ~CommandBuffer() { Free(); } KYTY_CLASS_NO_COPY(CommandBuffer); @@ -85,17 +86,18 @@ public: vk::Semaphore signal_semaphore); void SetDebugInfo(uint32_t op, uint64_t submit_id, uint32_t arg0 = 0, uint32_t arg1 = 0, uint32_t arg2 = 0, uint32_t arg3 = 0, uint64_t arg4 = 0); - void BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors, - uint32_t color_count, RenderDepthInfo* depth) const; + void BeginRenderPass(VulkanFramebuffer& framebuffer, RenderColorInfo* colors, + uint32_t color_count, RenderDepthInfo& depth) const; void EndRenderPass() const; void WaitForFenceOnly(); void WaitForFence(); void WaitForFenceAndReset(); - void DeleteAfterFence(VulkanBuffer* buffer); + void DeleteAfterFence(VulkanBuffer& buffer); void RetainResourceUntilFence(std::shared_ptr resource); - void RecycleDescriptorAfterFence(VulkanDescriptorSet* set); + void RecycleDescriptorAfterFence(VulkanDescriptorSet& set); [[nodiscard]] vk::CommandBuffer Handle() const; + [[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; } [[nodiscard]] int GetQueue() const { return m_queue; } [[nodiscard]] bool IsExecute() const { return m_execute; } [[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; } @@ -111,6 +113,7 @@ private: void DeleteBuffersAfterFence(); void RecycleDescriptorsAfterFence(); + GraphicContext& m_graphics; VulkanCommandPool* m_pool = nullptr; uint32_t m_index = static_cast(-1); int m_queue = -1; @@ -131,34 +134,49 @@ private: HostStreamBuffer m_host_stream; }; -void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, - HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_type_and_size, +class RenderCommandBuffer final: public CommandBuffer { +public: + RenderCommandBuffer(int queue, HW::Context& registers, HW::UserConfig& user_config, + HW::Shader& shaders) + : CommandBuffer(queue), m_registers(registers), m_user_config(user_config), + m_shaders(shaders) {} + + [[nodiscard]] HW::Context& GetRegisters() const noexcept { return m_registers; } + [[nodiscard]] HW::UserConfig& GetUserConfig() const noexcept { return m_user_config; } + [[nodiscard]] HW::Shader& GetShaders() const noexcept { return m_shaders; } + +private: + HW::Context& m_registers; + HW::UserConfig& m_user_config; + HW::Shader& m_shaders; +}; + +void RenderDrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_type_and_size, uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type, uint32_t instance_count = 1, uint32_t render_target_slice_offset = 0, int32_t vertex_offset_add = 0, uint32_t first_instance = 0); -void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, - HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_count, +void RenderDrawIndexAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count, uint32_t flags, uint32_t render_target_slice_offset = 0, uint32_t instance_count = 1, uint32_t first_vertex = 0, uint32_t first_instance = 0); -void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, - HW::Shader* sh_ctx, uint32_t thread_group_x, uint32_t thread_group_y, - uint32_t thread_group_z, uint32_t mode); +void RenderDispatchDirect(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t thread_group_x, + uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode); void GraphicsRenderInit(); void GraphicsRenderCreateContext(); +void GraphicsRenderSetContext(RenderContext& context); void GraphicsRenderReleaseThreadCommandPools(); [[nodiscard]] bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x, uint32_t group_y, uint32_t group_z, uint32_t mode, - ShaderBufferResource* descriptor, - uint32_t* packed_clear, uint64_t* size); + ShaderBufferResource& descriptor, + uint32_t& packed_clear, uint64_t& size); [[nodiscard]] bool ResolveHtileClearTarget(const HW::DepthRenderTarget& target, - uint64_t descriptor_size, HtileClearTarget* resolved); + uint64_t descriptor_size, HtileClearTarget& resolved); -void GraphicsRenderMemoryBarrier(CommandBuffer* buffer); -void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size); -void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size); +void GraphicsRenderMemoryBarrier(CommandBuffer& buffer); +void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size); +void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/renderCompute.cpp b/src/graphics/host_gpu/renderer/renderCompute.cpp index 5839b918e..e370ae4df 100644 --- a/src/graphics/host_gpu/renderer/renderCompute.cpp +++ b/src/graphics/host_gpu/renderer/renderCompute.cpp @@ -51,11 +51,8 @@ static uint64_t BufferDescriptorSize(const ShaderBufferResource& descriptor) { } bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor_size, - HtileClearTarget* resolved) { - if (resolved == nullptr) { - return false; - } - *resolved = {}; + HtileClearTarget& resolved) { + resolved = {}; const bool has_stencil = z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid); const auto* depth_policy = FindDepthFormatPolicy(z.z_info.format); @@ -112,7 +109,7 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor if (!descriptor_backed_state) { return false; } - *resolved = {.address = z.htile_data_base_addr, .size = descriptor_size}; + resolved = {.address = z.htile_data_base_addr, .size = descriptor_size}; return true; } const uint32_t width = size_xy_valid ? static_cast(z.size.x_max) + 1u : z.width; @@ -124,10 +121,10 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor return false; } TileSizeAlign htile_size {}; - if (!TileGetHtileSize(width, height, &htile_size) || htile_size.size != descriptor_size) { + if (!TileGetHtileSize(width, height, htile_size) || htile_size.size != descriptor_size) { return false; } - *resolved = {.address = z.htile_data_base_addr, .size = htile_size.size}; + resolved = {.address = z.htile_data_base_addr, .size = htile_size.size}; return true; } @@ -154,9 +151,10 @@ static void ValidateFullHtileClearDispatch(const ShaderComputeInputInfo& input, } } -static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, const HW::Context& ctx, - uint32_t group_x, uint32_t group_y, uint32_t group_z, - uint32_t mode) { +static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, + const RenderCommandBuffer& buffer, uint32_t group_x, + uint32_t group_y, uint32_t group_z, uint32_t mode) { + const auto& ctx = buffer.GetRegisters(); const auto& program = *input.stage.program; const auto& resources = *input.stage.resources; if (resources.buffers.size() != program.info.buffers.size()) { @@ -164,7 +162,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons } const auto& z = ctx.GetDepthRenderTarget(); const uint64_t meta_addr = z.htile_data_base_addr; - auto* cache = g_render_ctx->GetTextureCache(); + auto& cache = GetRenderContext().GetTextureCache(); uint32_t current_references = 0; uint32_t registered_writes = 0; uint64_t described_meta_size = 0; @@ -182,7 +180,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons // identifiable even when it is no longer the currently bound depth target. TextureCache::MetaRangeInfo resolved_meta {}; if (resource.written && - cache->ResolveMetaRange(descriptor.Base48(), descriptor_size, &resolved_meta)) { + cache.ResolveMetaRange(descriptor.Base48(), descriptor_size, resolved_meta)) { registered_writes++; registered_target = {.address = descriptor.Base48(), .size = descriptor_size}; registered_meta = resolved_meta; @@ -197,7 +195,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons } HtileClearTarget target {}; if (current_references != 0) { - if (!ResolveHtileClearTarget(z, described_meta_size, &target)) { + if (!ResolveHtileClearTarget(z, described_meta_size, target)) { EXIT("unsupported HTile compute-clear target state: current=%u registered=%u " "meta=0x%016" PRIx64 "+0x%016" PRIx64 " depth=0x%016" PRIx64 "/0x%016" PRIx64 " stencil=0x%016" PRIx64 "/0x%016" PRIx64 @@ -210,14 +208,14 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons z.slice_div64_minus1, z.z_info.format, z.stencil_info.format, z.z_info.num_samples); } - cache->RegisterMeta(g_render_ctx->GetGraphicCtx(), target.address, target.size); - if (!cache->ResolveMetaRange(target.address, target.size, ®istered_meta)) { + cache.RegisterMeta(target.address, target.size); + if (!cache.ResolveMetaRange(target.address, target.size, registered_meta)) { EXIT("failed to resolve registered HTile compute-clear range\n"); } } else { target = registered_target; } - g_render_ctx->GetBufferCache()->ValidateGpuAccess(target.address, target.size, false, true); + GetRenderContext().GetBufferCache().ValidateGpuAccess(target.address, target.size, false, true); uint32_t metadata_writes = 0; ShaderBufferResource metadata_descriptor {}; @@ -245,20 +243,20 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons } if (resource.written || !resource.read || resource.atomic || descriptor.Base48() == 0 || descriptor_size == 0 || - cache->QueryRegion(descriptor.Base48(), descriptor_size).metadata_pages) { + cache.QueryRegion(descriptor.Base48(), descriptor_size).metadata_pages) { EXIT("unsupported HTile clear side-buffer access\n"); } - g_render_ctx->GetBufferCache()->ValidateGpuAccess(descriptor.Base48(), descriptor_size, - true, false); + GetRenderContext().GetBufferCache().ValidateGpuAccess(descriptor.Base48(), descriptor_size, + true, false); } if (metadata_writes != 1) { EXIT("HTile clear requires exactly one write-only metadata buffer, writes=%u\n", metadata_writes); } ValidateFullHtileClearDispatch(input, metadata_descriptor, group_x, group_y, group_z, mode); - const bool recorded = registered_meta.full ? cache->ClearMeta(registered_meta.metadata_address) - : cache->TouchMeta(registered_meta.metadata_address, - registered_meta.slice, true); + const bool recorded = registered_meta.full ? cache.ClearMeta(registered_meta.metadata_address) + : cache.TouchMeta(registered_meta.metadata_address, + registered_meta.slice, true); if (!recorded) { EXIT("failed to record HTile compute clear\n"); } @@ -267,11 +265,8 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x, uint32_t group_y, uint32_t group_z, uint32_t mode, - ShaderBufferResource* resolved_descriptor, uint32_t* resolved_clear, - uint64_t* resolved_size) { - if (resolved_descriptor == nullptr || resolved_clear == nullptr || resolved_size == nullptr) { - return false; - } + ShaderBufferResource& resolved_descriptor, uint32_t& resolved_clear, + uint64_t& resolved_size) { const auto& program = *input.stage.program; const auto& resources = *input.stage.resources; if (program.info.buffers.size() != 1 || resources.buffers.size() != 1 || @@ -313,24 +308,24 @@ bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t grou if (!full_dispatch || size == 0) { return false; } - *resolved_descriptor = descriptor; - *resolved_clear = clear; - *resolved_size = size; + resolved_descriptor = descriptor; + resolved_clear = clear; + resolved_size = size; return true; } -static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, CommandBuffer* command, +static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, CommandBuffer& command, uint32_t group_x, uint32_t group_y, uint32_t group_z, uint32_t mode) { ShaderBufferResource descriptor; uint32_t packed_clear = 0; uint64_t size = 0; - if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, &descriptor, - &packed_clear, &size)) { + if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, descriptor, packed_clear, + size)) { return false; } - auto* cache = g_render_ctx->GetTextureCache(); - if (!cache->ClearImageFromBuffer(command, descriptor.Base48(), size, packed_clear)) { + auto& cache = GetRenderContext().GetTextureCache(); + if (!cache.ClearImageFromBuffer(command, descriptor.Base48(), size, packed_clear)) { return false; } static std::atomic logged_clears {0}; @@ -342,28 +337,26 @@ static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, Com return true; } -void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, - HW::Shader* sh_ctx, uint32_t thread_group_x, uint32_t thread_group_y, - uint32_t thread_group_z, uint32_t mode) { - EXIT_IF(ctx == nullptr); - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); +void RenderDispatchDirect(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t thread_group_x, + uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode) { + EXIT_IF(buffer.IsInvalid()); + auto& ctx = buffer.GetRegisters(); + auto& sh_ctx = buffer.GetShaders(); - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::DispatchDirect), submit_id, - thread_group_x, thread_group_y, thread_group_z, mode, - sh_ctx != nullptr ? sh_ctx->GetCs().cs_regs.data_addr : 0); + buffer.SetDebugInfo(static_cast(CommandBufferDebugOp::DispatchDirect), submit_id, + thread_group_x, thread_group_y, thread_group_z, mode, + sh_ctx.GetCs().cs_regs.data_addr); - Common::LockGuard lock(g_render_ctx->GetMutex()); + Common::LockGuard lock(GetRenderContext().GetMutex()); - if (sh_ctx->GetCs().cs_regs.data_addr == 0) { + if (sh_ctx.GetCs().cs_regs.data_addr == 0) { LOGF("GraphicsRenderDispatchDirect: temporary: ignoring dispatch with null CS shader, " "groups=%ux%ux%u mode=%u\n", thread_group_x, thread_group_y, thread_group_z, mode); return; } - if (!ShaderAddressValid(sh_ctx->GetCs().cs_regs.data_addr)) { + if (!ShaderAddressValid(sh_ctx.GetCs().cs_regs.data_addr)) { return; } @@ -380,17 +373,17 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context LOGF("GraphicsRenderDispatchDirect: unknown dispatch initiator bits " "mode=0x%08" PRIx32 " unknown=0x%08" PRIx32 " shader=0x%016" PRIx64 " groups=%ux%ux%u\n", - mode, unknown_mode_bits, sh_ctx->GetCs().cs_regs.data_addr, thread_group_x, + mode, unknown_mode_bits, sh_ctx.GetCs().cs_regs.data_addr, thread_group_x, thread_group_y, thread_group_z); } } - const auto& cs_regs = sh_ctx->GetCs(); - const auto& sh_regs = ctx->GetShaderRegisters(); + const auto& cs_regs = sh_ctx.GetCs(); + const auto& sh_regs = ctx.GetShaderRegisters(); ShaderComputeInputInfo input_info {}; std::span cs_shader; - if (!ShaderCompileInfoCS(&cs_regs, &sh_regs, &input_info, &cs_shader)) { + if (!ShaderCompileInfoCS(cs_regs, sh_regs, input_info, cs_shader)) { EXIT("ShaderCompileInfoCS failed for dispatch with CS shader 0x%016" PRIx64 "\n", cs_regs.cs_regs.data_addr); } @@ -408,8 +401,8 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context (input_info.threads_num[0] * input_info.threads_num[1] * input_info.threads_num[2] >= 512); const auto& program = *input_info.stage.program; const auto& resources = *input_info.stage.resources; - if (TryConsumeComputeMetaClear(input_info, *ctx, thread_group_x, thread_group_y, thread_group_z, - mode)) { + if (TryConsumeComputeMetaClear(input_info, buffer, thread_group_x, thread_group_y, + thread_group_z, mode)) { return; } if (TryConsumeComputeImageClear(input_info, buffer, thread_group_x, thread_group_y, @@ -428,7 +421,7 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context LOGF("GraphicsRenderDispatchDirect: frame=%u shader=0x%016" PRIx64 " groups=%ux%ux%u mode=0x%08" PRIx32 " local=%ux%ux%u " "buffers=%zu textures=%zu sampled=%zu storage=%zu samplers=%zu push=%u\n", - frame_num, sh_ctx->GetCs().cs_regs.data_addr, thread_group_x, thread_group_y, + frame_num, sh_ctx.GetCs().cs_regs.data_addr, thread_group_x, thread_group_y, thread_group_z, mode, input_info.threads_num[0], input_info.threads_num[1], input_info.threads_num[2], program.info.buffers.size(), program.info.images.size(), sampled_images, program.info.images.size() - sampled_images, @@ -503,23 +496,23 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context LOGF("GraphicsRenderDispatchDirect: skipping zero-sized dispatch groups=%ux%ux%u " "mode=0x%08" PRIx32 " shader=0x%016" PRIx64 "\n", thread_group_x, thread_group_y, thread_group_z, mode, - sh_ctx->GetCs().cs_regs.data_addr); + sh_ctx.GetCs().cs_regs.data_addr); } return; } for (;;) { - const auto recording_generation = buffer->GetRecordingGeneration(); - auto vk_buffer = buffer->Handle(); - auto* pipeline = g_render_ctx->GetPipelineCache()->CreateComputePipeline( - &input_info, &sh_ctx->GetCs(), cs_shader); + const auto recording_generation = buffer.GetRecordingGeneration(); + auto vk_buffer = buffer.Handle(); + auto& pipeline = GetRenderContext().GetPipelineCache().CreateComputePipeline( + input_info, sh_ctx.GetCs(), cs_shader); - vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->pipeline); + vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline.pipeline); BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eCompute, - pipeline->pipeline_layout, input_info.stage, + pipeline.pipeline_layout, input_info.stage, vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); - if (buffer->GetRecordingGeneration() != recording_generation) { + if (buffer.GetRecordingGeneration() != recording_generation) { continue; } diff --git a/src/graphics/host_gpu/renderer/renderContext.cpp b/src/graphics/host_gpu/renderer/renderContext.cpp index ef54c4ea5..67ab9e47e 100644 --- a/src/graphics/host_gpu/renderer/renderContext.cpp +++ b/src/graphics/host_gpu/renderer/renderContext.cpp @@ -2,7 +2,6 @@ #include "common/assert.h" #include "common/logging/log.h" -#include "graphics/presentation/window.h" #include "kernel/pthread.h" #include "libs/errno.h" @@ -10,38 +9,11 @@ namespace Libs::Graphics { -void RenderContext::SetGraphicCtx(GraphicContext* ctx) { - EXIT_IF(ctx == nullptr); - - Common::LockGuard lock(m_graphic_ctx_mutex); - - m_graphic_ctx = ctx; -} - -GraphicContext* RenderContext::GetGraphicCtx() { - { - Common::LockGuard lock(m_graphic_ctx_mutex); - if (m_graphic_ctx != nullptr) { - return m_graphic_ctx; - } - } - - WindowWaitForGraphicInitialized(); - - auto* ctx = WindowGetGraphicContext(); - LOGF("Graphic context initialized\n ctx = %p\n", static_cast(ctx)); - EXIT_IF(ctx == nullptr); - - GraphicContext* ret = nullptr; - { - Common::LockGuard lock(m_graphic_ctx_mutex); - if (m_graphic_ctx == nullptr) { - m_graphic_ctx = ctx; - } - ret = m_graphic_ctx; - } - - return ret; +RenderContext::RenderContext(GraphicContext& graphics) + : m_graphics(graphics), m_pipeline_cache(graphics), m_descriptor_cache(graphics), + m_framebuffer_cache(graphics), m_sampler_cache(graphics), m_gds_buffer(graphics), + m_gpu_resources(graphics) { + EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } void RenderContext::AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id) { diff --git a/src/graphics/host_gpu/renderer/renderContext.h b/src/graphics/host_gpu/renderer/renderContext.h index c2ee5f1fd..aaf6db910 100644 --- a/src/graphics/host_gpu/renderer/renderContext.h +++ b/src/graphics/host_gpu/renderer/renderContext.h @@ -23,22 +23,21 @@ constexpr int AGC_USER_INTERRUPT_EVENT = 0x1800; class RenderContext { public: - RenderContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } + explicit RenderContext(GraphicContext& graphics); ~RenderContext() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(RenderContext); - void SetGraphicCtx(GraphicContext* ctx); - GraphicContext* GetGraphicCtx(); + [[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; } Common::Mutex& GetMutex() { return m_mutex; } - PipelineCache* GetPipelineCache() { return &m_pipeline_cache; } - DescriptorCache* GetDescriptorCache() { return &m_descriptor_cache; } - FramebufferCache* GetFramebufferCache() { return &m_framebuffer_cache; } - SamplerCache* GetSamplerCache() { return &m_sampler_cache; } - GdsBuffer* GetGdsBuffer() { return &m_gds_buffer; } - GpuResourceManager* GetGpuResources() { return &m_gpu_resources; } - BufferCache* GetBufferCache() { return m_gpu_resources.GetBufferCache(); } - TextureCache* GetTextureCache() { return m_gpu_resources.GetTextureCache(); } + PipelineCache& GetPipelineCache() { return m_pipeline_cache; } + DescriptorCache& GetDescriptorCache() { return m_descriptor_cache; } + FramebufferCache& GetFramebufferCache() { return m_framebuffer_cache; } + SamplerCache& GetSamplerCache() { return m_sampler_cache; } + GdsBuffer& GetGdsBuffer() { return m_gds_buffer; } + GpuResourceManager& GetGpuResources() { return m_gpu_resources; } + BufferCache& GetBufferCache() { return m_gpu_resources.GetBufferCache(); } + TextureCache& GetTextureCache() { return m_gpu_resources.GetTextureCache(); } void AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id); void DeleteEopEq(LibKernel::EventQueue::KernelEqueue eq, int id); @@ -51,13 +50,12 @@ private: uint32_t count = 0; }; + GraphicContext& m_graphics; Common::Mutex m_mutex; - Common::Mutex m_graphic_ctx_mutex; PipelineCache m_pipeline_cache; DescriptorCache m_descriptor_cache; FramebufferCache m_framebuffer_cache; SamplerCache m_sampler_cache; - GraphicContext* m_graphic_ctx = nullptr; GdsBuffer m_gds_buffer; GpuResourceManager m_gpu_resources; @@ -65,7 +63,8 @@ private: std::vector m_eop_eqs; }; -extern RenderContext* g_render_ctx; +[[nodiscard]] bool HasRenderContext() noexcept; +[[nodiscard]] RenderContext& GetRenderContext(); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index 62aaec9ea..f500a6abd 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -70,7 +70,7 @@ static std::atomic g_mrt_state_log_count = 0; static std::atomic g_shader_stage_log_count = 0; static std::atomic g_framebuffer_skip_log_count = 0; -static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, +static bool ResolveColorTargets(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t render_target_slice_offset); static const char* RenderColorTypeName(RenderColorType type) { @@ -87,8 +87,10 @@ static bool IsDualSourceBlendFactor(uint32_t factor) { } static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& color, - const RenderDepthInfo& depth, const HW::Context* ctx, - const HW::UserConfig* ucfg, uint32_t index_count, uint32_t flags) { + const RenderDepthInfo& depth, const RenderCommandBuffer& buffer, + uint32_t index_count, uint32_t flags) { + const auto& ctx = buffer.GetRegisters(); + const auto& ucfg = buffer.GetUserConfig(); if (!graphics_debug_dump_enabled()) { return; } @@ -104,19 +106,17 @@ static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& col " prim=%u index_count=%u flags=0x%08" PRIx32 "\n", log_id, draw_name, RenderColorTypeName(color.type), color.base_addr, color.buffer_size, color.vulkan_buffer != nullptr ? "yes" : "no", VulkanToString(depth.format).c_str(), - depth.vulkan_buffer != nullptr ? "yes" : "no", depth.vaddr_num, - ctx != nullptr ? ctx->GetRenderTargetMask() : 0, ucfg != nullptr ? ucfg->GetPrimType() : 0, - index_count, flags); + depth.vulkan_buffer != nullptr ? "yes" : "no", depth.vaddr_num, ctx.GetRenderTargetMask(), + ucfg.GetPrimType(), index_count, flags); } -static void LogMrtState(const char* draw_name, const HW::Context* ctx, +static void LogMrtState(const char* draw_name, const RenderCommandBuffer& buffer, const ShaderPixelInputInfo& ps_input_info) { - EXIT_IF(ctx == nullptr); - - const auto& sh_regs = ctx->GetShaderRegisters(); - const auto rt_mask = ctx->GetRenderTargetMask(); + const auto& ctx = buffer.GetRegisters(); + const auto& sh_regs = ctx.GetShaderRegisters(); + const auto rt_mask = ctx.GetRenderTargetMask(); const auto cb_shader_mask = sh_regs.m_cbShaderMask; - const auto& bc0 = ctx->GetBlendControl(0); + const auto& bc0 = ctx.GetBlendControl(0); bool interesting = rt_mask != 0x0f || (cb_shader_mask & ~0x0fu) != 0 || IsDualSourceBlendFactor(bc0.color_srcblend) || @@ -125,7 +125,7 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx, IsDualSourceBlendFactor(bc0.alpha_destblend))); for (uint32_t i = 1; i < 8; i++) { - const auto& rt = ctx->GetRenderTarget(i); + const auto& rt = ctx.GetRenderTarget(i); if (rt.base.addr != 0 || ps_input_info.target_output_mode[i] != 0 || ((rt_mask >> (i * 4u)) & 0x0fu) != 0 || ((cb_shader_mask >> (i * 4u)) & 0x0fu) != 0) { interesting = true; @@ -148,8 +148,8 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx, bc0.separate_alpha_blend ? "true" : "false"); for (uint32_t i = 0; i < 8; i++) { - const auto& rt = ctx->GetRenderTarget(i); - const auto& bc = ctx->GetBlendControl(i); + const auto& rt = ctx.GetRenderTarget(i); + const auto& bc = ctx.GetBlendControl(i); const auto ctm = (rt_mask >> (i * 4u)) & 0x0fu; const auto csm = (cb_shader_mask >> (i * 4u)) & 0x0fu; @@ -171,10 +171,11 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx, } static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& color, - const RenderDepthInfo& depth, const HW::Context* ctx, - const HW::UserConfig* ucfg, + const RenderDepthInfo& depth, const RenderCommandBuffer& buffer, const ShaderPixelInputInfo& ps_input_info, uint32_t index_count, uint32_t flags) { + const auto& ctx = buffer.GetRegisters(); + const auto& ucfg = buffer.GetUserConfig(); if (color.type == RenderColorType::NoColorOutput) { return; } @@ -184,13 +185,10 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col return; } - EXIT_IF(ctx == nullptr); - EXIT_IF(ucfg == nullptr); - - const auto& cc = ctx->GetColorControl(); - const auto& bc = ctx->GetBlendControl(color.target_slot); - const auto& dc = ctx->GetDepthControl(); - const auto& vp = ctx->GetScreenViewport(); + const auto& cc = ctx.GetColorControl(); + const auto& bc = ctx.GetBlendControl(color.target_slot); + const auto& dc = ctx.GetDepthControl(); + const auto& vp = ctx.GetScreenViewport(); const auto& vp0 = vp.viewports[0]; const auto& ps_resources = ps_input_info.stage.program->info; const auto sampled_images = std::count_if( @@ -200,7 +198,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col }); vk::Extent2D extent = color.vulkan_buffer != nullptr ? color.extent : vk::Extent2D {}; - auto sc = calc_final_scissor(vp, ctx->GetScanModeControl(), extent); + auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent); LOGF( "DrawTargetState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64 @@ -210,8 +208,8 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col " depth_test=%s depth_write=%s depth_func=%u depth_clear=%s viewport=(%.1f,%.1f %.1fx%.1f) " "scissor=(%d,%d)-(%d,%d)\n", log_id, GraphicsRunGetFrameNum(), draw_name, RenderColorTypeName(color.type), - color.base_addr, extent.width, extent.height, ucfg->GetPrimType(), index_count, flags, - ctx->GetRenderTargetMask(), color.color_clear_enable ? "true" : "false", + color.base_addr, extent.width, extent.height, ucfg.GetPrimType(), index_count, flags, + ctx.GetRenderTargetMask(), color.color_clear_enable ? "true" : "false", color.color_clear_value.float32[0], color.color_clear_value.float32[1], color.color_clear_value.float32[2], color.color_clear_value.float32[3], cc.mode, cc.op, bc.enable ? "true" : "false", bc.color_srcblend, bc.color_destblend, bc.color_comb_fcn, @@ -223,7 +221,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col vp0.yoffset - vp0.yscale, vp0.xscale * 2.0f, vp0.yscale * 2.0f, sc.left, sc.top, sc.right, sc.bottom); - LogMrtState(draw_name, ctx, ps_input_info); + LogMrtState(draw_name, buffer, ps_input_info); } static void LogDrawInputState(const RenderColorInfo& color, @@ -305,11 +303,11 @@ static void LogDrawInputState(const RenderColorInfo& color, } } -static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuffer command_buffer, - uint32_t attachment_count, - const vk::Bool32* p_color_write_enables) { - EXIT_IF(ctx == nullptr); - EXIT_IF(ctx->device == nullptr); +static void VulkanCmdSetColorWriteEnableEXT(const RenderCommandBuffer& buffer, + vk::CommandBuffer command_buffer, + uint32_t attachment_count, + const vk::Bool32* p_color_write_enables) { + EXIT_IF(buffer.GetGraphics().device == nullptr); if (VULKAN_HPP_DEFAULT_DISPATCHER.vkCmdSetColorWriteEnableEXT == nullptr) { EXIT("vkCmdSetColorWriteEnableEXT not present\n"); @@ -317,11 +315,12 @@ static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuff command_buffer.setColorWriteEnableEXT(attachment_count, p_color_write_enables); } -static PipelineDynamicParameters BuildGraphicsDynamicParams(const HW::Context& ctx, - const RenderColorInfo* colors, - uint32_t color_count, - const RenderDepthInfo& depth) { +static PipelineDynamicParameters BuildGraphicsDynamicParams(const RenderCommandBuffer& buffer, + const RenderColorInfo* colors, + uint32_t color_count, + const RenderDepthInfo& depth) { EXIT_IF(colors == nullptr); + const auto& ctx = buffer.GetRegisters(); PipelineDynamicParameters ret {}; ret.color_write_count = color_count; @@ -362,7 +361,7 @@ static PipelineDynamicParameters BuildGraphicsDynamicParams(const HW::Context& return ret; } -static void SetDynamicParams(vk::CommandBuffer vk_buffer, +static void SetDynamicParams(const RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer, const PipelineDynamicParameters& dynamic_params) { KYTY_PROFILER_FUNCTION(); @@ -414,14 +413,12 @@ static void SetDynamicParams(vk::CommandBuffer vk_buffer, for (uint32_t i = 0; i < dynamic_params.color_write_count; i++) { enable[i] = (dynamic_params.color_write_enable[i] ? VK_TRUE : VK_FALSE); } - VulkanCmdSetColorWriteEnableEXT(g_render_ctx->GetGraphicCtx(), vk_buffer, - dynamic_params.color_write_count, enable); + VulkanCmdSetColorWriteEnableEXT(buffer, vk_buffer, dynamic_params.color_write_count, enable); } -static bool DrawHasValidVertexShader(const HW::Shader* sh_ctx) { - EXIT_IF(sh_ctx == nullptr); +static bool DrawHasValidVertexShader(const HW::Shader& sh_ctx) { - const auto& vs = sh_ctx->GetVs(); + const auto& vs = sh_ctx.GetVs(); return vs.gs_regs.chksum != 0 && ShaderAddressValid(vs.es_regs.data_addr); } @@ -432,16 +429,14 @@ static bool PixelShaderHasDepthOrCoverageSideEffects(const HW::ShaderRegisters& db.shader_execute_on_noop; } -static bool ShouldSkipGeShader(const HW::Context* ctx, const HW::UserConfig* ucfg, - const HW::Shader* sh_ctx) { - EXIT_IF(ctx == nullptr); - EXIT_IF(ucfg == nullptr); - EXIT_IF(sh_ctx == nullptr); - - const auto& sh_regs = ctx->GetShaderRegisters(); - const auto& ge_cntl = ucfg->GetGeControl(); - const auto& vertex_info = sh_ctx->GetVs(); - const auto stages = ctx->GetShaderStages(); +static bool ShouldSkipGeShader(const RenderCommandBuffer& buffer) { + const auto& ctx = buffer.GetRegisters(); + const auto& ucfg = buffer.GetUserConfig(); + const auto& sh_ctx = buffer.GetShaders(); + const auto& sh_regs = ctx.GetShaderRegisters(); + const auto& ge_cntl = ucfg.GetGeControl(); + const auto& vertex_info = sh_ctx.GetVs(); + const auto stages = ctx.GetShaderStages(); const auto is_known_gs_out_prim_type = [](uint32_t value) { switch (static_cast(value)) { @@ -511,11 +506,11 @@ struct DrawCallInfo { uint32_t first_instance = 0; }; -static bool DrawHasActivePixelShader(const HW::Context* ctx, const HW::Shader* sh_ctx, +static bool DrawHasActivePixelShader(const RenderCommandBuffer& buffer, const DrawRenderState& state, const DrawCallInfo& draw) { - EXIT_IF(ctx == nullptr); - EXIT_IF(sh_ctx == nullptr); EXIT_IF(draw.name == nullptr); + const auto& ctx = buffer.GetRegisters(); + const auto& sh_ctx = buffer.GetShaders(); const bool with_depth = (state.depth_info.format != vk::Format::eUndefined && state.depth_info.vulkan_buffer != nullptr); @@ -523,8 +518,8 @@ static bool DrawHasActivePixelShader(const HW::Context* ctx, const HW::Shader* s return true; } - const auto& sh_regs = ctx->GetShaderRegisters(); - const auto& ps = sh_ctx->GetPs(); + const auto& sh_regs = ctx.GetShaderRegisters(); + const auto& ps = sh_ctx.GetPs(); return ShaderAddressValid(ps.ps_regs.data_addr) && PixelShaderHasDepthOrCoverageSideEffects(sh_regs); } @@ -538,8 +533,9 @@ enum class CbColorMode : uint8_t { DccDecompress = 6, }; -static bool ConsumeMetadataColorOperation(const HW::Context& ctx) { - const auto mode = ctx.GetColorControl().mode; +static bool ConsumeMetadataColorOperation(const RenderCommandBuffer& buffer) { + const auto& ctx = buffer.GetRegisters(); + const auto mode = ctx.GetColorControl().mode; // These AGC CB modes run color-buffer metadata/decompression operations. The shader is a // dummy vehicle for the CB, and its exported color must not be applied as a normal draw. // Kyty currently stores host images as expanded Vulkan images and does not track CMASK/DCC @@ -570,176 +566,160 @@ static uint64_t VertexBufferDescriptorSize(const ShaderVertexInputBuffer& buffer : buffer.num_records); } -static void SetDrawDebugPhase(CommandBuffer* buffer, uint64_t submit_id, const DrawCallInfo& draw, - uint32_t phase) { - EXIT_IF(buffer == nullptr); +static void SetDrawDebugPhase(RenderCommandBuffer& buffer, uint64_t submit_id, + const DrawCallInfo& draw, uint32_t phase) { EXIT_IF(draw.name == nullptr); - buffer->SetDebugInfo(static_cast(draw.debug_op), submit_id, phase, draw.index_count, - draw.flags, draw.instance_count, draw.first_instance); + buffer.SetDebugInfo(static_cast(draw.debug_op), submit_id, phase, draw.index_count, + draw.flags, draw.instance_count, draw.first_instance); } -static bool GetDrawTopology(const HW::UserConfig* ucfg, bool auto_draw, bool use_ngg_rectlist_draw, - vk::PrimitiveTopology* topology) { - EXIT_IF(ucfg == nullptr); - EXIT_IF(topology == nullptr); +static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw, bool use_ngg_rectlist_draw, + vk::PrimitiveTopology& topology) { - *topology = vk::PrimitiveTopology::ePointList; + topology = vk::PrimitiveTopology::ePointList; - switch (static_cast(ucfg->GetPrimType())) { + switch (static_cast(ucfg.GetPrimType())) { case Prospero::PrimitiveType::kNone: return false; case Prospero::PrimitiveType::kPointList: - *topology = vk::PrimitiveTopology::ePointList; - break; - case Prospero::PrimitiveType::kLineList: - *topology = vk::PrimitiveTopology::eLineList; + topology = vk::PrimitiveTopology::ePointList; break; + case Prospero::PrimitiveType::kLineList: topology = vk::PrimitiveTopology::eLineList; break; case Prospero::PrimitiveType::kLineStrip: - *topology = vk::PrimitiveTopology::eLineStrip; + topology = vk::PrimitiveTopology::eLineStrip; break; case Prospero::PrimitiveType::kTriList: - *topology = vk::PrimitiveTopology::eTriangleList; + topology = vk::PrimitiveTopology::eTriangleList; break; case Prospero::PrimitiveType::kTriFan: - *topology = vk::PrimitiveTopology::eTriangleFan; + topology = vk::PrimitiveTopology::eTriangleFan; break; case Prospero::PrimitiveType::kTriStrip: - *topology = vk::PrimitiveTopology::eTriangleStrip; + topology = vk::PrimitiveTopology::eTriangleStrip; break; case Prospero::PrimitiveType::kRectList: - *topology = (auto_draw && use_ngg_rectlist_draw ? vk::PrimitiveTopology::eTriangleStrip - : vk::PrimitiveTopology::eTriangleList); + topology = (auto_draw && use_ngg_rectlist_draw ? vk::PrimitiveTopology::eTriangleStrip + : vk::PrimitiveTopology::eTriangleList); break; case Prospero::PrimitiveType::kRectListLegacy: if (!auto_draw) { - EXIT("unknown primitive type: %u\n", ucfg->GetPrimType()); + EXIT("unknown primitive type: %u\n", ucfg.GetPrimType()); } - *topology = vk::PrimitiveTopology::eTriangleStrip; + topology = vk::PrimitiveTopology::eTriangleStrip; break; case Prospero::PrimitiveType::kQuadListLegacy: - *topology = vk::PrimitiveTopology::eTriangleFan; + topology = vk::PrimitiveTopology::eTriangleFan; break; - default: EXIT("unknown primitive type: %u\n", ucfg->GetPrimType()); + default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType()); } return true; } -static bool PrepareDrawRenderState(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, - HW::UserConfig* ucfg, HW::Shader* sh_ctx, +static bool PrepareDrawRenderState(uint64_t submit_id, RenderCommandBuffer& buffer, const DrawCallInfo& draw, uint32_t render_target_slice_offset, bool skip_null_framebuffer, bool log_setup_phases, - DrawRenderState* state) { - EXIT_IF(buffer == nullptr); - EXIT_IF(ctx == nullptr); - EXIT_IF(ucfg == nullptr); - EXIT_IF(sh_ctx == nullptr); + DrawRenderState& state) { EXIT_IF(draw.name == nullptr); - EXIT_IF(state == nullptr); + auto& ctx = buffer.GetRegisters(); if (log_setup_phases) { LogDrawPhase(draw.name, "ResolveRenderDepthTarget"); } - ResolveRenderDepthTarget(submit_id, buffer, *ctx, &state->depth_info); + ResolveRenderDepthTarget(submit_id, buffer, state.depth_info); - if (ResolveColorTargets(submit_id, buffer, *ctx, render_target_slice_offset)) { - MarkRenderTargetGpuWritten(state->depth_info); + if (ResolveColorTargets(submit_id, buffer, render_target_slice_offset)) { + MarkRenderTargetGpuWritten(state.depth_info); return false; } - MarkRenderTargetGpuWritten(state->depth_info); + MarkRenderTargetGpuWritten(state.depth_info); if (log_setup_phases) { LogDrawPhase(draw.name, "ResolveRenderColorTarget"); } for (uint32_t slot = 0; slot < RENDER_COLOR_ATTACHMENTS_MAX; slot++) { - if (slot == 0 || (render_target_mask_slot(ctx->GetRenderTargetMask(), slot) != 0 && - ctx->GetRenderTarget(slot).base.addr != 0)) { - ResolveRenderColorTarget(submit_id, buffer, *ctx, - &state->color_info[state->color_count], + if (slot == 0 || (render_target_mask_slot(ctx.GetRenderTargetMask(), slot) != 0 && + ctx.GetRenderTarget(slot).base.addr != 0)) { + ResolveRenderColorTarget(submit_id, buffer, state.color_info[state.color_count], render_target_slice_offset, slot); - if (state->color_info[state->color_count].vulkan_buffer != nullptr) { - MarkRenderTargetGpuWritten(state->color_info[state->color_count]); - state->color_count++; + if (state.color_info[state.color_count].vulkan_buffer != nullptr) { + MarkRenderTargetGpuWritten(state.color_info[state.color_count]); + state.color_count++; } } } - const bool with_depth = (state->depth_info.format != vk::Format::eUndefined && - state->depth_info.vulkan_buffer != nullptr); - if (state->color_count == 0 && !with_depth) { - LogFramebufferSkip(draw.name, state->color_info[0], state->depth_info, ctx, ucfg, + const bool with_depth = (state.depth_info.format != vk::Format::eUndefined && + state.depth_info.vulkan_buffer != nullptr); + if (state.color_count == 0 && !with_depth) { + LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer, draw.index_count, draw.flags); return false; } - state->ps_active = DrawHasActivePixelShader(ctx, sh_ctx, *state, draw); + state.ps_active = DrawHasActivePixelShader(buffer, state, draw); if (log_setup_phases) { LogDrawPhase(draw.name, "CreateFramebuffer"); } - state->framebuffer = g_render_ctx->GetFramebufferCache()->CreateFramebuffer( - state->color_info, state->color_count, &state->depth_info); + state.framebuffer = GetRenderContext().GetFramebufferCache().CreateFramebuffer( + state.color_info, state.color_count, state.depth_info); - if (state->framebuffer == nullptr && skip_null_framebuffer) { - LogFramebufferSkip(draw.name, state->color_info[0], state->depth_info, ctx, ucfg, + if (state.framebuffer == nullptr && skip_null_framebuffer) { + LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer, draw.index_count, draw.flags); return false; } - EXIT_NOT_IMPLEMENTED(state->framebuffer == nullptr); - EXIT_NOT_IMPLEMENTED(state->framebuffer->render_pass == nullptr); + EXIT_NOT_IMPLEMENTED(state.framebuffer == nullptr); + EXIT_NOT_IMPLEMENTED(state.framebuffer->render_pass == nullptr); - state->vk_buffer = buffer->Handle(); + state.vk_buffer = buffer.Handle(); return true; } -static void RefreshShaders(HW::Context* ctx, HW::Shader* sh_ctx, const DrawCallInfo& draw, - bool log_phases, DrawRenderState* state) { - EXIT_IF(ctx == nullptr); - EXIT_IF(sh_ctx == nullptr); +static void RefreshShaders(RenderCommandBuffer& buffer, const DrawCallInfo& draw, bool log_phases, + DrawRenderState& state) { EXIT_IF(draw.name == nullptr); - EXIT_IF(state == nullptr); + auto& ctx = buffer.GetRegisters(); + auto& sh_ctx = buffer.GetShaders(); - const auto& vertex_shader_info = sh_ctx->GetVs(); - const auto& pixel_shader_info = sh_ctx->GetPs(); - const auto& shader_regs = ctx->GetShaderRegisters(); + const auto& vertex_shader_info = sh_ctx.GetVs(); + const auto& pixel_shader_info = sh_ctx.GetPs(); + const auto& shader_regs = ctx.GetShaderRegisters(); - state->vs_shader = {}; - state->ps_shader = {}; - state->ps_input_info = {}; + state.vs_shader = {}; + state.ps_shader = {}; + state.ps_input_info = {}; std::array target_export_mapping {}; - for (uint32_t i = 0; i < state->color_count; i++) { - target_export_mapping[state->color_info[i].target_slot] = - state->color_info[i].export_mapping; + for (uint32_t i = 0; i < state.color_count; i++) { + target_export_mapping[state.color_info[i].target_slot] = state.color_info[i].export_mapping; } - EXIT_IF(g_render_ctx == nullptr || g_render_ctx->GetGraphicCtx() == nullptr); - const auto lane_mask_mode = SelectGraphicsLaneMaskMode(*g_render_ctx->GetGraphicCtx(), 64u); + const auto lane_mask_mode = SelectGraphicsLaneMaskMode(64u); if (log_phases) { LogDrawPhase(draw.name, "ShaderCompileInfoVS"); } - if (!ShaderCompileInfoVS(&vertex_shader_info, &shader_regs, lane_mask_mode, - &state->vs_input_info, &state->vs_shader)) { + if (!ShaderCompileInfoVS(vertex_shader_info, shader_regs, lane_mask_mode, state.vs_input_info, + state.vs_shader)) { EXIT("ShaderCompileInfoVS failed for draw %s\n", draw.name); } - if (!state->ps_active) { + if (!state.ps_active) { return; } if (log_phases) { LogDrawPhase(draw.name, "ShaderCompileInfoPS"); } - if (!ShaderCompileInfoPS(&pixel_shader_info, &shader_regs, lane_mask_mode, - &state->vs_input_info, target_export_mapping, &state->ps_input_info, - &state->ps_shader)) { + if (!ShaderCompileInfoPS(pixel_shader_info, shader_regs, lane_mask_mode, state.vs_input_info, + target_export_mapping, state.ps_input_info, state.ps_shader)) { EXIT("ShaderCompileInfoPS failed for draw %s\n", draw.name); } } -static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer, +static void BindDrawVertexBuffers(uint64_t submit_id, RenderCommandBuffer& buffer, const DrawCallInfo& draw, vk::CommandBuffer vk_buffer, const ShaderVertexInputInfo& vs_input_info) { - EXIT_IF(buffer == nullptr); EXIT_IF(draw.name == nullptr); (void)submit_id; @@ -752,13 +732,11 @@ static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer, vk::DeviceSize offset = 0; if (size == 0) { - vertices = g_render_ctx->GetBufferCache()->ObtainNullBuffer( - buffer, g_render_ctx->GetGraphicCtx()); + vertices = &GetRenderContext().GetBufferCache().ObtainNullBuffer(buffer); } else { - auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer( - buffer, g_render_ctx->GetGraphicCtx(), addr, size); - vertices = binding.first; - offset = binding.second; + auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(buffer, addr, size); + vertices = &binding.buffer; + offset = binding.offset; } EXIT_NOT_IMPLEMENTED(vertices == nullptr); @@ -766,7 +744,7 @@ static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer, } } -static void BindDrawIndexBuffer(CommandBuffer* buffer, vk::CommandBuffer vk_buffer, +static void BindDrawIndexBuffer(RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer, const DrawIndexBufferSource& source) { if (!source.enabled) { return; @@ -777,27 +755,24 @@ static void BindDrawIndexBuffer(CommandBuffer* buffer, vk::CommandBuffer vk_buff vk::DeviceSize index_offset = 0; if (source.host_data != nullptr) { vk::DeviceSize range = 0; - if (!g_render_ctx->GetBufferCache()->UploadHostData(buffer, g_render_ctx->GetGraphicCtx(), - source.host_data, source.size, 16, - &index_buffer, &index_offset, &range)) { + if (!GetRenderContext().GetBufferCache().UploadHostData( + buffer, source.host_data, source.size, 16, index_buffer, index_offset, range)) { EXIT("failed to upload host index buffer\n"); } } else { - auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer( - buffer, g_render_ctx->GetGraphicCtx(), source.address, source.size); - index_buffer = binding.first; - index_offset = binding.second; + auto binding = + GetRenderContext().GetBufferCache().ObtainBuffer(buffer, source.address, source.size); + index_buffer = &binding.buffer; + index_offset = binding.offset; } EXIT_IF(index_buffer == nullptr); vk_buffer.bindIndexBuffer(index_buffer->buffer, index_offset, source.type); } -static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const DrawCallInfo& draw, +static void LogDrawStateIfNeeded(const RenderCommandBuffer& buffer, const DrawCallInfo& draw, const DrawRenderState& state, bool always_log, bool force_legacy_rect_log, uint32_t index_type_and_size, const void* index_addr) { - EXIT_IF(ctx == nullptr); - EXIT_IF(ucfg == nullptr); EXIT_IF(draw.name == nullptr); if (!graphics_debug_dump_enabled()) { @@ -809,7 +784,7 @@ static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const D } if (state.ps_active) { - LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, ctx, ucfg, + LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, buffer, state.ps_input_info, draw.index_count, draw.flags); } LogDrawInputState(state.color_info[0], state.vs_input_info, index_type_and_size, @@ -831,13 +806,12 @@ static bool IsHostExpandedRectListDrawSupported(const ShaderVertexInputInfo& vs_ return draw.index_count == 3 || draw.index_count == emit.draw_vertex_count; } -static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_buffer, +static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_buffer, const ShaderVertexInputInfo& vs_input_info, const DrawCallInfo& draw, const DrawEmitInfo& emit) { - EXIT_IF(ucfg == nullptr); EXIT_IF(draw.name == nullptr); - switch (static_cast(ucfg->GetPrimType())) { + switch (static_cast(ucfg.GetPrimType())) { case Prospero::PrimitiveType::kPointList: case Prospero::PrimitiveType::kLineList: case Prospero::PrimitiveType::kLineStrip: @@ -865,7 +839,7 @@ static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_ break; case Prospero::PrimitiveType::kRectListLegacy: if (emit.indexed) { - EXIT("unknown primitive type: %u\n", ucfg->GetPrimType()); + EXIT("unknown primitive type: %u\n", ucfg.GetPrimType()); } // Sarah EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0)); @@ -883,67 +857,63 @@ static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_ } } break; - default: EXIT("unknown primitive type: %u\n", ucfg->GetPrimType()); + default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType()); } } -static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, - HW::UserConfig* ucfg, HW::Shader* sh_ctx, const DrawCallInfo& draw, - DrawRenderState* state, vk::PrimitiveTopology topology, - const DrawEmitInfo& emit, const DrawIndexBufferSource& index_source, - bool log_pipeline_phase, bool set_bind_debug, bool set_auto_debug) { - EXIT_IF(buffer == nullptr); - EXIT_IF(ctx == nullptr); - EXIT_IF(ucfg == nullptr); - EXIT_IF(sh_ctx == nullptr); +static void ExecutePreparedDraw(uint64_t submit_id, RenderCommandBuffer& buffer, + const DrawCallInfo& draw, DrawRenderState& state, + vk::PrimitiveTopology topology, const DrawEmitInfo& emit, + const DrawIndexBufferSource& index_source, bool log_pipeline_phase, + bool set_bind_debug, bool set_auto_debug) { EXIT_IF(draw.name == nullptr); - EXIT_IF(state == nullptr); + auto& ucfg = buffer.GetUserConfig(); for (;;) { - const auto recording_generation = buffer->GetRecordingGeneration(); + const auto recording_generation = buffer.GetRecordingGeneration(); if (log_pipeline_phase) { LogDrawPhase(draw.name, "CreatePipeline"); } - auto* pipeline = g_render_ctx->GetPipelineCache()->CreateGraphicsPipeline( - state->framebuffer, state->color_info, state->color_count, &state->depth_info, - &state->vs_input_info, ctx, sh_ctx, &state->ps_input_info, topology, state->ps_active, - state->vs_shader, state->ps_shader); + auto& pipeline = GetRenderContext().GetPipelineCache().CreateGraphicsPipeline( + *state.framebuffer, state.color_info, state.color_count, state.depth_info, + state.vs_input_info, buffer, &state.ps_input_info, topology, state.ps_active, + state.vs_shader, state.ps_shader); if (set_bind_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x100u); } - state->vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline->pipeline); - const auto dynamic_params = BuildGraphicsDynamicParams( - *ctx, state->color_info, state->color_count, state->depth_info); - SetDynamicParams(state->vk_buffer, dynamic_params); + state.vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.pipeline); + const auto dynamic_params = BuildGraphicsDynamicParams(buffer, state.color_info, + state.color_count, state.depth_info); + SetDynamicParams(buffer, state.vk_buffer, dynamic_params); // EXIT_NOT_IMPLEMENTED(vs_input_info.buffers_num > 1); - BindDrawVertexBuffers(submit_id, buffer, draw, state->vk_buffer, state->vs_input_info); + BindDrawVertexBuffers(submit_id, buffer, draw, state.vk_buffer, state.vs_input_info); LogDrawPhase(draw.name, "BindDescriptorsVS"); if (set_auto_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x200u); } BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, - pipeline->pipeline_layout, state->vs_input_info.stage, + pipeline.pipeline_layout, state.vs_input_info.stage, vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex); - if (state->ps_active) { + if (state.ps_active) { LogDrawPhase(draw.name, "BindDescriptorsPS"); if (set_auto_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x300u); } BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, - pipeline->pipeline_layout, state->ps_input_info.stage, + pipeline.pipeline_layout, state.ps_input_info.stage, vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel); } - if (buffer->GetRecordingGeneration() != recording_generation) { + if (buffer.GetRecordingGeneration() != recording_generation) { continue; } // Index data may use this command buffer's host stream. Resolve it only after the other // fault-capable bindings, and rebuild it whenever a fault reset changes the generation. - BindDrawIndexBuffer(buffer, state->vk_buffer, index_source); - if (buffer->GetRecordingGeneration() != recording_generation) { + BindDrawIndexBuffer(buffer, state.vk_buffer, index_source); + if (buffer.GetRecordingGeneration() != recording_generation) { continue; } @@ -951,29 +921,29 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C if (set_auto_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x400u); } - buffer->BeginRenderPass(state->framebuffer, state->color_info, state->color_count, - &state->depth_info); + buffer.BeginRenderPass(*state.framebuffer, state.color_info, state.color_count, + state.depth_info); if (set_auto_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x500u); } - EmitDrawPrimitives(ucfg, state->vk_buffer, state->vs_input_info, draw, emit); + EmitDrawPrimitives(ucfg, state.vk_buffer, state.vs_input_info, draw, emit); if (set_auto_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x600u); } - buffer->EndRenderPass(); + buffer.EndRenderPass(); vk::PipelineStageFlags shader_write_stages = {}; - if (HasShaderBufferWrites(state->vs_input_info.stage)) { + if (HasShaderBufferWrites(state.vs_input_info.stage)) { shader_write_stages |= vk::PipelineStageFlagBits::eVertexShader; } - if (state->ps_active) { - if (HasShaderBufferWrites(state->ps_input_info.stage)) { + if (state.ps_active) { + if (HasShaderBufferWrites(state.ps_input_info.stage)) { shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader; } } if (shader_write_stages) { - ShaderWriteBarrier(state->vk_buffer, shader_write_stages); + ShaderWriteBarrier(state.vk_buffer, shader_write_stages); } LogDrawPhase(draw.name, "EndRenderPass"); if (set_auto_debug) { @@ -983,30 +953,27 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C } } -void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, - HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_type_and_size, +void RenderDrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_type_and_size, uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type, uint32_t instance_count, uint32_t render_target_slice_offset, int32_t vertex_offset_add, uint32_t first_instance) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr); - EXIT_IF(ucfg == nullptr); - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); + EXIT_IF(buffer.IsInvalid()); + auto& ucfg = buffer.GetUserConfig(); + auto& sh_ctx = buffer.GetShaders(); - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::DrawIndex), submit_id, - index_count, flags, type, instance_count, - reinterpret_cast(index_addr)); + buffer.SetDebugInfo(static_cast(CommandBufferDebugOp::DrawIndex), submit_id, + index_count, flags, type, instance_count, + reinterpret_cast(index_addr)); - Common::LockGuard lock(g_render_ctx->GetMutex()); + Common::LockGuard lock(GetRenderContext().GetMutex()); if (index_count == 0) { return; } - if (ConsumeMetadataColorOperation(*ctx)) { + if (ConsumeMetadataColorOperation(buffer)) { return; } @@ -1014,14 +981,14 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx return; } - if (ShouldSkipGeShader(ctx, ucfg, sh_ctx)) { + if (ShouldSkipGeShader(buffer)) { return; } if (graphics_debug_dump_enabled()) { - sh_print("GraphicsRenderDrawIndex():Shader:", *sh_ctx); - uc_print("GraphicsRenderDrawIndex():UserConfig:", *ucfg); - hw_print(*ctx); + sh_print("GraphicsRenderDrawIndex():Shader:", sh_ctx); + uc_print("GraphicsRenderDrawIndex():UserConfig:", ucfg); + hw_print(buffer); LOGF("GraphicsRenderDrawIndex():Parameters:\n" "\t index_type_and_size = 0x%08" PRIx32 "\n" @@ -1037,14 +1004,14 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx instance_count, render_target_slice_offset, static_cast(vertex_offset_add), first_instance); } - sh_check(*sh_ctx); + sh_check(sh_ctx); - uc_check(*ucfg); + uc_check(ucfg); - hw_check(*ctx); + hw_check(buffer); vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList; - if (!GetDrawTopology(ucfg, false, false, &topology)) { + if (!GetDrawTopology(ucfg, false, false, topology)) { return; } @@ -1099,47 +1066,46 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx index_source.type = index_type; DrawRenderState state {}; - if (!PrepareDrawRenderState(submit_id, buffer, ctx, ucfg, sh_ctx, draw, - render_target_slice_offset, false, true, &state)) { + if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, false, true, + state)) { return; } - RefreshShaders(ctx, sh_ctx, draw, true, &state); + RefreshShaders(buffer, draw, true, state); - LogDrawStateIfNeeded(ctx, ucfg, draw, state, true, false, index_type_and_size, index_addr); + LogDrawStateIfNeeded(buffer, draw, state, true, false, index_type_and_size, index_addr); const auto vertex_offset = - ResolveVertexOffset(ucfg->GetIndexOffset(), state.vs_input_info) + vertex_offset_add; + ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) + vertex_offset_add; DrawEmitInfo emit {}; emit.indexed = true; emit.vertex_offset = vertex_offset; - ExecutePreparedDraw(submit_id, buffer, ctx, ucfg, sh_ctx, draw, &state, topology, emit, - index_source, true, true, false); + ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, true, true, + false); } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, - HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_count, +void RenderDrawIndexAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count, uint32_t flags, uint32_t render_target_slice_offset, uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr || ucfg == nullptr); - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(buffer == nullptr || buffer->IsInvalid()); + EXIT_IF(buffer.IsInvalid()); + auto& ucfg = buffer.GetUserConfig(); + auto& sh_ctx = buffer.GetShaders(); - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::DrawIndexAuto), submit_id, - index_count, flags, first_vertex, instance_count, first_instance); + buffer.SetDebugInfo(static_cast(CommandBufferDebugOp::DrawIndexAuto), submit_id, + index_count, flags, first_vertex, instance_count, first_instance); - Common::LockGuard lock(g_render_ctx->GetMutex()); + Common::LockGuard lock(GetRenderContext().GetMutex()); if (index_count == 0) { return; } - if (ConsumeMetadataColorOperation(*ctx)) { + if (ConsumeMetadataColorOperation(buffer)) { return; } @@ -1147,14 +1113,14 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* return; } - if (ShouldSkipGeShader(ctx, ucfg, sh_ctx)) { + if (ShouldSkipGeShader(buffer)) { return; } if (graphics_debug_dump_enabled()) { - sh_print("GraphicsRenderDrawIndexAuto():Shader:", *sh_ctx); - uc_print("GraphicsRenderDrawIndexAuto():UserConfig:", *ucfg); - hw_print(*ctx); + sh_print("GraphicsRenderDrawIndexAuto():Shader:", sh_ctx); + uc_print("GraphicsRenderDrawIndexAuto():UserConfig:", ucfg); + hw_print(buffer); LOGF("GraphicsRenderDrawIndexAuto():Parameters:\n" "\t index_count = 0x%08" PRIx32 "\n" @@ -1166,11 +1132,11 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* index_count, flags, render_target_slice_offset, instance_count, first_vertex, first_instance); } - sh_check(*sh_ctx); + sh_check(sh_ctx); - uc_check(*ucfg); + uc_check(ucfg); - hw_check(*ctx); + hw_check(buffer); EXIT_NOT_IMPLEMENTED(flags != 0); if (instance_count == 0) { @@ -1182,50 +1148,50 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* instance_count, first_instance}; DrawRenderState state {}; - if (!PrepareDrawRenderState(submit_id, buffer, ctx, ucfg, sh_ctx, draw, - render_target_slice_offset, true, false, &state)) { + if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, true, false, + state)) { return; } vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList; const bool use_ngg_rectlist_draw = Config::NggRectlistDrawEnabled(); - if (!GetDrawTopology(ucfg, true, use_ngg_rectlist_draw, &topology)) { + if (!GetDrawTopology(ucfg, true, use_ngg_rectlist_draw, topology)) { return; } const bool draw_prim7_as_ngg = (use_ngg_rectlist_draw && - ucfg->GetPrimType() == Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectList)); + ucfg.GetPrimType() == Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectList)); - RefreshShaders(ctx, sh_ctx, draw, false, &state); + RefreshShaders(buffer, draw, false, state); if (draw_prim7_as_ngg && state.vs_input_info.buffers_num == 0 && state.vs_input_info.param_export_mask == 0 && state.ps_input_info.input_num != 0) { if (graphics_debug_dump_enabled()) { LOGF("DrawIndexAuto: skipping rect-list draw with no VS param exports and PS inputs: " "ps_inputs=%u ps=0x%016" PRIx64 " es=0x%016" PRIx64 " gs=0x%016" PRIx64 "\n", - state.ps_input_info.input_num, sh_ctx->GetPs().ps_regs.chksum, - sh_ctx->GetVs().es_regs.data_addr, sh_ctx->GetVs().gs_regs.data_addr); + state.ps_input_info.input_num, sh_ctx.GetPs().ps_regs.chksum, + sh_ctx.GetVs().es_regs.data_addr, sh_ctx.GetVs().gs_regs.data_addr); } return; } - LogDrawStateIfNeeded(ctx, ucfg, draw, state, false, - ucfg->GetPrimType() == + LogDrawStateIfNeeded(buffer, draw, state, false, + ucfg.GetPrimType() == Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectListLegacy), 0, nullptr); const uint32_t draw_vertex_count = (draw_prim7_as_ngg ? 4u : index_count); - const auto vertex_offset = ResolveVertexOffset(ucfg->GetIndexOffset(), state.vs_input_info) + - static_cast(first_vertex); - DrawEmitInfo emit {}; + const auto vertex_offset = ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) + + static_cast(first_vertex); + DrawEmitInfo emit {}; emit.draw_prim7_as_ngg = draw_prim7_as_ngg; emit.draw_vertex_count = draw_vertex_count; emit.first_vertex = static_cast(vertex_offset); DrawIndexBufferSource index_source {}; - ExecutePreparedDraw(submit_id, buffer, ctx, ucfg, sh_ctx, draw, &state, topology, emit, - index_source, false, false, true); + ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, false, false, + true); } bool IsSameColorResolveSubresource(const RenderColorInfo& src, const RenderColorInfo& dst) { @@ -1235,8 +1201,7 @@ bool IsSameColorResolveSubresource(const RenderColorInfo& src, const RenderColor ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColorInfo& dst, uint32_t width, uint32_t height) { - ImageImageCopy region {}; - region.src_image = src.vulkan_buffer; + ImageImageCopy region {*src.vulkan_buffer}; region.src_level = src.base_mip_level; region.dst_level = dst.base_mip_level; region.width = width; @@ -1246,8 +1211,9 @@ ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColo return region; } -static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, +static bool ResolveColorTargets(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t render_target_slice_offset) { + const auto& hw = buffer.GetRegisters(); if (hw.GetColorControl().mode != 3) { return false; } @@ -1260,9 +1226,8 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const RenderColorInfo src {}; RenderColorInfo dst {}; - ResolveRenderColorTarget(submit_id, buffer, hw, &src, render_target_slice_offset, 0, true, - true); - ResolveRenderColorTarget(submit_id, buffer, hw, &dst, render_target_slice_offset, 1, true); + ResolveRenderColorTarget(submit_id, buffer, src, render_target_slice_offset, 0, true, true); + ResolveRenderColorTarget(submit_id, buffer, dst, render_target_slice_offset, 1, true); if (src.vulkan_buffer == nullptr || dst.vulkan_buffer == nullptr || src.type == RenderColorType::NoColorOutput || dst.type == RenderColorType::NoColorOutput) { return false; @@ -1280,7 +1245,7 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const const std::array regions {MakeColorResolveCopy(src, dst, width, height)}; MarkRenderTargetGpuWritten(dst); - Transfer::CopyImage(buffer, regions, dst.vulkan_buffer, dst.vulkan_buffer->layout); + Transfer::CopyImage(buffer, regions, *dst.vulkan_buffer, dst.vulkan_buffer->layout); return true; } diff --git a/src/graphics/host_gpu/renderer/renderTargetBarriers.cpp b/src/graphics/host_gpu/renderer/renderTargetBarriers.cpp index 3ceb86b09..2e39edf32 100644 --- a/src/graphics/host_gpu/renderer/renderTargetBarriers.cpp +++ b/src/graphics/host_gpu/renderer/renderTargetBarriers.cpp @@ -28,13 +28,12 @@ namespace Libs::Graphics { -void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) { - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); +void GraphicsRenderMemoryBarrier(CommandBuffer& buffer) { + EXIT_IF(buffer.IsInvalid()); - Common::LockGuard lock(g_render_ctx->GetMutex()); + Common::LockGuard lock(GetRenderContext().GetMutex()); - auto vk_buffer = buffer->Handle(); + auto vk_buffer = buffer.Handle(); VulkanMemoryBarrier mem_barrier {}; mem_barrier.sType = vk::StructureType::eMemoryBarrier; @@ -47,8 +46,7 @@ void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) { &mem_barrier, 0, nullptr, 0, nullptr); } -void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image) { - EXIT_IF(image == nullptr); +void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) { vk::ImageMemoryBarrier image_memory_barrier {}; image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; @@ -57,16 +55,16 @@ void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* imag vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eTransferWrite | vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryRead; image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; - image_memory_barrier.oldLayout = image->layout; + image_memory_barrier.oldLayout = image.layout; image_memory_barrier.newLayout = RENDER_COLOR_IMAGE_LAYOUT; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.image = image->image; + image_memory_barrier.image = image.image; image_memory_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = image->layers; + image_memory_barrier.subresourceRange.layerCount = image.layers; vk_buffer.pipelineBarrier( vk::PipelineStageFlagBits::eColorAttachmentOutput | @@ -76,21 +74,19 @@ void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* imag vk::PipelineStageFlagBits::eComputeShader, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); - image->layout = image_memory_barrier.newLayout; + image.layout = image_memory_barrier.newLayout; } -void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image, +void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image, vk::ImageLayout new_layout) { - EXIT_IF(image == nullptr); - - if (image->layout != new_layout) { - if (image->type == VulkanImageType::VideoOut && - image->layout == vk::ImageLayout::eTransferDstOptimal) { + if (image.layout != new_layout) { + if (image.type == VulkanImageType::VideoOut && + image.layout == vk::ImageLayout::eTransferDstOptimal) { static std::atomic log_count {0}; if (log_count.fetch_add(1, std::memory_order_relaxed) < 128) { LOGF("GraphicsRenderColorImageBarrier: image=%p type=%d layout=%s -> %s\n", - VulkanHandleToPointer(image->image), static_cast(image->type), - VulkanToString(image->layout).c_str(), VulkanToString(new_layout).c_str()); + VulkanHandleToPointer(image.image), static_cast(image.type), + VulkanToString(image.layout).c_str(), VulkanToString(new_layout).c_str()); } } vk::ImageMemoryBarrier image_memory_barrier {}; @@ -100,16 +96,16 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead; image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead; - image_memory_barrier.oldLayout = image->layout; + image_memory_barrier.oldLayout = image.layout; image_memory_barrier.newLayout = new_layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.image = image->image; + image_memory_barrier.image = image.image; image_memory_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = image->layers; + image_memory_barrier.subresourceRange.layerCount = image.layers; const auto stages = static_cast( vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | @@ -117,75 +113,72 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); - image->layout = image_memory_barrier.newLayout; + image.layout = image_memory_barrier.newLayout; } } -void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image, +void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image, vk::ImageLayout new_layout) { - EXIT_IF(image == nullptr); - EXIT_IF(image->type != VulkanImageType::DepthStencil); + EXIT_IF(image.type != VulkanImageType::DepthStencil); if (new_layout == vk::ImageLayout::eUndefined || new_layout == vk::ImageLayout::ePreinitialized) { EXIT("invalid destination depth/stencil image layout: %s\n", VulkanToString(new_layout).c_str()); } - if (image->layout == new_layout) { + if (image.layout == new_layout) { return; } vk::ImageMemoryBarrier barrier {}; barrier.sType = vk::StructureType::eImageMemoryBarrier; barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; - barrier.oldLayout = image->layout; + barrier.oldLayout = image.layout; barrier.newLayout = new_layout; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image->image; - barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image->format), 0, - VK_REMAINING_MIP_LEVELS, 0, image->layers}; + barrier.image = image.image; + barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image.format), 0, + VK_REMAINING_MIP_LEVELS, 0, image.layers}; const auto stages = static_cast( vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer); vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &barrier); - image->layout = new_layout; + image.layout = new_layout; } -void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image) { - EXIT_IF(image == nullptr); +void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) { + EXIT_IF(image.type != VulkanImageType::DepthStencil); - EXIT_IF(image->type != VulkanImageType::DepthStencil); - - auto* depth = static_cast(image); - if (depth->compressed) { + auto& depth = static_cast(image); + if (depth.compressed) { static std::atomic log_count {0}; if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { LOGF( "DepthTexture: decompressing depth target for shader read format=%s extent=%ux%u\n", - VulkanToString(depth->format).c_str(), depth->extent.width, depth->extent.height); + VulkanToString(depth.format).c_str(), depth.extent.width, depth.extent.height); } - depth->compressed = false; + depth.compressed = false; } - if (image->layout != vk::ImageLayout::eDepthStencilReadOnlyOptimal) { + if (image.layout != vk::ImageLayout::eDepthStencilReadOnlyOptimal) { vk::ImageMemoryBarrier image_memory_barrier {}; image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; image_memory_barrier.pNext = nullptr; image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; - image_memory_barrier.oldLayout = image->layout; + image_memory_barrier.oldLayout = image.layout; image_memory_barrier.newLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.image = image->image; + image_memory_barrier.image = image.image; image_memory_barrier.subresourceRange.aspectMask = - ImageViewOps::DepthAspectMask(image->format); + ImageViewOps::DepthAspectMask(image.format); image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = image->layers; + image_memory_barrier.subresourceRange.layerCount = image.layers; vk_buffer.pipelineBarrier( vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | @@ -194,37 +187,35 @@ void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* vk::PipelineStageFlagBits::eComputeShader, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); - image->layout = image_memory_barrier.newLayout; + image.layout = image_memory_barrier.newLayout; } } -void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size) { - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); +void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) { + EXIT_IF(buffer.IsInvalid()); - Common::LockGuard lock(g_render_ctx->GetMutex()); + Common::LockGuard lock(GetRenderContext().GetMutex()); - auto vk_buffer = buffer->Handle(); + auto vk_buffer = buffer.Handle(); - auto* native = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(buffer, vaddr, size); + auto* native = GetRenderContext().GetTextureCache().FindRenderTargetByRange(buffer, vaddr, size); if (native == nullptr) { EXIT("render-target barrier range has no cached image\n"); } - GraphicsRenderTextureBarrier(vk_buffer, native); + GraphicsRenderTextureBarrier(vk_buffer, *native); } -void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size) { - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); +void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) { + EXIT_IF(buffer.IsInvalid()); - Common::LockGuard lock(g_render_ctx->GetMutex()); + Common::LockGuard lock(GetRenderContext().GetMutex()); - auto vk_buffer = buffer->Handle(); - auto* native = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(buffer, vaddr, size); + auto vk_buffer = buffer.Handle(); + auto* native = GetRenderContext().GetTextureCache().FindDepthTargetByRange(buffer, vaddr, size); if (native == nullptr) { EXIT("depth-target barrier range has no cached image\n"); } - GraphicsRenderDepthStencilBarrier(vk_buffer, native); + GraphicsRenderDepthStencilBarrier(vk_buffer, *native); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/renderTargetBarriers.h b/src/graphics/host_gpu/renderer/renderTargetBarriers.h index c24a5189b..3e4056f79 100644 --- a/src/graphics/host_gpu/renderer/renderTargetBarriers.h +++ b/src/graphics/host_gpu/renderer/renderTargetBarriers.h @@ -7,12 +7,12 @@ namespace Libs::Graphics { struct VulkanImage; -void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image); -void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image, +void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image); +void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image, vk::ImageLayout new_layout); -void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image, +void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image, vk::ImageLayout new_layout); -void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image); +void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/samplerCache.cpp b/src/graphics/host_gpu/renderer/samplerCache.cpp index f1eb50cb9..54cf4890a 100644 --- a/src/graphics/host_gpu/renderer/samplerCache.cpp +++ b/src/graphics/host_gpu/renderer/samplerCache.cpp @@ -143,8 +143,7 @@ vk::Sampler SamplerCache::GetSampler(const ShaderSamplerResource& r) { } vk::Sampler vk_sampler = nullptr; - const auto result = - g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler); + const auto result = m_graphics.device.createSampler(&sampler_info, nullptr, &vk_sampler); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || vk_sampler == nullptr); m_samplers.emplace(key, vk_sampler); diff --git a/src/graphics/host_gpu/renderer/samplerCache.h b/src/graphics/host_gpu/renderer/samplerCache.h index a06b6793e..d7ad4d83a 100644 --- a/src/graphics/host_gpu/renderer/samplerCache.h +++ b/src/graphics/host_gpu/renderer/samplerCache.h @@ -14,9 +14,13 @@ namespace Libs::Graphics { +struct GraphicContext; + class SamplerCache { public: - SamplerCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } + explicit SamplerCache(GraphicContext& graphics): m_graphics(graphics) { + EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); + } ~SamplerCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(SamplerCache); @@ -37,6 +41,7 @@ private: } }; + GraphicContext& m_graphics; Common::Mutex m_mutex; std::unordered_map m_samplers; }; diff --git a/src/graphics/host_gpu/renderer/shaderSubgroup.cpp b/src/graphics/host_gpu/renderer/shaderSubgroup.cpp index d4d6ee4b6..832ca57ec 100644 --- a/src/graphics/host_gpu/renderer/shaderSubgroup.cpp +++ b/src/graphics/host_gpu/renderer/shaderSubgroup.cpp @@ -4,8 +4,13 @@ namespace Libs::Graphics { -ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context, - uint32_t guest_wave_size) { +ShaderSubgroupCapabilities::ShaderSubgroupCapabilities(const GraphicContext& graphics) + : subgroup_size(graphics.subgroup_size), min_subgroup_size(graphics.min_subgroup_size), + max_subgroup_size(graphics.max_subgroup_size), + required_subgroup_size_stages(graphics.required_subgroup_size_stages), + subgroup_size_control_enabled(graphics.subgroup_size_control_enabled) {} + +ShaderLaneMaskMode SelectGraphicsLaneMaskMode(uint32_t guest_wave_size) { // A 64-wide guest wave can't assume the host GPU's lane layout matches // GCN's. AMD RDNA also reports a 64-wide subgroup but uses a different // lane/pixel layout, which corrupted rendering under "native wave" mode. @@ -16,16 +21,16 @@ ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context, return ShaderLaneMaskMode::NativeWave; } -ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& context, - vk::ShaderStageFlagBits stage, +ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabilities& capabilities, + vk::ShaderStageFlagBits stage, const ShaderRecompiler::IR::Program& program) { const auto guest_wave_size = program.wave_size; if (guest_wave_size != 32u && guest_wave_size != 64u) { return {}; } if (stage != vk::ShaderStageFlagBits::eCompute) { - const auto expected = SelectGraphicsLaneMaskMode(context, guest_wave_size); - if (program.lane_mask_mode != expected || (context.subgroup_size != guest_wave_size && + const auto expected = SelectGraphicsLaneMaskMode(guest_wave_size); + if (program.lane_mask_mode != expected || (capabilities.subgroup_size != guest_wave_size && expected != ShaderLaneMaskMode::PerInvocation)) { return {}; } @@ -37,12 +42,13 @@ ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& if (program.lane_mask_mode != ShaderLaneMaskMode::NativeWave) { return {}; } - if (context.subgroup_size == guest_wave_size) { + if (capabilities.subgroup_size == guest_wave_size) { return {ShaderSubgroupMode::Natural, 0}; } - if (context.subgroup_size_control_enabled && (context.required_subgroup_size_stages & stage) && - guest_wave_size >= context.min_subgroup_size && - guest_wave_size <= context.max_subgroup_size) { + if (capabilities.subgroup_size_control_enabled && + (capabilities.required_subgroup_size_stages & stage) && + guest_wave_size >= capabilities.min_subgroup_size && + guest_wave_size <= capabilities.max_subgroup_size) { return {ShaderSubgroupMode::Controlled, guest_wave_size}; } if (!ShaderRecompiler::Spirv::ProgramRequiresExactSubgroupSize(program)) { diff --git a/src/graphics/host_gpu/renderer/shaderSubgroup.h b/src/graphics/host_gpu/renderer/shaderSubgroup.h index 7e0ace565..f60f295e1 100644 --- a/src/graphics/host_gpu/renderer/shaderSubgroup.h +++ b/src/graphics/host_gpu/renderer/shaderSubgroup.h @@ -19,11 +19,20 @@ struct ShaderSubgroupConfiguration { uint32_t required_size = 0; }; -ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context, - uint32_t guest_wave_size); +struct ShaderSubgroupCapabilities { + explicit ShaderSubgroupCapabilities(const GraphicContext& graphics); -ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& context, - vk::ShaderStageFlagBits stage, + uint32_t subgroup_size = 0; + uint32_t min_subgroup_size = 0; + uint32_t max_subgroup_size = 0; + vk::ShaderStageFlags required_subgroup_size_stages; + bool subgroup_size_control_enabled = false; +}; + +ShaderLaneMaskMode SelectGraphicsLaneMaskMode(uint32_t guest_wave_size); + +ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabilities& capabilities, + vk::ShaderStageFlagBits stage, const ShaderRecompiler::IR::Program& program); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/shaders.cpp b/src/graphics/host_gpu/renderer/shaders.cpp index ad5ee4e95..880bebad8 100644 --- a/src/graphics/host_gpu/renderer/shaders.cpp +++ b/src/graphics/host_gpu/renderer/shaders.cpp @@ -25,62 +25,59 @@ namespace Libs::Graphics { // IDK: maybe we can remove it? constexpr uint32_t kTemporaryPs5BufferFormat121 = 121u; -static bool NarrowInputFormat(vk::Format* format, uint32_t* size, uint32_t used_components) { - EXIT_IF(format == nullptr); - EXIT_IF(size == nullptr); - - if (used_components == 0 || used_components >= *size) { +static bool NarrowInputFormat(vk::Format& format, uint32_t& size, uint32_t used_components) { + if (used_components == 0 || used_components >= size) { return false; } - switch (*format) { + switch (format) { case vk::Format::eR32G32B32A32Sfloat: switch (used_components) { - case 1: *format = vk::Format::eR32Sfloat; break; - case 2: *format = vk::Format::eR32G32Sfloat; break; - case 3: *format = vk::Format::eR32G32B32Sfloat; break; + case 1: format = vk::Format::eR32Sfloat; break; + case 2: format = vk::Format::eR32G32Sfloat; break; + case 3: format = vk::Format::eR32G32B32Sfloat; break; default: return false; } - *size = used_components; + size = used_components; return true; case vk::Format::eR32G32B32Sfloat: switch (used_components) { - case 1: *format = vk::Format::eR32Sfloat; break; - case 2: *format = vk::Format::eR32G32Sfloat; break; + case 1: format = vk::Format::eR32Sfloat; break; + case 2: format = vk::Format::eR32G32Sfloat; break; default: return false; } - *size = used_components; + size = used_components; return true; case vk::Format::eR16G16B16A16Sfloat: switch (used_components) { - case 1: *format = vk::Format::eR16Sfloat; break; - case 2: *format = vk::Format::eR16G16Sfloat; break; + case 1: format = vk::Format::eR16Sfloat; break; + case 2: format = vk::Format::eR16G16Sfloat; break; default: return false; } - *size = used_components; + size = used_components; return true; case vk::Format::eR8G8B8A8Unorm: switch (used_components) { - case 1: *format = vk::Format::eR8Unorm; break; - case 2: *format = vk::Format::eR8G8Unorm; break; + case 1: format = vk::Format::eR8Unorm; break; + case 2: format = vk::Format::eR8G8Unorm; break; default: return false; } - *size = used_components; + size = used_components; return true; case vk::Format::eR8G8B8A8Snorm: if (used_components != 2) { return false; } - *format = vk::Format::eR8G8Snorm; - *size = 2; + format = vk::Format::eR8G8Snorm; + size = 2; return true; case vk::Format::eR8G8B8A8Uint: switch (used_components) { - case 1: *format = vk::Format::eR8Uint; break; - case 2: *format = vk::Format::eR8G8Uint; break; + case 1: format = vk::Format::eR8Uint; break; + case 2: format = vk::Format::eR8G8Uint; break; default: return false; } - *size = used_components; + size = used_components; return true; default: break; } @@ -88,11 +85,8 @@ static bool NarrowInputFormat(vk::Format* format, uint32_t* size, uint32_t used_ return false; } -static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format, uint32_t* size, +static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format, uint32_t& size, uint32_t used_components) { - EXIT_IF(format == nullptr); - EXIT_IF(size == nullptr); - auto fmt = res.Format(); if (fmt == Prospero::GpuEnumValue(Prospero::VertexAttribFormat::k16_16SInt)) { static bool logged_113 = false; @@ -101,11 +95,11 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format, "vk::Format::eR32G32B32A32Sfloat\n"); logged_113 = true; } - *format = vk::Format::eR32G32B32A32Sfloat; - *size = 4; + format = vk::Format::eR32G32B32A32Sfloat; + size = 4; if (NarrowInputFormat(format, size, used_components)) { LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt, - VulkanToString(*format).c_str(), used_components); + VulkanToString(format).c_str(), used_components); } return; } @@ -115,228 +109,228 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format, LOGF("InputFormat: accepting PS5 buffer format 121 as vk::Format::eR16G16Sfloat\n"); logged_121 = true; } - *format = vk::Format::eR16G16Sfloat; - *size = 2; + format = vk::Format::eR16G16Sfloat; + size = 2; if (NarrowInputFormat(format, size, used_components)) { LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt, - VulkanToString(*format).c_str(), used_components); + VulkanToString(format).c_str(), used_components); } return; } switch (static_cast(fmt)) { case Prospero::BufferFormat::k32_32_32_32Float: - *format = vk::Format::eR32G32B32A32Sfloat; - *size = 4; + format = vk::Format::eR32G32B32A32Sfloat; + size = 4; break; case Prospero::BufferFormat::k32_32_32_32SInt: - *format = vk::Format::eR32G32B32A32Sint; - *size = 4; + format = vk::Format::eR32G32B32A32Sint; + size = 4; break; case Prospero::BufferFormat::k32_32_32_32UInt: - *format = vk::Format::eR32G32B32A32Uint; - *size = 4; + format = vk::Format::eR32G32B32A32Uint; + size = 4; break; case Prospero::BufferFormat::k32_32_32Float: - *format = vk::Format::eR32G32B32Sfloat; - *size = 3; + format = vk::Format::eR32G32B32Sfloat; + size = 3; break; case Prospero::BufferFormat::k32_32_32SInt: - *format = vk::Format::eR32G32B32Sint; - *size = 3; + format = vk::Format::eR32G32B32Sint; + size = 3; break; case Prospero::BufferFormat::k32_32_32UInt: - *format = vk::Format::eR32G32B32Uint; - *size = 3; + format = vk::Format::eR32G32B32Uint; + size = 3; break; case Prospero::BufferFormat::k16_16_16_16Float: - *format = vk::Format::eR16G16B16A16Sfloat; - *size = 4; + format = vk::Format::eR16G16B16A16Sfloat; + size = 4; break; case Prospero::BufferFormat::k16_16_16_16SInt: - *format = vk::Format::eR16G16B16A16Sint; - *size = 4; + format = vk::Format::eR16G16B16A16Sint; + size = 4; break; case Prospero::BufferFormat::k16_16_16_16UInt: - *format = vk::Format::eR16G16B16A16Uint; - *size = 4; + format = vk::Format::eR16G16B16A16Uint; + size = 4; break; case Prospero::BufferFormat::k16_16_16_16SScaled: - *format = vk::Format::eR16G16B16A16Sscaled; - *size = 4; + format = vk::Format::eR16G16B16A16Sscaled; + size = 4; break; case Prospero::BufferFormat::k16_16_16_16UScaled: - *format = vk::Format::eR16G16B16A16Uscaled; - *size = 4; + format = vk::Format::eR16G16B16A16Uscaled; + size = 4; break; case Prospero::BufferFormat::k16_16_16_16SNorm: - *format = vk::Format::eR16G16B16A16Snorm; - *size = 4; + format = vk::Format::eR16G16B16A16Snorm; + size = 4; break; case Prospero::BufferFormat::k16_16_16_16UNorm: - *format = vk::Format::eR16G16B16A16Unorm; - *size = 4; + format = vk::Format::eR16G16B16A16Unorm; + size = 4; break; case Prospero::BufferFormat::k32_32Float: - *format = vk::Format::eR32G32Sfloat; - *size = 2; + format = vk::Format::eR32G32Sfloat; + size = 2; break; case Prospero::BufferFormat::k32_32SInt: - *format = vk::Format::eR32G32Sint; - *size = 2; + format = vk::Format::eR32G32Sint; + size = 2; break; case Prospero::BufferFormat::k32_32UInt: - *format = vk::Format::eR32G32Uint; - *size = 2; + format = vk::Format::eR32G32Uint; + size = 2; break; case Prospero::BufferFormat::k8_8_8_8UInt: - *format = vk::Format::eR8G8B8A8Uint; - *size = 4; + format = vk::Format::eR8G8B8A8Uint; + size = 4; break; case Prospero::BufferFormat::k8_8_8_8SScaled: - *format = vk::Format::eR8G8B8A8Sscaled; - *size = 4; + format = vk::Format::eR8G8B8A8Sscaled; + size = 4; break; case Prospero::BufferFormat::k8_8_8_8UScaled: - *format = vk::Format::eR8G8B8A8Uscaled; - *size = 4; + format = vk::Format::eR8G8B8A8Uscaled; + size = 4; break; case Prospero::BufferFormat::k8_8_8_8SNorm: - *format = vk::Format::eR8G8B8A8Snorm; - *size = 4; + format = vk::Format::eR8G8B8A8Snorm; + size = 4; break; case Prospero::BufferFormat::k8_8_8_8UNorm: - *format = vk::Format::eR8G8B8A8Unorm; - *size = 4; + format = vk::Format::eR8G8B8A8Unorm; + size = 4; break; case Prospero::BufferFormat::k10_10_10_2UNorm: - *format = vk::Format::eA2B10G10R10UnormPack32; - *size = 4; + format = vk::Format::eA2B10G10R10UnormPack32; + size = 4; break; case Prospero::BufferFormat::k10_10_10_2SNorm: - *format = vk::Format::eA2B10G10R10SnormPack32; - *size = 4; + format = vk::Format::eA2B10G10R10SnormPack32; + size = 4; break; case Prospero::BufferFormat::k16_16Float: - *format = vk::Format::eR16G16Sfloat; - *size = 2; + format = vk::Format::eR16G16Sfloat; + size = 2; break; case Prospero::BufferFormat::k16_16SInt: - *format = vk::Format::eR16G16Sint; - *size = 2; + format = vk::Format::eR16G16Sint; + size = 2; break; case Prospero::BufferFormat::k16_16UInt: - *format = vk::Format::eR16G16Uint; - *size = 2; + format = vk::Format::eR16G16Uint; + size = 2; break; case Prospero::BufferFormat::k16_16SScaled: - *format = vk::Format::eR16G16Sscaled; - *size = 2; + format = vk::Format::eR16G16Sscaled; + size = 2; break; case Prospero::BufferFormat::k16_16UScaled: - *format = vk::Format::eR16G16Uscaled; - *size = 2; + format = vk::Format::eR16G16Uscaled; + size = 2; break; case Prospero::BufferFormat::k16_16SNorm: - *format = vk::Format::eR16G16Snorm; - *size = 2; + format = vk::Format::eR16G16Snorm; + size = 2; break; case Prospero::BufferFormat::k16_16UNorm: - *format = vk::Format::eR16G16Unorm; - *size = 2; + format = vk::Format::eR16G16Unorm; + size = 2; break; case Prospero::BufferFormat::k32Float: - *format = vk::Format::eR32Sfloat; - *size = 1; + format = vk::Format::eR32Sfloat; + size = 1; break; case Prospero::BufferFormat::k32SInt: - *format = vk::Format::eR32Sint; - *size = 1; + format = vk::Format::eR32Sint; + size = 1; break; case Prospero::BufferFormat::k32UInt: - *format = vk::Format::eR32Uint; - *size = 1; + format = vk::Format::eR32Uint; + size = 1; break; case Prospero::BufferFormat::k8_8SInt: - *format = vk::Format::eR8G8Sint; - *size = 2; + format = vk::Format::eR8G8Sint; + size = 2; break; case Prospero::BufferFormat::k8_8UInt: - *format = vk::Format::eR8G8Uint; - *size = 2; + format = vk::Format::eR8G8Uint; + size = 2; break; case Prospero::BufferFormat::k8_8SScaled: - *format = vk::Format::eR8G8Sscaled; - *size = 2; + format = vk::Format::eR8G8Sscaled; + size = 2; break; case Prospero::BufferFormat::k8_8UScaled: - *format = vk::Format::eR8G8Uscaled; - *size = 2; + format = vk::Format::eR8G8Uscaled; + size = 2; break; case Prospero::BufferFormat::k8_8SNorm: - *format = vk::Format::eR8G8Snorm; - *size = 2; + format = vk::Format::eR8G8Snorm; + size = 2; break; case Prospero::BufferFormat::k8_8UNorm: - *format = vk::Format::eR8G8Unorm; - *size = 2; + format = vk::Format::eR8G8Unorm; + size = 2; break; case Prospero::BufferFormat::k16Float: - *format = vk::Format::eR16Sfloat; - *size = 1; + format = vk::Format::eR16Sfloat; + size = 1; break; case Prospero::BufferFormat::k16SInt: - *format = vk::Format::eR16Sint; - *size = 1; + format = vk::Format::eR16Sint; + size = 1; break; case Prospero::BufferFormat::k16UInt: - *format = vk::Format::eR16Uint; - *size = 1; + format = vk::Format::eR16Uint; + size = 1; break; case Prospero::BufferFormat::k16SScaled: - *format = vk::Format::eR16Sscaled; - *size = 1; + format = vk::Format::eR16Sscaled; + size = 1; break; case Prospero::BufferFormat::k16UScaled: - *format = vk::Format::eR16Uscaled; - *size = 1; + format = vk::Format::eR16Uscaled; + size = 1; break; case Prospero::BufferFormat::k16SNorm: - *format = vk::Format::eR16Snorm; - *size = 1; + format = vk::Format::eR16Snorm; + size = 1; break; case Prospero::BufferFormat::k16UNorm: - *format = vk::Format::eR16Unorm; - *size = 1; + format = vk::Format::eR16Unorm; + size = 1; break; case Prospero::BufferFormat::k8SInt: - *format = vk::Format::eR8Sint; - *size = 1; + format = vk::Format::eR8Sint; + size = 1; break; case Prospero::BufferFormat::k8UInt: - *format = vk::Format::eR8Uint; - *size = 1; + format = vk::Format::eR8Uint; + size = 1; break; case Prospero::BufferFormat::k8SScaled: - *format = vk::Format::eR8Sscaled; - *size = 1; + format = vk::Format::eR8Sscaled; + size = 1; break; case Prospero::BufferFormat::k8UScaled: - *format = vk::Format::eR8Uscaled; - *size = 1; + format = vk::Format::eR8Uscaled; + size = 1; break; case Prospero::BufferFormat::k8SNorm: - *format = vk::Format::eR8Snorm; - *size = 1; + format = vk::Format::eR8Snorm; + size = 1; break; case Prospero::BufferFormat::k8UNorm: - *format = vk::Format::eR8Unorm; - *size = 1; + format = vk::Format::eR8Unorm; + size = 1; break; default: EXIT("unknown format: fmt = %u\n", fmt); - *format = vk::Format::eUndefined; - *size = 4; + format = vk::Format::eUndefined; + size = 4; break; } @@ -391,43 +385,39 @@ static vk::BlendOp GetBlendOp(uint32_t op) { return vk::BlendOp::eAdd; } -static void CreateLayout(vk::DescriptorSetLayout* set_layouts, uint32_t* set_layouts_num, - vk::PushConstantRange* push_constant_info, - uint32_t* push_constant_info_num, +static void CreateLayout(std::span set_layouts, uint32_t& set_layouts_num, + std::span push_constant_info, + uint32_t& push_constant_info_num, const ShaderRecompiler::IR::Program& program, vk::ShaderStageFlags vk_stage, DescriptorCache::Stage stage) { - EXIT_IF(set_layouts == nullptr); - EXIT_IF(set_layouts_num == nullptr); - EXIT_IF(push_constant_info == nullptr); - EXIT_IF(push_constant_info_num == nullptr); - const auto& bindings = program.bindings; const bool need_descriptor = !bindings.descriptors.empty(); if (bindings.push_constant_size != 0) { - auto index = *push_constant_info_num; + auto index = push_constant_info_num; push_constant_info[index].stageFlags = vk_stage; push_constant_info[index].offset = bindings.push_constant_offset; push_constant_info[index].size = bindings.push_constant_size; - (*push_constant_info_num)++; + push_constant_info_num++; } if (need_descriptor) { - EXIT_IF(bindings.descriptor_set != *set_layouts_num); + EXIT_IF(bindings.descriptor_set != set_layouts_num); - set_layouts[*set_layouts_num] = - g_render_ctx->GetDescriptorCache()->GetDescriptorSetLayout(stage, program); - (*set_layouts_num)++; + set_layouts[set_layouts_num] = + GetRenderContext().GetDescriptorCache().GetDescriptorSetLayout(stage, program); + set_layouts_num++; } } -static void ConfigureSubgroupSize(const GraphicContext* gctx, vk::ShaderStageFlagBits vk_stage, +static void ConfigureSubgroupSize(vk::ShaderStageFlagBits vk_stage, const ShaderRecompiler::IR::Program& program, - vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo* required, - vk::PipelineShaderStageCreateInfo* stage) { - EXIT_IF(gctx == nullptr || required == nullptr || stage == nullptr); - const auto config = ConfigureShaderSubgroup(*gctx, vk_stage, program); + vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo& required, + vk::PipelineShaderStageCreateInfo& stage) { + const auto& graphics = GetRenderContext().GetGraphics(); + const auto config = + ConfigureShaderSubgroup(ShaderSubgroupCapabilities {graphics}, vk_stage, program); switch (config.mode) { case ShaderSubgroupMode::Natural: return; case ShaderSubgroupMode::PerInvocationGraphics: { @@ -453,33 +443,30 @@ static void ConfigureSubgroupSize(const GraphicContext* gctx, vk::ShaderStageFla default: EXIT("Vulkan cannot run %u-lane shader stage 0x%08x: default=%u min=%u max=%u " "controlled_stages=0x%08x\n", - program.wave_size, static_cast(vk_stage), gctx->subgroup_size, - gctx->min_subgroup_size, gctx->max_subgroup_size, - static_cast(gctx->required_subgroup_size_stages)); + program.wave_size, static_cast(vk_stage), graphics.subgroup_size, + graphics.min_subgroup_size, graphics.max_subgroup_size, + static_cast( + graphics.required_subgroup_size_stages)); } - required->sType = vk::StructureType::ePipelineShaderStageRequiredSubgroupSizeCreateInfo; - required->requiredSubgroupSize = config.required_size; - stage->pNext = required; + required.sType = vk::StructureType::ePipelineShaderStageRequiredSubgroupSizeCreateInfo; + required.requiredSubgroupSize = config.required_size; + stage.pNext = &required; } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::RenderPass render_pass, - const ShaderVertexInputInfo* vs_input_info, +void CreatePipelineInternal(PipelineCache::GraphicsPipeline& pipeline, vk::RenderPass render_pass, + const ShaderVertexInputInfo& vs_input_info, std::span vs_shader, const ShaderPixelInputInfo* ps_input_info, std::span ps_shader, const PipelineStaticParameters& static_params, uint32_t vs_hash0, uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32, bool ps_active) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(pipeline == nullptr); EXIT_IF(render_pass == nullptr); EXIT_IF(ps_active && ps_input_info == nullptr); - auto* gctx = g_render_ctx->GetGraphicCtx(); - - EXIT_IF(gctx == nullptr); + auto& graphics = GetRenderContext().GetGraphics(); vk::ShaderModule vert_shader_module = nullptr; vk::ShaderModule frag_shader_module = nullptr; @@ -492,7 +479,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende create_info.codeSize = vs_shader.size() * 4; create_info.pCode = vs_shader.data(); - auto result = gctx->device.createShaderModule(&create_info, nullptr, &vert_shader_module); + auto result = graphics.device.createShaderModule(&create_info, nullptr, &vert_shader_module); if (graphics_debug_dump_enabled()) { LOGF("PipelineTrace: vkCreateShaderModule VS done result=%s module=%p\n", VulkanToString(result).c_str(), static_cast(vert_shader_module)); @@ -502,7 +489,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende if (ps_active) { create_info.codeSize = ps_shader.size() * 4; create_info.pCode = ps_shader.data(); - result = gctx->device.createShaderModule(&create_info, nullptr, &frag_shader_module); + result = graphics.device.createShaderModule(&create_info, nullptr, &frag_shader_module); if (graphics_debug_dump_enabled()) { LOGF("PipelineTrace: vkCreateShaderModule PS done result=%s module=%p\n", VulkanToString(result).c_str(), static_cast(frag_shader_module)); @@ -523,9 +510,9 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende vert_shader_stage_info.module = vert_shader_module; vert_shader_stage_info.pName = "main"; vert_shader_stage_info.pSpecializationInfo = nullptr; - EXIT_IF(!vs_input_info->stage); - ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eVertex, *vs_input_info->stage.program, - &vert_subgroup_size, &vert_shader_stage_info); + EXIT_IF(!vs_input_info.stage); + ConfigureSubgroupSize(vk::ShaderStageFlagBits::eVertex, *vs_input_info.stage.program, + vert_subgroup_size, vert_shader_stage_info); vk::PipelineShaderStageCreateInfo frag_shader_stage_info {}; vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo frag_subgroup_size {}; @@ -538,9 +525,8 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende frag_shader_stage_info.pSpecializationInfo = nullptr; if (ps_active) { EXIT_IF(!ps_input_info->stage); - ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eFragment, - *ps_input_info->stage.program, &frag_subgroup_size, - &frag_shader_stage_info); + ConfigureSubgroupSize(vk::ShaderStageFlagBits::eFragment, *ps_input_info->stage.program, + frag_subgroup_size, frag_shader_stage_info); } vk::PipelineShaderStageCreateInfo shader_stages[] = {vert_shader_stage_info, @@ -550,8 +536,8 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende vk::VertexInputAttributeDescription input_attr[ShaderVertexInputInfo::RES_MAX]; vk::VertexInputBindingDescription input_desc[ShaderVertexInputInfo::RES_MAX]; - for (int bi = 0; bi < vs_input_info->buffers_num; bi++) { - const auto& b = vs_input_info->buffers[bi]; + for (int bi = 0; bi < vs_input_info.buffers_num; bi++) { + const auto& b = vs_input_info.buffers[bi]; input_desc[bi].binding = bi; input_desc[bi].stride = b.stride; input_desc[bi].inputRate = @@ -564,11 +550,11 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende input_attr[index].offset = b.attr_offsets[ai]; uint32_t attr_size = 4; - auto registers_num = vs_input_info->resources_dst[index].registers_num; - auto used_components = (vs_input_info->resource_fetch_components[index] > 0 - ? vs_input_info->resource_fetch_components[index] + auto registers_num = vs_input_info.resources_dst[index].registers_num; + auto used_components = (vs_input_info.resource_fetch_components[index] > 0 + ? vs_input_info.resource_fetch_components[index] : registers_num); - GetInputFormat(vs_input_info->resources[index], &input_attr[index].format, &attr_size, + GetInputFormat(vs_input_info.resources[index], input_attr[index].format, attr_size, static_cast(used_components)); if (graphics_debug_dump_enabled()) { @@ -580,29 +566,29 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende " fetched_components=%u attr_size=%u swizzle=%u,%u,%u,%u\n", log_id, index, input_attr[index].binding, input_attr[index].offset, input_desc[bi].stride, static_cast(input_attr[index].format), - static_cast(vs_input_info->resources[index].Format()), - static_cast(vs_input_info->resources_dst[index].register_start), + static_cast(vs_input_info.resources[index].Format()), + static_cast(vs_input_info.resources_dst[index].register_start), static_cast(registers_num), static_cast(used_components), attr_size, - static_cast(vs_input_info->resources[index].DstSelX()), - static_cast(vs_input_info->resources[index].DstSelY()), - static_cast(vs_input_info->resources[index].DstSelZ()), - static_cast(vs_input_info->resources[index].DstSelW())); + static_cast(vs_input_info.resources[index].DstSelX()), + static_cast(vs_input_info.resources[index].DstSelY()), + static_cast(vs_input_info.resources[index].DstSelZ()), + static_cast(vs_input_info.resources[index].DstSelW())); } } - if (vs_input_info->resources[index].OutOfBounds() != 0) { + if (vs_input_info.resources[index].OutOfBounds() != 0) { static bool logged = false; if (!logged) { LOGF("VertexInput: temporary: accepting PS5 out-of-bounds behavior %" PRIu8 "\n", - vs_input_info->resources[index].OutOfBounds()); + vs_input_info.resources[index].OutOfBounds()); logged = true; } } - EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].AddTid()); - EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].SwizzleEnabled()); + EXIT_NOT_IMPLEMENTED(vs_input_info.resources[index].AddTid()); + EXIT_NOT_IMPLEMENTED(vs_input_info.resources[index].SwizzleEnabled()); auto log_unsupported_vertex_swizzle = [index, attr_size, registers_num]( uint32_t swizzle, uint32_t expected) { @@ -619,14 +605,14 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende switch (registers_num) { case 1: { - auto swizzle = vs_input_info->resources[index].DstSelX(); + auto swizzle = vs_input_info.resources[index].DstSelX(); if (swizzle != DstSel(4)) { log_unsupported_vertex_swizzle(swizzle, DstSel(4)); } break; } case 2: { - auto swizzle = vs_input_info->resources[index].DstSelXY(); + auto swizzle = vs_input_info.resources[index].DstSelXY(); auto expected = (attr_size == 1 ? DstSel(4, 0) : DstSel(4, 5)); if (swizzle != expected) { log_unsupported_vertex_swizzle(swizzle, expected); @@ -634,7 +620,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende break; } case 3: { - auto swizzle = vs_input_info->resources[index].DstSelXYZ(); + auto swizzle = vs_input_info.resources[index].DstSelXYZ(); auto expected = (attr_size == 1 ? DstSel(4, 0, 0) : (attr_size == 2 ? DstSel(4, 5, 0) : DstSel(4, 5, 6))); @@ -644,7 +630,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende break; } case 4: { - auto swizzle = vs_input_info->resources[index].DstSelXYZW(); + auto swizzle = vs_input_info.resources[index].DstSelXYZW(); auto expected = DstSel(4, 5, 6, 7); bool supported = false; switch (attr_size) { @@ -679,9 +665,9 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende vertex_input_info.sType = vk::StructureType::ePipelineVertexInputStateCreateInfo; vertex_input_info.pNext = nullptr; vertex_input_info.flags = {}; - vertex_input_info.vertexBindingDescriptionCount = vs_input_info->buffers_num; + vertex_input_info.vertexBindingDescriptionCount = vs_input_info.buffers_num; vertex_input_info.pVertexBindingDescriptions = input_desc; - vertex_input_info.vertexAttributeDescriptionCount = vs_input_info->resources_num; + vertex_input_info.vertexAttributeDescriptionCount = vs_input_info.resources_num; vertex_input_info.pVertexAttributeDescriptions = input_attr; vk::PipelineInputAssemblyStateCreateInfo input_assembly {}; @@ -833,13 +819,13 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende vk::PushConstantRange push_constant_info[2]; uint32_t push_constant_info_num = 0; - EXIT_IF(!vs_input_info->stage); - CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num, - *vs_input_info->stage.program, vk::ShaderStageFlagBits::eVertex, + EXIT_IF(!vs_input_info.stage); + CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num, + *vs_input_info.stage.program, vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex); if (ps_active) { EXIT_IF(!ps_input_info->stage); - CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num, + CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num, *ps_input_info->stage.program, vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel); } @@ -854,7 +840,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende pipeline_layout_info.pPushConstantRanges = push_constant_info_num > 0 ? push_constant_info : nullptr; - EXIT_IF(pipeline->pipeline_layout != nullptr); + EXIT_IF(pipeline.pipeline_layout != nullptr); if (graphics_debug_dump_enabled()) { LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=0x%08" PRIx32 "/0x%08" PRIx32 @@ -862,15 +848,15 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende "\n", vs_hash0, vs_crc32, ps_hash0, ps_crc32, set_layouts_num, push_constant_info_num); } - result = gctx->device.createPipelineLayout(&pipeline_layout_info, nullptr, - &pipeline->pipeline_layout); + result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr, + &pipeline.pipeline_layout); if (graphics_debug_dump_enabled()) { LOGF("PipelineTrace: vkCreatePipelineLayout done result=%s layout=%p\n", - VulkanToString(result).c_str(), static_cast(pipeline->pipeline_layout)); + VulkanToString(result).c_str(), static_cast(pipeline.pipeline_layout)); } EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); - EXIT_NOT_IMPLEMENTED(pipeline->pipeline_layout == nullptr); + EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr); vk::PipelineDepthStencilStateCreateInfo depth_stencil_info {}; depth_stencil_info.sType = vk::StructureType::ePipelineDepthStencilStateCreateInfo; @@ -927,13 +913,13 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende pipeline_info.pDepthStencilState = (static_params.with_depth ? &depth_stencil_info : nullptr); pipeline_info.pColorBlendState = &color_blending; pipeline_info.pDynamicState = &dynamic_state; - pipeline_info.layout = pipeline->pipeline_layout; + pipeline_info.layout = pipeline.pipeline_layout; pipeline_info.renderPass = render_pass; pipeline_info.subpass = 0; pipeline_info.basePipelineHandle = nullptr; pipeline_info.basePipelineIndex = -1; - EXIT_IF(pipeline->pipeline != nullptr); + EXIT_IF(pipeline.pipeline != nullptr); if (graphics_debug_dump_enabled()) { LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=0x%08" PRIx32 "/0x%08" PRIx32 @@ -946,32 +932,27 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende viewport.y, viewport.width, viewport.height, scissor.offset.x, scissor.offset.y, scissor.extent.width, scissor.extent.height); } - result = gctx->device.createGraphicsPipelines(nullptr, 1, &pipeline_info, nullptr, - &pipeline->pipeline); + result = graphics.device.createGraphicsPipelines(nullptr, 1, &pipeline_info, nullptr, + &pipeline.pipeline); if (graphics_debug_dump_enabled()) { LOGF("PipelineTrace: vkCreateGraphicsPipelines done result=%s pipeline=%p\n", - VulkanToString(result).c_str(), static_cast(pipeline->pipeline)); + VulkanToString(result).c_str(), static_cast(pipeline.pipeline)); } EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); - EXIT_NOT_IMPLEMENTED(pipeline->pipeline == nullptr); + EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr); if (frag_shader_module != nullptr) { - gctx->device.destroyShaderModule(frag_shader_module, nullptr); + graphics.device.destroyShaderModule(frag_shader_module, nullptr); } - gctx->device.destroyShaderModule(vert_shader_module, nullptr); + graphics.device.destroyShaderModule(vert_shader_module, nullptr); } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline, - const ShaderComputeInputInfo* input_info, +void CreatePipelineInternal(PipelineCache::ComputePipeline& pipeline, + const ShaderComputeInputInfo& input_info, std::span cs_shader) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(pipeline == nullptr); - - auto* gctx = g_render_ctx->GetGraphicCtx(); - - EXIT_IF(gctx == nullptr); + auto& graphics = GetRenderContext().GetGraphics(); vk::ShaderModule comp_shader_module = nullptr; @@ -984,7 +965,7 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline, create_info.pCode = cs_shader.data(); LOGF("PipelineTrace: vkCreateShaderModule CS begin words=%" PRIu64 "\n", static_cast(cs_shader.size())); - auto result = gctx->device.createShaderModule(&create_info, nullptr, &comp_shader_module); + auto result = graphics.device.createShaderModule(&create_info, nullptr, &comp_shader_module); LOGF("PipelineTrace: vkCreateShaderModule CS done result=%s module=%p\n", VulkanToString(result).c_str(), static_cast(comp_shader_module)); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); @@ -1000,9 +981,9 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline, comp_shader_stage_info.module = comp_shader_module; comp_shader_stage_info.pName = "main"; comp_shader_stage_info.pSpecializationInfo = nullptr; - EXIT_IF(!input_info->stage); - ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eCompute, *input_info->stage.program, - &comp_subgroup_size, &comp_shader_stage_info); + EXIT_IF(!input_info.stage); + ConfigureSubgroupSize(vk::ShaderStageFlagBits::eCompute, *input_info.stage.program, + comp_subgroup_size, comp_shader_stage_info); vk::DescriptorSetLayout set_layouts[1] = {}; uint32_t set_layouts_num = 0; @@ -1010,9 +991,9 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline, vk::PushConstantRange push_constant_info[1]; uint32_t push_constant_info_num = 0; - EXIT_IF(!input_info->stage); - CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num, - *input_info->stage.program, vk::ShaderStageFlagBits::eCompute, + EXIT_IF(!input_info.stage); + CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num, + *input_info.stage.program, vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); vk::PipelineLayoutCreateInfo pipeline_layout_info {}; @@ -1025,39 +1006,39 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline, pipeline_layout_info.pPushConstantRanges = push_constant_info_num > 0 ? push_constant_info : nullptr; - EXIT_IF(pipeline->pipeline_layout != nullptr); + EXIT_IF(pipeline.pipeline_layout != nullptr); LOGF("PipelineTrace: vkCreatePipelineLayout CS begin set_layouts=%u push_constants=%u\n", set_layouts_num, push_constant_info_num); - result = gctx->device.createPipelineLayout(&pipeline_layout_info, nullptr, - &pipeline->pipeline_layout); + result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr, + &pipeline.pipeline_layout); LOGF("PipelineTrace: vkCreatePipelineLayout CS done result=%s layout=%p\n", - VulkanToString(result).c_str(), static_cast(pipeline->pipeline_layout)); + VulkanToString(result).c_str(), static_cast(pipeline.pipeline_layout)); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); - EXIT_NOT_IMPLEMENTED(pipeline->pipeline_layout == nullptr); + EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr); vk::ComputePipelineCreateInfo info {}; info.sType = vk::StructureType::eComputePipelineCreateInfo; info.pNext = nullptr; info.flags = {}; info.stage = comp_shader_stage_info; - info.layout = pipeline->pipeline_layout; + info.layout = pipeline.pipeline_layout; info.basePipelineHandle = nullptr; info.basePipelineIndex = -1; - EXIT_IF(pipeline->pipeline != nullptr); + EXIT_IF(pipeline.pipeline != nullptr); LOGF("PipelineTrace: vkCreateComputePipelines begin layout=%p\n", - static_cast(pipeline->pipeline_layout)); - result = gctx->device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline->pipeline); + static_cast(pipeline.pipeline_layout)); + result = graphics.device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline.pipeline); LOGF("PipelineTrace: vkCreateComputePipelines done result=%s pipeline=%p\n", - VulkanToString(result).c_str(), static_cast(pipeline->pipeline)); + VulkanToString(result).c_str(), static_cast(pipeline.pipeline)); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); - EXIT_NOT_IMPLEMENTED(pipeline->pipeline == nullptr); + EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr); - gctx->device.destroyShaderModule(comp_shader_module, nullptr); + graphics.device.destroyShaderModule(comp_shader_module, nullptr); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/streamBuffer.cpp b/src/graphics/host_gpu/renderer/streamBuffer.cpp index c67d7076d..66f45bc9a 100644 --- a/src/graphics/host_gpu/renderer/streamBuffer.cpp +++ b/src/graphics/host_gpu/renderer/streamBuffer.cpp @@ -16,21 +16,20 @@ namespace { std::atomic g_stream_buffer_count {0}; } // namespace -HostStreamBuffer::HostStreamBuffer() = default; +HostStreamBuffer::HostStreamBuffer(GraphicContext& graphics): m_graphics(graphics) {} HostStreamBuffer::~HostStreamBuffer() { Release(); } -void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) { +void HostStreamBuffer::EnsureBuffer() { if (m_buffer != nullptr) { - if (m_ctx != ctx || m_mapped == nullptr) { - EXIT("host stream buffer changed graphics context\n"); + if (m_mapped == nullptr) { + EXIT("host stream buffer lost its mapped storage\n"); } return; } KYTY_PROFILER_BLOCK("HostStreamBuffer::create"); - m_ctx = ctx; m_buffer = std::make_unique(); m_buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eVertexBuffer | @@ -39,17 +38,16 @@ void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) { m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached; - VulkanCreateBuffer(ctx, CAPACITY, m_buffer.get()); - VulkanMapMemory(ctx, &m_buffer->memory, &m_mapped); + m_graphics.CreateBuffer(CAPACITY, *m_buffer); + m_graphics.MapMemory(m_buffer->memory, m_mapped); const auto count = g_stream_buffer_count.fetch_add(1, std::memory_order_relaxed) + 1; LOGF("HostStreamBuffer: created serial=%" PRIu64 " capacity=%" PRIu64 "\n", count, CAPACITY); } -bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment, - VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range) { +bool HostStreamBuffer::Copy(const void* src, uint64_t size, uint64_t alignment, + VulkanBuffer*& out_buffer, uint64_t& out_offset, uint64_t& out_range) { KYTY_PROFILER_FUNCTION(); - if (ctx == nullptr || src == nullptr || out_buffer == nullptr || out_offset == nullptr || - out_range == nullptr) { + if (src == nullptr) { EXIT("invalid host stream upload\n"); } std::lock_guard lock(m_mutex); @@ -66,12 +64,12 @@ bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size, if (offset > CAPACITY || size > CAPACITY - offset) { return false; } - EnsureBuffer(ctx); + EnsureBuffer(); std::memcpy(static_cast(m_mapped) + offset, src, static_cast(size)); - m_offset = offset + size; - *out_buffer = m_buffer.get(); - *out_offset = offset; - *out_range = size; + m_offset = offset + size; + out_buffer = m_buffer.get(); + out_offset = offset; + out_range = size; return true; } @@ -83,14 +81,13 @@ void HostStreamBuffer::Reset() noexcept { void HostStreamBuffer::Release() noexcept { std::lock_guard lock(m_mutex); if (m_buffer != nullptr) { - if (m_ctx == nullptr || m_mapped == nullptr) { + if (m_mapped == nullptr) { EXIT("invalid host stream buffer release state\n"); } - VulkanUnmapMemory(m_ctx, &m_buffer->memory); - VulkanDeleteBuffer(m_ctx, m_buffer.get()); + m_graphics.UnmapMemory(m_buffer->memory); + m_graphics.DeleteBuffer(*m_buffer); m_buffer.reset(); } - m_ctx = nullptr; m_mapped = nullptr; m_offset = 0; } diff --git a/src/graphics/host_gpu/renderer/streamBuffer.h b/src/graphics/host_gpu/renderer/streamBuffer.h index 4c09a3baa..9bda80614 100644 --- a/src/graphics/host_gpu/renderer/streamBuffer.h +++ b/src/graphics/host_gpu/renderer/streamBuffer.h @@ -18,17 +18,17 @@ struct VulkanBuffer; // backend with scheduler watches will not change descriptor/render call sites. class HostStreamBuffer final { public: - HostStreamBuffer(); + explicit HostStreamBuffer(GraphicContext& graphics); ~HostStreamBuffer(); KYTY_CLASS_NO_COPY(HostStreamBuffer); - [[nodiscard]] bool Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment, - VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range); + [[nodiscard]] bool Copy(const void* src, uint64_t size, uint64_t alignment, + VulkanBuffer*& out_buffer, uint64_t& out_offset, uint64_t& out_range); void Reset() noexcept; void Release() noexcept; private: - void EnsureBuffer(GraphicContext* ctx); + void EnsureBuffer(); // Interim fence-scoped backend: one command processor's eight live command buffers reserve up // to 128 MiB lazily. Additional active processors scale that aggregate until this backend is @@ -36,7 +36,7 @@ private: static constexpr uint64_t CAPACITY = 16ull * 1024ull * 1024ull; mutable std::mutex m_mutex; - GraphicContext* m_ctx = nullptr; + GraphicContext& m_graphics; std::unique_ptr m_buffer; void* m_mapped = nullptr; uint64_t m_offset = 0; diff --git a/src/graphics/host_gpu/renderer/sync.cpp b/src/graphics/host_gpu/renderer/sync.cpp index 9bf8d5990..90bd46a37 100644 --- a/src/graphics/host_gpu/renderer/sync.cpp +++ b/src/graphics/host_gpu/renderer/sync.cpp @@ -24,8 +24,8 @@ constexpr int GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT = 0x00; constexpr int GRAPHICS_EVENT_EOP = 0x40; constexpr uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000; -bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t* value) { - if (host_frequency == 0 || value == nullptr) { +bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t& value) { + if (host_frequency == 0) { return false; } @@ -42,7 +42,7 @@ bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t* if (whole_value > MAX_VALUE - fractional_value) { return false; } - *value = whole_value + fractional_value; + value = whole_value + fractional_value; return true; } @@ -50,25 +50,22 @@ uint64_t ReadReferenceClock() { const auto host_frequency = LibKernel::KernelGetTscFrequency(); const auto host_ticks = LibKernel::KernelReadTsc(); uint64_t value = 0; - if (!ScaleReferenceClock(host_ticks, host_frequency, &value)) { + if (!ScaleReferenceClock(host_ticks, host_frequency, value)) { EXIT("cannot scale host clock, ticks=0x%016" PRIx64 " frequency=%" PRIu64 "\n", host_ticks, host_frequency); } return value; } -static void SubmitLabel(CommandBuffer* buffer, LabelCallback callback_1 = nullptr, +static void SubmitLabel(CommandBuffer& buffer, LabelCallback callback_1 = nullptr, LabelCallback callback_2 = nullptr, const uint64_t* args = nullptr) { - auto* label = LabelCreate(g_render_ctx->GetGraphicCtx(), callback_1, callback_2, args); - LabelSet(buffer, label); - LabelDelete(label); + auto* label = LabelCreate(callback_1, callback_2, args); + LabelSet(buffer, *label); + LabelDelete(*label); } static bool CompleteDisplayBufferFlip(const uint64_t* args) { - if (g_render_ctx == nullptr || args == nullptr) { - EXIT("GPU flip completion has invalid state, render_ctx=%p args=%p\n", - static_cast(g_render_ctx), static_cast(args)); - } + EXIT_IF(args == nullptr); Presentation::DisplayBufferCompleteFlipFromGpu(args[0]); return true; } @@ -90,20 +87,17 @@ enum class EndOfPipeWriteSize : uint32_t { Dword = 4, Qword = 8 }; enum class EndOfPipeWriteAction { Write, WriteBack, Interrupt, InterruptWriteBack }; static bool TriggerEopEventCallback(const uint64_t* args) { - EXIT_IF(g_render_ctx == nullptr); EXIT_IF(args == nullptr); - g_render_ctx->TriggerEopEvent(static_cast(args[0])); + GetRenderContext().TriggerEopEvent(static_cast(args[0])); return true; } static bool TriggerDefaultEopEventCallback(const uint64_t* /*args*/) { - EXIT_IF(g_render_ctx == nullptr); - g_render_ctx->TriggerEopEvent(0); + GetRenderContext().TriggerEopEvent(0); return true; } static void ValidateEndOfPipeSignal(const EndOfPipeSignal& signal) { - EXIT_IF(g_render_ctx == nullptr); if (signal.destination.has_value()) { EXIT_IF(*signal.destination == 0); } @@ -121,13 +115,13 @@ static void RecordEndOfPipeSignal(const EndOfPipeSignal& signal) { switch (signal.completion) { case EndOfPipeCompletion::None: return; case EndOfPipeCompletion::Interrupt: - SubmitLabel(signal.buffer, nullptr, TriggerEopEventCallback, args); + SubmitLabel(*signal.buffer, nullptr, TriggerEopEventCallback, args); return; case EndOfPipeCompletion::Flip: - SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, nullptr, args); + SubmitLabel(*signal.buffer, CompleteDisplayBufferFlip, nullptr, args); return; case EndOfPipeCompletion::FlipAndInterrupt: - SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback, + SubmitLabel(*signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback, args); return; } @@ -149,7 +143,7 @@ static bool TriggersInterrupt(EndOfPipeWriteAction action) { action == EndOfPipeWriteAction::InterruptWriteBack; } -static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer* buffer, uint64_t destination, +static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer& buffer, uint64_t destination, uint64_t value, EndOfPipeWriteSize size, EndOfPipeWriteAction action, uint32_t context_id = 0) { const auto width = static_cast(size); @@ -158,7 +152,7 @@ static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer* buffer, uint const bool interrupt = TriggersInterrupt(action); EndOfPipeSignal signal { - .buffer = buffer, + .buffer = &buffer, .submit_id = submit_id, .debug_operation = DebugOperation(action), .debug_args = interrupt ? std::array {width, context_id, value_low, value_high} @@ -179,21 +173,20 @@ void TriggerAgcUserInterrupt() { } void TriggerEopEvent(uint32_t context_id) { - EXIT_IF(g_render_ctx == nullptr); - g_render_ctx->TriggerEopEvent(context_id); + GetRenderContext().TriggerEopEvent(context_id); } -void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, +void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Write); } -void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, +void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t dw_offset, uint32_t dw_num) { const auto destination = reinterpret_cast(dst_gpu_addr); RecordEndOfPipeSignal({ - .buffer = buffer, + .buffer = &buffer, .submit_id = submit_id, .debug_operation = CommandBufferDebugOp::EopWrite, .debug_args = {dw_offset, dw_num, 0, 0}, @@ -202,13 +195,13 @@ void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* }); } -void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, +void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write); } -void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, +void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), 0, EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write); @@ -218,7 +211,7 @@ void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uin reinterpret_cast(dst_gpu_addr), value); } -void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), 0, EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack); @@ -228,19 +221,19 @@ void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer reinterpret_cast(dst_gpu_addr), value); } -void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack); } -void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::WriteBack); } -void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, @@ -248,7 +241,7 @@ void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* context_id); } -void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, @@ -256,24 +249,24 @@ void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* context_id); } -void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Interrupt, context_id); } -void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Interrupt, context_id); } -uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index, int flip_mode, +uint64_t PrepareDisplayBufferFlip(CommandBuffer& buffer, int handle, int index, int flip_mode, int64_t flip_arg) { for (;;) { uint64_t request_id = 0; const auto result = Presentation::DisplayBufferSubmitFlipFromGpu( - buffer, handle, index, flip_mode, flip_arg, &request_id); + buffer, handle, index, flip_mode, flip_arg, request_id); if (result == OK) { EXIT_IF(request_id == 0); return request_id; @@ -287,13 +280,13 @@ uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index, } } -void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id) { const auto destination = reinterpret_cast(dst_gpu_addr); RecordEndOfPipeSignal({ - .buffer = buffer, + .buffer = &buffer, .submit_id = submit_id, .debug_operation = CommandBufferDebugOp::EopWriteBackFlip, .debug_args = {static_cast(handle), static_cast(index), @@ -305,12 +298,12 @@ void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuf }); } -void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, +void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id) { const auto destination = reinterpret_cast(dst_gpu_addr); RecordEndOfPipeSignal({ - .buffer = buffer, + .buffer = &buffer, .submit_id = submit_id, .debug_operation = CommandBufferDebugOp::EopFlip, .debug_args = {static_cast(handle), static_cast(index), @@ -322,10 +315,10 @@ void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint3 }); } -void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index, +void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer& buffer, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id) { RecordEndOfPipeSignal({ - .buffer = buffer, + .buffer = &buffer, .submit_id = submit_id, .debug_operation = CommandBufferDebugOp::EopOnlyFlip, .debug_args = {static_cast(handle), static_cast(index), @@ -336,8 +329,8 @@ void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int han }); } -void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id) { - ValidateEndOfPipeSignal({.buffer = buffer}); +void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id) { + ValidateEndOfPipeSignal({.buffer = &buffer}); uint64_t args[LABEL_ARGS_MAX] = {static_cast(context_id)}; SubmitLabel(buffer, nullptr, TriggerEopEventCallback, args); @@ -353,11 +346,10 @@ static void EopEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) { static void EopEventDeleteFunc(LibKernel::EventQueue::KernelEqueue eq, LibKernel::EventQueue::KernelEqueueEvent* event) { EXIT_IF(event == nullptr); - EXIT_IF(g_render_ctx == nullptr); EXIT_NOT_IMPLEMENTED(event->event.filter != LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS); if (event->event.ident == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || event->event.ident == GRAPHICS_EVENT_EOP) { - g_render_ctx->DeleteEopEq(eq, static_cast(event->event.ident)); + GetRenderContext().DeleteEopEq(eq, static_cast(event->event.ident)); } } @@ -377,8 +369,6 @@ static void EopEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event, } int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) { - EXIT_IF(g_render_ctx == nullptr); - LibKernel::EventQueue::KernelEqueueEvent event; event.triggered = false; event.event.ident = static_cast(id); @@ -395,15 +385,13 @@ int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) { if (result == 0 && (id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP)) { - g_render_ctx->AddEopEq(eq, id); + GetRenderContext().AddEopEq(eq, id); } return result; } int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) { - EXIT_IF(g_render_ctx == nullptr); - int result = LibKernel::EventQueue::KernelDeleteEvent( eq, static_cast(id), LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS); @@ -411,14 +399,11 @@ int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) { } void ReadGds(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) { - EXIT_IF(g_render_ctx == nullptr); - - g_render_ctx->GetGdsBuffer()->Read(g_render_ctx->GetGraphicCtx(), dst, dw_offset, dw_size); + GetRenderContext().GetGdsBuffer().Read(dst, dw_offset, dw_size); } void DeleteBuffers() { - EXIT_IF(g_render_ctx == nullptr); - g_render_ctx->GetBufferCache()->ResetNullBuffer(); + GetRenderContext().GetBufferCache().ResetNullBuffer(); } } // namespace Libs::Graphics::Sync diff --git a/src/graphics/host_gpu/renderer/sync.h b/src/graphics/host_gpu/renderer/sync.h index 6cabccf33..29068e9aa 100644 --- a/src/graphics/host_gpu/renderer/sync.h +++ b/src/graphics/host_gpu/renderer/sync.h @@ -12,48 +12,48 @@ class CommandBuffer; namespace Sync { [[nodiscard]] bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, - uint64_t* value); + uint64_t& value); [[nodiscard]] uint64_t ReadReferenceClock(); void TriggerAgcUserInterrupt(); void TriggerEopEvent(uint32_t context_id); -void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id); +void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id); -void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, +void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value); -void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, +void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value); -void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, +void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t dw_offset, uint32_t dw_num); -void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, +void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value); -void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value); -void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value); -void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value); -void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id = 0); -void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id = 0); -void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id = 0); -void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id = 0); -[[nodiscard]] uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index, +[[nodiscard]] uint64_t PrepareDisplayBufferFlip(CommandBuffer& buffer, int handle, int index, int flip_mode, int64_t flip_arg); -void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index, +void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer& buffer, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id); -void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, +void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id); -void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer* buffer, +void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id); diff --git a/src/graphics/host_gpu/renderer/textureCache.cpp b/src/graphics/host_gpu/renderer/textureCache.cpp index a362888a1..005e49d9c 100644 --- a/src/graphics/host_gpu/renderer/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/textureCache.cpp @@ -139,14 +139,14 @@ bool IsExactRenderTargetMipStorage(const ImageInfo& sampled, const ImageInfo& st std::array level_layouts {}; std::array level_padded {}; if (!TileGetRenderTargetMipLayout(sampled.width, sampled.height, sampled.pitch, - bytes_per_element, sampled.levels, &sampled_layout, + bytes_per_element, sampled.levels, sampled_layout, level_layouts.data(), level_padded.data()) || sampled_layout.align != 65536 || sampled_layout.size != sampled.size) { return false; } TileSizeAlign storage_layout {}; if (!TileGetRenderTargetSize(storage.width, storage.height, storage.pitch, bytes_per_element, - &storage_layout) || + storage_layout) || storage_layout.align != 65536 || storage_layout.size != storage.size) { return false; } @@ -189,6 +189,8 @@ bool IsExactRenderTargetMipStorage(const ImageInfo& sampled, const ImageInfo& st } struct TextureCache::CachedImage { + explicit CachedImage(GraphicContext& graphics): graphics(graphics) {} + enum class Kind { Texture, StorageTexture, @@ -200,7 +202,7 @@ struct TextureCache::CachedImage { RenderTargetInfo target; DepthTargetInfo depth; VideoOutInfo video_out; - GraphicContext* ctx = nullptr; + GraphicContext& graphics; VulkanImage* image = nullptr; bool gpu_modified = false; bool buffer_modified = false; @@ -208,13 +210,12 @@ struct TextureCache::CachedImage { bool registered = false; ~CachedImage() { - if (ctx == nullptr || image == nullptr || registered) { - EXIT("TextureCache: cached image destroyed with invalid resources, ctx=%p image=%p " + if (image == nullptr || registered) { + EXIT("TextureCache: cached image destroyed with invalid resources, image=%p " "kind=%u registered=%d\n", - static_cast(ctx), static_cast(image), - static_cast(kind), registered); + static_cast(image), static_cast(kind), registered); } - ImageOps::Destroy(ctx, image); + ImageOps::Destroy(*image); image = nullptr; } @@ -323,17 +324,17 @@ void TextureCache::UnregisterImageLocked(CachedImage& image, bool release_tracki image.registered = false; } -VulkanImage* TextureCache::PublishImage(CommandBuffer* command, +VulkanImage& TextureCache::PublishImage(CommandBuffer& command, std::shared_ptr image) { - if (command == nullptr || image == nullptr || image->image == nullptr || image->registered) { - EXIT("TextureCache: invalid image publication, command=%p record=%p image=%p " + if (image == nullptr || image->image == nullptr || image->registered) { + EXIT("TextureCache: invalid image publication, record=%p image=%p " "registered=%d\n", - static_cast(command), static_cast(image.get()), + static_cast(image.get()), image != nullptr ? static_cast(image->image) : nullptr, image != nullptr && image->registered); } - auto result = image->image; - command->RetainResourceUntilFence(image); + auto& result = *image->image; + command.RetainResourceUntilFence(image); m_images.push_back(std::move(image)); RegisterImageLocked(*m_images.back()); return result; @@ -514,7 +515,7 @@ struct TextureCache::ReadbackWorker { Prospero::GpuEnumValue(has_stencil ? Prospero::StencilFormat::k8UInt : Prospero::StencilFormat::kInvalid), - has_htile, &expected_stencil, &expected_htile, &expected_depth); + has_htile, expected_stencil, expected_htile, expected_depth); const auto expected_pitch = prospero_layout ? TileGetTexturePitch(info.guest_format, info.width, 1, @@ -604,8 +605,8 @@ struct TextureCache::ReadbackWorker { TileBlockLayout depth_block {}; TileBlockLayout stencil_block {}; EXIT_NOT_IMPLEMENTED( - !TileGetBlockLayout(TileBlockFamily::Depth64KB, info.bytes_per_element, &depth_block) || - (has_stencil && !TileGetBlockLayout(TileBlockFamily::Depth64KB, 1, &stencil_block))); + !TileGetBlockLayout(TileBlockFamily::Depth64KB, info.bytes_per_element, depth_block) || + (has_stencil && !TileGetBlockLayout(TileBlockFamily::Depth64KB, 1, stencil_block))); gpu_infos.reserve(regions.size()); for (uint32_t layer = 0; layer < info.layers; layer++) { const uint64_t offset = depth_slice_size * layer; @@ -642,8 +643,8 @@ struct TextureCache::ReadbackWorker { } } guest.resize(transfer_size); - Transfer::DownloadTiledImage(cached.ctx, guest.data(), transfer_size, transfer_size, - gpu_infos, regions, cached.image, cached.image->layout); + Transfer::DownloadTiledImage(guest.data(), transfer_size, transfer_size, gpu_infos, regions, + *cached.image, cached.image->layout); Libs::LibKernel::Memory::WriteBacking(info.address, guest.data(), info.size); ReadbackTransfer transfer; transfer.Add(info.address, info.size); @@ -685,7 +686,7 @@ struct TextureCache::ReadbackWorker { const bool target_mip_chain = target && info.levels > 1 && layers == 1 && tiled_target && TileGetRenderTargetMipLayout(info.width, info.height, info.pitch, - info.bytes_per_element, info.levels, &target_mip_layout, + info.bytes_per_element, info.levels, target_mip_layout, nullptr, nullptr) && target_mip_layout.align == 65536 && target_mip_layout.size == info.size && cached.image != nullptr && cached.image->format == info.format && @@ -743,14 +744,14 @@ struct TextureCache::ReadbackWorker { : ImageOps::RenderTargetTransferFormat(info.bytes_per_element); guest.resize(info.size); EXIT_NOT_IMPLEMENTED(!TextureBuildGpuTileInfos(info.size, tiled_regions, tiled_layout, - format, layers, info.levels, &infos)); - Transfer::DownloadTiledImage(cached.ctx, guest.data(), info.size, info.size, infos, - regions, cached.image, cached.image->layout); + format, layers, info.levels, infos)); + Transfer::DownloadTiledImage(guest.data(), info.size, info.size, infos, regions, + *cached.image, cached.image->layout); Libs::LibKernel::Memory::WriteBacking(info.address, guest.data(), info.size); } else { download.resize(info.size); std::fill(download.begin(), download.end(), 0); - Transfer::DownloadImage(cached.ctx, download.data(), info.size, regions, cached.image, + Transfer::DownloadImage(download.data(), info.size, regions, *cached.image, cached.image->layout); Libs::LibKernel::Memory::WriteBacking(info.address, download.data(), info.size); } @@ -789,16 +790,14 @@ struct TextureCache::ReadbackWorker { const bool depth_target = selected != nullptr && selected->kind == CachedImage::Kind::DepthTarget; if ((!render_target && !storage_texture && !depth_target) || !selected->gpu_modified || - selected->buffer_modified || selected->ctx == nullptr || - selected->image == nullptr) { + selected->buffer_modified || selected->image == nullptr) { EXIT("TextureCache: unsupported GPU image readback owner, addr=0x%016" PRIx64 " size=0x%016" PRIx64 " access=%u image=%p kind=%u gpu_modified=%d " - "buffer_modified=%d ctx=%p vulkan_image=%p\n", + "buffer_modified=%d vulkan_image=%p\n", vaddr, size, static_cast(access), static_cast(selected), selected != nullptr ? static_cast(selected->kind) : UINT32_MAX, selected != nullptr && selected->gpu_modified, selected != nullptr && selected->buffer_modified, - selected != nullptr ? static_cast(selected->ctx) : nullptr, selected != nullptr ? static_cast(selected->image) : nullptr); } @@ -1006,20 +1005,19 @@ void TextureCache::RetireDepthMetadataLocked(const std::vector& re } void TextureCache::MaterializeImagesToGuestLocked( - GraphicContext* ctx, const std::vector>& images) { + const std::vector>& images) { if (std::any_of(images.begin(), images.end(), [](const auto& cached) { return cached->gpu_modified; })) { - Transfer::WaitForGraphicsIdle(ctx); + Transfer::WaitForGraphicsIdle(); } for (const auto& cached: images) { if (!cached->gpu_modified) { continue; } - if (cached->ctx != ctx || cached->buffer_modified) { - EXIT("TextureCache: image recreation has invalid ownership, kind=%u ctx=%p/%p " + if (cached->buffer_modified) { + EXIT("TextureCache: image recreation has invalid ownership, kind=%u " "buffer_modified=%d\n", - static_cast(cached->kind), static_cast(cached->ctx), - static_cast(ctx), cached->buffer_modified); + static_cast(cached->kind), cached->buffer_modified); } if (cached->kind != CachedImage::Kind::DepthTarget && cached->kind != CachedImage::Kind::RenderTarget && @@ -1116,20 +1114,19 @@ bool Equal(const DepthTargetInfo& left, const DepthTargetInfo& right) { return result; } -void AppendLayerCopies(std::vector& regions, VulkanImage* source, +void AppendLayerCopies(std::vector& regions, VulkanImage& source, vk::ImageAspectFlags aspect) { - for (uint32_t layer = 0; layer < source->layers; layer++) { - for (uint32_t level = 0; level < source->mip_levels; level++) { - ImageImageCopy region {}; - region.src_image = source; + for (uint32_t layer = 0; layer < source.layers; layer++) { + for (uint32_t level = 0; level < source.mip_levels; level++) { + ImageImageCopy region {source}; region.src_aspect = aspect; region.dst_aspect = aspect; region.src_level = level; region.dst_level = level; region.src_layer = layer; region.dst_layer = layer; - region.width = std::max(source->extent.width >> level, 1u); - region.height = std::max(source->extent.height >> level, 1u); + region.width = std::max(source.extent.width >> level, 1u); + region.height = std::max(source.extent.height >> level, 1u); regions.push_back(region); } } @@ -1137,10 +1134,11 @@ void AppendLayerCopies(std::vector& regions, VulkanImage* source } // namespace -TextureCache::TextureCache(PageManager& page_manager, BufferCache& buffer_cache, - ResourceMutex& resource_mutex) - : m_memory_tracker(page_manager), m_metadata_tracker(page_manager, PageWatchMode::Write), - m_buffer_cache(buffer_cache), m_resource_mutex(resource_mutex) { +TextureCache::TextureCache(GraphicContext& graphics, PageManager& page_manager, + BufferCache& buffer_cache, ResourceMutex& resource_mutex) + : m_graphics(graphics), m_memory_tracker(page_manager), + m_metadata_tracker(page_manager, PageWatchMode::Write), m_buffer_cache(buffer_cache), + m_resource_mutex(resource_mutex) { if (!Common::Thread::IsMainThread()) { EXIT("TextureCache: construction is restricted to the main thread\n"); } @@ -1184,7 +1182,7 @@ void TextureCache::MarkSampledAliasesCpuDirtyLocked(uint64_t vaddr, uint64_t siz } } -void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageInfo& requested) { +void TextureCache::RetireSampledTargetAliases(const ImageInfo& requested) { std::vector retire; bool wait_idle = false; for (auto* cached: FindImagesInRegionLocked(requested.address, requested.size, true)) { @@ -1192,7 +1190,7 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn continue; } switch (ClassifySampledRenderTargetOverlap(requested, cached->target, - cached->buffer_modified, cached->ctx == ctx)) { + cached->buffer_modified)) { case RenderTargetOverlap::None: continue; case RenderTargetOverlap::RetireTarget: wait_idle |= cached->gpu_modified; @@ -1205,9 +1203,9 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn case RenderTargetOverlap::Unsupported: EXIT("TextureCache: unsupported sampled/render-target alias, sampled=0x%016" PRIx64 "+0x%016" PRIx64 " target=0x%016" PRIx64 "+0x%016" PRIx64 - " same_context=%d gpu=%d buffer=%d\n", + " gpu=%d buffer=%d\n", requested.address, requested.size, cached->target.address, cached->target.size, - cached->ctx == ctx, cached->gpu_modified, cached->buffer_modified); + cached->gpu_modified, cached->buffer_modified); } } for (auto* cached: FindImagesInRegionLocked(requested.address, requested.size, true)) { @@ -1239,30 +1237,29 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn cached->depth.stencil_size); const bool clean_pool_alias = CanRetireGuestCurrentDepthForSampled( requested, cached->depth, cached->gpu_modified, cached->buffer_modified, - depth_tracker_gpu, stencil_tracker_gpu, cached->ctx == ctx); + depth_tracker_gpu, stencil_tracker_gpu); const bool native_transition = - cached->ctx == ctx && !cached->buffer_modified && cached->depth.stencil_address == 0 && + !cached->buffer_modified && cached->depth.stencil_address == 0 && cached->depth.stencil_size == 0 && cached->depth.layers == 1 && contained && (exact_range || sampled_expansion); const bool supported = clean_pool_alias || native_transition; if (!supported) { EXIT("TextureCache: unsupported sampled/depth-target alias, sampled=0x%016" PRIx64 "+0x%016" PRIx64 " depth=0x%016" PRIx64 "+0x%016" PRIx64 - " overlaps=%d/%d contained=%d same_context=%d gpu=%d/%d/%d buffer=%d" + " overlaps=%d/%d contained=%d gpu=%d/%d/%d buffer=%d" " stencil=0x%016" PRIx64 "+0x%016" PRIx64 " layers=%u expansion=%d" " sampled_info={fmt=%u extent=%ux%u pitch=%u levels=%u/%u tile=%u type=%u}" " depth_info={fmt=%u host=%d extent=%ux%u pitch=%u tile=%u htile=0x%016" PRIx64 "+0x%016" PRIx64 "}\n", requested.address, requested.size, cached->depth.address, cached->depth.size, - overlaps_depth, overlaps_stencil, contained, cached->ctx == ctx, - cached->gpu_modified, depth_tracker_gpu, stencil_tracker_gpu, - cached->buffer_modified, cached->depth.stencil_address, cached->depth.stencil_size, - cached->depth.layers, sampled_expansion, requested.format, requested.width, - requested.height, requested.pitch, requested.levels, requested.view_levels, - requested.tile, requested.type, cached->depth.guest_format, - static_cast(cached->depth.format), cached->depth.width, cached->depth.height, - cached->depth.pitch, cached->depth.tile_mode, cached->depth.htile_address, - cached->depth.htile_size); + overlaps_depth, overlaps_stencil, contained, cached->gpu_modified, + depth_tracker_gpu, stencil_tracker_gpu, cached->buffer_modified, + cached->depth.stencil_address, cached->depth.stencil_size, cached->depth.layers, + sampled_expansion, requested.format, requested.width, requested.height, + requested.pitch, requested.levels, requested.view_levels, requested.tile, + requested.type, cached->depth.guest_format, static_cast(cached->depth.format), + cached->depth.width, cached->depth.height, cached->depth.pitch, + cached->depth.tile_mode, cached->depth.htile_address, cached->depth.htile_size); } wait_idle |= cached->gpu_modified; retire.push_back(cached); @@ -1272,7 +1269,7 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn } RequireRetirementIsolation(retire, "sampled target", requested.address, requested.size); if (wait_idle) { - Transfer::WaitForGraphicsIdle(ctx); + Transfer::WaitForGraphicsIdle(); } for (auto* cached: retire) { if (!cached->gpu_modified) { @@ -1291,14 +1288,14 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn RetireImages(retire); } -void TextureCache::ResolveStorageImageOverlaps(GraphicContext* ctx, const ImageInfo& requested) { +void TextureCache::ResolveStorageImageOverlaps(const ImageInfo& requested) { std::vector retire; for (auto* cached: FindImagesInRegionLocked(requested.address, requested.size, true)) { const bool tracker_gpu = m_memory_tracker.IsRegionGpuModified(cached->Address(), cached->Size()); switch (ClassifyStorageImageOverlap( requested.address, requested.size, cached->Address(), cached->Size(), - cached->kind == CachedImage::Kind::Texture, cached->ctx == ctx, cached->gpu_modified, + cached->kind == CachedImage::Kind::Texture, cached->gpu_modified, cached->buffer_modified, tracker_gpu)) { case StorageImageOverlap::None: continue; case StorageImageOverlap::RetireSampled: retire.push_back(cached); continue; @@ -1306,10 +1303,10 @@ void TextureCache::ResolveStorageImageOverlaps(GraphicContext* ctx, const ImageI case StorageImageOverlap::Unsupported: EXIT("TextureCache: unsupported storage-image byte alias, requested=0x%016" PRIx64 "+0x%016" PRIx64 " existing=0x%016" PRIx64 "+0x%016" PRIx64 - " kind=%u same_context=%d gpu=%d/%d buffer=%d\n", + " kind=%u gpu=%d/%d buffer=%d\n", requested.address, requested.size, cached->Address(), cached->Size(), - static_cast(cached->kind), cached->ctx == ctx, cached->gpu_modified, - tracker_gpu, cached->buffer_modified); + static_cast(cached->kind), cached->gpu_modified, tracker_gpu, + cached->buffer_modified); } } // Every exact byte overlap was classified above: only clean sampled images are retired and all @@ -1330,7 +1327,7 @@ void TextureCache::ResolveStorageImageOverlaps(GraphicContext* ctx, const ImageI RetireImages(retire); } -void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const ImageInfo& requested) { +void TextureCache::RetireStorageDepthAliasLocked(const ImageInfo& requested) { CachedImage* selected = nullptr; for (auto* entry: FindImagesInRegionLocked(requested.address, requested.size, true)) { auto& cached = *entry; @@ -1340,10 +1337,10 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag } const auto& depth = cached.depth; const bool exact_d32_uint = - cached.ctx == ctx && cached.gpu_modified && !cached.buffer_modified && - depth.address == requested.address && depth.size == requested.size && - depth.stencil_address == 0 && depth.stencil_size == 0 && depth.htile_address == 0 && - depth.htile_size == 0 && depth.layers == 1 && depth.format == vk::Format::eD32Sfloat && + cached.gpu_modified && !cached.buffer_modified && depth.address == requested.address && + depth.size == requested.size && depth.stencil_address == 0 && depth.stencil_size == 0 && + depth.htile_address == 0 && depth.htile_size == 0 && depth.layers == 1 && + depth.format == vk::Format::eD32Sfloat && depth.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) && depth.bytes_per_element == 4 && depth.width == requested.width && depth.height == requested.height && depth.pitch == requested.pitch && @@ -1363,7 +1360,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag if (selected == nullptr) { return; } - Transfer::WaitForGraphicsIdle(ctx); + Transfer::WaitForGraphicsIdle(); const auto transfer = m_readback->DownloadDepthTarget(*selected, false); for (const auto& range: transfer.Ranges()) { m_memory_tracker.ForEachDownloadRange(range.address, range.size, @@ -1376,7 +1373,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag TextureCache::~TextureCache() { m_readback.reset(); if (!m_images.empty()) { - Transfer::WaitForGraphicsIdle(m_images.front()->ctx); + Transfer::WaitForGraphicsIdle(); } for (const auto& image: m_images) { UnregisterImageLocked(*image, false); @@ -1385,21 +1382,21 @@ TextureCache::~TextureCache() { m_dummy_textures.reset(); } -VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* ctx, - const ImageInfo& info, bool metadata_read) { +VulkanImage& TextureCache::FindTexture(CommandBuffer& command, const ImageInfo& info, + bool metadata_read) { if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address || info.width == 0 || info.height == 0 || info.depth == 0 || info.levels == 0 || info.levels >= 16 || info.view_levels == 0 || info.base_level + info.view_levels > info.levels) { - EXIT("TextureCache: invalid sampled-image request, command=%p ctx=%p addr=0x%016" PRIx64 + EXIT("TextureCache: invalid sampled-image request, command=%p addr=0x%016" PRIx64 " size=0x%016" PRIx64 " extent=%ux%ux%u levels=%u\n", - static_cast(command), static_cast(ctx), info.address, - info.size, info.width, info.height, info.depth, info.levels); + static_cast(&command), info.address, info.size, info.width, info.height, + info.depth, info.levels); } std::lock_guard transaction(m_resource_mutex); { FaultSafeTextureLock lock(this, m_lock); - RetireSampledTargetAliases(ctx, info); + RetireSampledTargetAliases(info); } BufferImageCopySource source {nullptr, 0, info.address, info.size, true}; if (m_buffer_cache.HasPageOverlap(info.address, info.size)) { @@ -1435,7 +1432,7 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c info, cached->info, requested_view_format, cached->image->format); switch (ClassifyStorageSampledOverlap( info, cached->info, requested_view_format, cached->image->format, cached->gpu_modified, - cpu_dirty, cached->ctx == ctx, exact_mip, cached->buffer_modified, tracker_gpu)) { + cpu_dirty, exact_mip, cached->buffer_modified, tracker_gpu)) { case StorageSampledOverlap::None: break; case StorageSampledOverlap::ExactImage: if (storage_match != nullptr) { @@ -1453,20 +1450,20 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c "requested=0x%016" PRIx64 "+0x%016" PRIx64 " storage=0x%016" PRIx64 "+0x%016" PRIx64 " gpu_modified=%d buffer_modified=%d tracker_gpu=%d cpu_dirty=%d" - " same_context=%d exact_mip=%d" + " exact_mip=%d" " requested_info={format=%u extent=%ux%ux%u pitch=%u base=%u levels=%u" " view_levels=%u tile=%u swizzle=0x%03x type=%u base_array=%u}" " storage_info={format=%u extent=%ux%ux%u pitch=%u base=%u levels=%u" " view_levels=%u tile=%u swizzle=0x%03x type=%u base_array=%u}\n", info.address, info.size, cached->info.address, cached->info.size, cached->gpu_modified, cached->buffer_modified, tracker_gpu, cpu_dirty, - cached->ctx == ctx, exact_mip, info.format, info.width, info.height, - info.depth, info.pitch, info.base_level, info.levels, info.view_levels, - info.tile, info.swizzle, info.type, info.base_array, cached->info.format, - cached->info.width, cached->info.height, cached->info.depth, - cached->info.pitch, cached->info.base_level, cached->info.levels, - cached->info.view_levels, cached->info.tile, cached->info.swizzle, - cached->info.type, cached->info.base_array); + exact_mip, info.format, info.width, info.height, info.depth, info.pitch, + info.base_level, info.levels, info.view_levels, info.tile, info.swizzle, + info.type, info.base_array, cached->info.format, cached->info.width, + cached->info.height, cached->info.depth, cached->info.pitch, + cached->info.base_level, cached->info.levels, cached->info.view_levels, + cached->info.tile, cached->info.swizzle, cached->info.type, + cached->info.base_array); } } if (storage_match != nullptr && !storage_retire.empty()) { @@ -1483,15 +1480,15 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c "addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", info.address, info.size); } - command->RetainResourceUntilFence(storage_match); - return storage_match->image; + command.RetainResourceUntilFence(storage_match); + return *storage_match->image; } if (!storage_retire.empty()) { // shadPS4 resolves a modified cached mip before replacing it with the containing image. // Kyty does not yet copy between those independently allocated Vulkan images, so use the // existing synchronized tiled readback seam and rebuild the complete chain from coherent // guest backing. This is an uncommon ownership transition, not a frame lookup fast path. - Transfer::WaitForGraphicsIdle(ctx); + Transfer::WaitForGraphicsIdle(); for (auto* cached: storage_retire) { if (!cached->gpu_modified || cached->buffer_modified || cached->info.IsCpuDirty() || !m_memory_tracker.IsRegionGpuModified(cached->info.address, cached->info.size) || @@ -1518,11 +1515,10 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c if (cached->kind != CachedImage::Kind::Texture || !Equal(info, cached->info)) { continue; } - if (match != nullptr || cached->gpu_modified || cached->ctx != ctx) { + if (match != nullptr || cached->gpu_modified) { EXIT("TextureCache: invalid exact sampled-image cache match, addr=0x%016" PRIx64 - " size=0x%016" PRIx64 " duplicate=%d gpu_modified=%d same_context=%d\n", - info.address, info.size, match != nullptr, cached->gpu_modified, - cached->ctx == ctx); + " size=0x%016" PRIx64 " duplicate=%d gpu_modified=%d\n", + info.address, info.size, match != nullptr, cached->gpu_modified); } match = cached; } @@ -1552,8 +1548,7 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c m_memory_tracker.ForEachUploadRange( info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { - m_tiler.DetileImage(match->ctx, - static_cast(match->image), + m_tiler.DetileImage(*static_cast(match->image), match->info, source, true, false); }); if (match->info.IsCpuDirty()) { @@ -1561,8 +1556,8 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c } match->buffer_modified = false; } - command->RetainResourceUntilFence(match); - return match->image; + command.RetainResourceUntilFence(match); + return *match->image; } for (const auto& cached: m_images) { if (cached->kind != CachedImage::Kind::Texture) { @@ -1577,36 +1572,32 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c static_cast(cached->kind), info.format, info.width, info.height, info.depth, info.pitch, info.levels, info.tile, info.type); } - const auto overlap = - ClassifySampledOverlap(info, cached->info, cached->gpu_modified, cached->ctx == ctx); + const auto overlap = ClassifySampledOverlap(info, cached->info, cached->gpu_modified); if (overlap == SampledOverlap::Unsupported) { EXIT("TextureCache: unsupported sampled-texture alias, requested=0x%016" PRIx64 - "+0x%016" PRIx64 " existing=0x%016" PRIx64 "+0x%016" PRIx64 - " gpu_modified=%d same_context=%d\n", + "+0x%016" PRIx64 " existing=0x%016" PRIx64 "+0x%016" PRIx64 " gpu_modified=%d\n", info.address, info.size, cached->info.address, cached->info.size, - cached->gpu_modified, cached->ctx == ctx); + cached->gpu_modified); } } m_images.reserve(m_images.size() + 1); - auto cached = std::make_shared(); + auto cached = std::make_shared(m_graphics); cached->kind = CachedImage::Kind::Texture; cached->info = info; - cached->ctx = ctx; vk::ComponentMapping components {}; - cached->image = ImageOps::CreateTexture(ctx, info, false, &components); + cached->image = ImageOps::CreateTexture(info, false, components); m_memory_tracker.ForEachUploadRange( info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { - m_tiler.DetileImage(cached->ctx, static_cast(cached->image), - cached->info, source, false, false); + m_tiler.DetileImage(*static_cast(cached->image), cached->info, + source, false, false); }); - ImageOps::CreateTextureViews(ctx, static_cast(cached->image), info, - false, components); + ImageOps::CreateTextureViews(*static_cast(cached->image), info, false, + components); return PublishImage(command, std::move(cached)); } -StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* command, - GraphicContext* ctx, +StorageTextureVulkanImage& TextureCache::FindStorageTexture(CommandBuffer& command, const ImageInfo& info) { const bool supported_type = info.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) || @@ -1623,13 +1614,13 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com info.tile != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) && !supported_depth_tile) || !IsSupportedStorageSwizzle(info.format, info.swizzle)) { - EXIT("TextureCache: unsupported storage-image request, command=%p ctx=%p " + EXIT("TextureCache: unsupported storage-image request, command=%p " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 " extent=%ux%ux%u levels=%u base_level=%u base_array=%u type=%u tile=%u " "swizzle=0x%03x\n", - static_cast(command), static_cast(ctx), info.address, - info.size, info.width, info.height, info.depth, info.levels, info.base_level, - info.base_array, info.type, info.tile, info.swizzle); + static_cast(&command), info.address, info.size, info.width, info.height, + info.depth, info.levels, info.base_level, info.base_array, info.type, info.tile, + info.swizzle); } if ((info.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && info.depth != 1) || (info.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor3D) && info.depth == 0) || @@ -1653,10 +1644,10 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com } } FaultSafeTextureLock lock(this, m_lock); - ResolveImageMetadataOverlapsLocked(ctx, info.address, info.size); + ResolveImageMetadataOverlapsLocked(info.address, info.size); if (supported_depth_tile && info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt)) { - RetireStorageDepthAliasLocked(ctx, info); + RetireStorageDepthAliasLocked(info); } std::shared_ptr match; @@ -1665,11 +1656,10 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com !EqualStorageBacking(info, cached->info)) { continue; } - if (match != nullptr || cached->ctx != ctx || cached->info.IsCpuDirty()) { + if (match != nullptr || cached->info.IsCpuDirty()) { EXIT("TextureCache: invalid exact storage-image cache match, addr=0x%016" PRIx64 - " size=0x%016" PRIx64 " duplicate=%d same_context=%d cpu_dirty=%d\n", - info.address, info.size, match != nullptr, cached->ctx == ctx, - cached->info.IsCpuDirty()); + " size=0x%016" PRIx64 " duplicate=%d cpu_dirty=%d\n", + info.address, info.size, match != nullptr, cached->info.IsCpuDirty()); } match = cached; } @@ -1695,8 +1685,7 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com m_memory_tracker.ForEachUploadRange( info.address, info.size, true, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { - m_tiler.DetileImage(match->ctx, - static_cast(match->image), + m_tiler.DetileImage(*static_cast(match->image), match->info, source, true, true); }); match->buffer_modified = false; @@ -1707,9 +1696,8 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com info.address, info.size, true, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { m_tiler.DetileImage( - match->ctx, static_cast(match->image), - match->info, {nullptr, 0, match->info.address, match->info.size, true}, - true, true); + *static_cast(match->image), match->info, + {nullptr, 0, match->info.address, match->info.size, true}, true, true); }); } else { // A readback leaves both copies current. Reclaim ownership without an unnecessary @@ -1718,32 +1706,30 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com } match->gpu_modified = true; } - command->RetainResourceUntilFence(match); - return static_cast(match->image); + command.RetainResourceUntilFence(match); + return *static_cast(match->image); } - ResolveStorageImageOverlaps(ctx, info); + ResolveStorageImageOverlaps(info); m_images.reserve(m_images.size() + 1); - auto cached = std::make_shared(); + auto cached = std::make_shared(m_graphics); cached->kind = CachedImage::Kind::StorageTexture; cached->info = info; - cached->ctx = ctx; vk::ComponentMapping components {}; - cached->image = ImageOps::CreateTexture(ctx, info, true, &components); + cached->image = ImageOps::CreateTexture(info, true, components); m_memory_tracker.ForEachUploadRange( info.address, info.size, true, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { - m_tiler.DetileImage(cached->ctx, static_cast(cached->image), - cached->info, source, false, true); + m_tiler.DetileImage(*static_cast(cached->image), cached->info, + source, false, true); }); cached->gpu_modified = true; - ImageOps::CreateTextureViews(ctx, static_cast(cached->image), info, - true, components); - return static_cast(PublishImage(command, std::move(cached))); + ImageOps::CreateTextureViews(*static_cast(cached->image), info, true, + components); + return static_cast(PublishImage(command, std::move(cached))); } -RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* command, - GraphicContext* ctx, +RenderTextureVulkanImage& TextureCache::FindRenderTarget(CommandBuffer& command, const RenderTargetInfo& info) { const bool standard64 = IsSupportedStandard64RenderTarget(info); const bool valid_samples = @@ -1759,18 +1745,17 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* (info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kLinear) && info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) && !standard64)) { - EXIT("TextureCache: invalid render-target request, ctx=%p addr=0x%016" PRIx64 - " size=0x%016" PRIx64 " extent=%ux%u pitch=%u bpe=%u samples=%u tile=%u format=%d\n", - static_cast(ctx), info.address, info.size, info.width, info.height, - info.pitch, info.bytes_per_element, info.samples, info.tile_mode, - static_cast(info.format)); + EXIT("TextureCache: invalid render-target request, addr=0x%016" PRIx64 " size=0x%016" PRIx64 + " extent=%ux%u pitch=%u bpe=%u samples=%u tile=%u format=%d\n", + info.address, info.size, info.width, info.height, info.pitch, info.bytes_per_element, + info.samples, info.tile_mode, static_cast(info.format)); } if (info.levels == 1 && info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget)) { TileSizeAlign layout {}; const auto encoded_samples = static_cast(std::countr_zero(info.samples)); if (!TileGetRenderTargetSize(info.width, info.height, info.pitch, info.bytes_per_element, - &layout, encoded_samples) || + layout, encoded_samples) || layout.size > UINT64_MAX / info.layers || static_cast(layout.size) * info.layers != info.size) { EXIT("TextureCache: invalid render-target block layout, size=0x%016" PRIx64 @@ -1783,7 +1768,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* TileSizeAlign layout {}; if (info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || !TileGetRenderTargetMipLayout(info.width, info.height, info.pitch, - info.bytes_per_element, info.levels, &layout, nullptr, + info.bytes_per_element, info.levels, layout, nullptr, nullptr) || layout.size > UINT64_MAX / info.layers || static_cast(layout.size) * info.layers != info.size) { @@ -1831,7 +1816,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* FaultSafeTextureLock lock(this, m_lock); std::shared_ptr match; for (auto& cached: m_images) { - if (cached->kind != CachedImage::Kind::RenderTarget || cached->ctx != ctx || + if (cached->kind != CachedImage::Kind::RenderTarget || (!Equal(info, cached->target) && !IsCompatibleRenderTargetView(cached->target, info) && !IsCompatibleRenderTargetBacking(cached->target, info))) { continue; @@ -1839,7 +1824,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* match = cached; } if (match != nullptr) { - ResolveImageMetadataOverlapsLocked(ctx, info.address, info.size); + ResolveImageMetadataOverlapsLocked(info.address, info.size); if (info.samples > 1 && (match->buffer_modified || m_memory_tracker.IsRegionCpuModified(info.address, info.size))) { EXIT("TextureCache: multisampled render-target refresh is unsupported, " @@ -1862,12 +1847,12 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { ImageOps::UploadRenderTarget( - ctx, static_cast(match->image), info, true); + *static_cast(match->image), info, true); }); match->buffer_modified = false; } - command->RetainResourceUntilFence(match); - return static_cast(match->image); + command.RetainResourceUntilFence(match); + return *static_cast(match->image); } std::vector retire; std::vector> recreated_depth_sources; @@ -1880,8 +1865,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* RenderTargetOverlap overlap = RenderTargetOverlap::Unsupported; switch (cached.kind) { case CachedImage::Kind::Texture: - overlap = ClassifyRenderTargetOverlap(cached.info, cached.gpu_modified, - cached.ctx == ctx, info); + overlap = ClassifyRenderTargetOverlap(cached.info, cached.gpu_modified, info); break; case CachedImage::Kind::StorageTexture: overlap = ClassifyStorageRenderTargetOverlap( @@ -1889,13 +1873,12 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* cached.info.IsCpuDirty() || m_memory_tracker.IsRegionCpuModified(cached.info.address, cached.info.size), m_memory_tracker.IsRegionGpuModified(cached.info.address, cached.info.size), - cached.ctx == ctx, info); + info); break; case CachedImage::Kind::RenderTarget: overlap = ClassifyRenderTargetOverlap( cached.target, cached.gpu_modified, cached.buffer_modified, m_memory_tracker.IsRegionGpuModified(cached.target.address, cached.target.size), - cached.ctx == ctx, IsCoherentGuestImageSource(target_source, info.address, info.size), info); break; case CachedImage::Kind::DepthTarget: { @@ -1906,7 +1889,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* } if (CanRecreateDepthForRenderTarget( cached.depth, cached.gpu_modified, cached.buffer_modified, - tracker_gpu_modified, cached.ctx == ctx, + tracker_gpu_modified, IsCoherentGuestImageSource(target_source, info.address, info.size), info)) { overlap = RenderTargetOverlap::RetireTarget; } @@ -1951,19 +1934,19 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* if (!supported) { EXIT("TextureCache: unsupported render-target alias, requested=0x%016" PRIx64 "+0x%016" PRIx64 " existing_kind=%u existing=0x%016" PRIx64 "+0x%016" PRIx64 - " gpu_modified=%d same_context=%d" + " gpu_modified=%d" " sampled_format=%u extent=%ux%ux%u pitch=%u levels=%u base_level=%u" " tile=%u type=%u base_array=%u\n", info.address, info.size, static_cast(cached.kind), cached.Address(), - cached.Size(), cached.gpu_modified, cached.ctx == ctx, cached.info.format, - cached.info.width, cached.info.height, cached.info.depth, cached.info.pitch, - cached.info.levels, cached.info.base_level, cached.info.tile, cached.info.type, + cached.Size(), cached.gpu_modified, cached.info.format, cached.info.width, + cached.info.height, cached.info.depth, cached.info.pitch, cached.info.levels, + cached.info.base_level, cached.info.tile, cached.info.type, cached.info.base_array); } retire.push_back(&cached); } RequireRetirementIsolation(retire, "render target", info.address, info.size); - MaterializeImagesToGuestLocked(ctx, recreated_depth_sources); + MaterializeImagesToGuestLocked(recreated_depth_sources); for (const auto& cached: recreated_depth_sources) { // The exact guest range owns the current bytes. Clear a stale buffer marker only after // source-coherence validation so retirement can replace the obsolete Vulkan shape. @@ -1971,15 +1954,14 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* } RetireDepthMetadataLocked(retire); RetireImages(retire, native_image_source.get()); - ResolveImageMetadataOverlapsLocked(ctx, info.address, info.size); - auto cached = std::make_shared(); + ResolveImageMetadataOverlapsLocked(info.address, info.size); + auto cached = std::make_shared(m_graphics); cached->kind = CachedImage::Kind::RenderTarget; cached->target = info; - cached->ctx = ctx; - cached->image = ImageOps::CreateRenderTarget(ctx, info); + cached->image = ImageOps::CreateRenderTarget(info); const bool preserve_native = native_image_source != nullptr; if (preserve_native) { - command->RetainResourceUntilFence(native_image_source); + command.RetainResourceUntilFence(native_image_source); if (native_image_source->kind == CachedImage::Kind::RenderTarget) { const auto& old = native_image_source->target; const auto tail_address = info.address + old.size; @@ -1994,15 +1976,15 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* tail_address, tail_size, true, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { ImageOps::UploadRenderTargetLayers( - ctx, static_cast(cached->image), info, - old.layers, info.layers - old.layers, false); + *static_cast(cached->image), info, old.layers, + info.layers - old.layers, false); }); } std::vector regions; regions.reserve(static_cast(native_image_source->image->layers) * native_image_source->image->mip_levels); - AppendLayerCopies(regions, native_image_source->image, vk::ImageAspectFlagBits::eColor); - Transfer::CopyImage(command, regions, cached->image, RENDER_COLOR_IMAGE_LAYOUT); + AppendLayerCopies(regions, *native_image_source->image, vk::ImageAspectFlagBits::eColor); + Transfer::CopyImage(command, regions, *cached->image, RENDER_COLOR_IMAGE_LAYOUT); } else { if (info.samples > 1) { if (!IsCoherentGuestImageSource(target_source, info.address, info.size) || @@ -2020,15 +2002,15 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { ImageOps::UploadRenderTarget( - ctx, static_cast(cached->image), info, false); + *static_cast(cached->image), info, false); }); } } cached->gpu_modified = preserve_native; - return static_cast(PublishImage(command, std::move(cached))); + return static_cast(PublishImage(command, std::move(cached))); } -DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, GraphicContext* ctx, +DepthStencilVulkanImage& TextureCache::FindDepthTarget(CommandBuffer& command, const DepthTargetInfo& info) { const bool has_stencil = info.stencil_address != 0 || info.stencil_size != 0; const bool has_htile = info.htile_address != 0 || info.htile_size != 0; @@ -2057,14 +2039,14 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G info.htile_address, info.htile_size)))) || (info.stencil_htile_compressed && (!has_stencil || !has_htile)) || !IsSupportedDepthTargetFormat(info)) { - EXIT("TextureCache: unsupported depth target, command=%p ctx=%p depth=0x%016" PRIx64 + EXIT("TextureCache: unsupported depth target, command=%p depth=0x%016" PRIx64 "+0x%016" PRIx64 " stencil=0x%016" PRIx64 "+0x%016" PRIx64 " htile=0x%016" PRIx64 "+0x%016" PRIx64 " extent=%ux%u pitch=%u samples=%u tile=%u format=%d guest_format=%u bpe=%u\n", - static_cast(command), static_cast(ctx), info.address, - info.size, info.stencil_address, info.stencil_size, info.htile_address, - info.htile_size, info.width, info.height, info.pitch, info.samples, info.tile_mode, - static_cast(info.format), info.guest_format, info.bytes_per_element); + static_cast(&command), info.address, info.size, info.stencil_address, + info.stencil_size, info.htile_address, info.htile_size, info.width, info.height, + info.pitch, info.samples, info.tile_mode, static_cast(info.format), + info.guest_format, info.bytes_per_element); } const auto* depth_policy = FindGuestDepthFormatPolicy(info.guest_format); TileSizeAlign expected_depth {}; @@ -2077,7 +2059,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G info.width, info.height, 0, Prospero::GpuEnumValue(depth_policy->depth_format), Prospero::GpuEnumValue(has_stencil ? Prospero::StencilFormat::k8UInt : Prospero::StencilFormat::kInvalid), - has_htile, &expected_stencil, &expected_htile, &expected_depth, encoded_samples) || + has_htile, expected_stencil, expected_htile, expected_depth, encoded_samples) || expected_depth.size > UINT64_MAX / info.layers || static_cast(expected_depth.size) * info.layers != info.size || (has_stencil && @@ -2117,7 +2099,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G info.stencil_address, info.stencil_size, info.htile_address, info.htile_size); } if (has_htile) { - RegisterMeta(ctx, info.htile_address, info.htile_size, info.layers); + RegisterMeta(info.htile_address, info.htile_size, info.layers); } std::lock_guard transaction(m_resource_mutex); // BufferCache treats an untracked guest range as CPU-current. That is useful when @@ -2129,13 +2111,13 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G has_stencil ? m_buffer_cache.ObtainBufferForImage(info.stencil_address, info.stencil_size) : BufferImageCopySource {}; FaultSafeTextureLock lock(this, m_lock); - ResolveImageMetadataOverlapsLocked(ctx, info.address, info.size); + ResolveImageMetadataOverlapsLocked(info.address, info.size); if (has_stencil) { - ResolveImageMetadataOverlapsLocked(ctx, info.stencil_address, info.stencil_size); + ResolveImageMetadataOverlapsLocked(info.stencil_address, info.stencil_size); } std::shared_ptr match; for (auto& cached: m_images) { - if (cached->kind != CachedImage::Kind::DepthTarget || cached->ctx != ctx || + if (cached->kind != CachedImage::Kind::DepthTarget || (!Equal(info, cached->depth) && !IsCompatibleDepthTargetBacking(cached->depth, info))) { continue; } @@ -2177,8 +2159,8 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G m_memory_tracker.ForEachUploadRange( info.address, info.size, true, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { - m_tiler.DetileImage(ctx, static_cast(match->image), - info, depth_source, true); + m_tiler.DetileImage(*static_cast(match->image), info, + depth_source, true); }); match->buffer_modified = false; match->gpu_modified = true; @@ -2186,8 +2168,8 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G m_memory_tracker.ForEachUploadRange( info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { - m_tiler.DetileImage(ctx, static_cast(match->image), - info, depth_source, true); + m_tiler.DetileImage(*static_cast(match->image), info, + depth_source, true); }); } if (!match->gpu_modified && has_stencil && stencil_source.cpu_dirty) { @@ -2195,15 +2177,14 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G info.stencil_address, info.stencil_size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { if (!info.stencil_load_clear) { - m_tiler.DetileStencil(ctx, - static_cast(match->image), + m_tiler.DetileStencil(*static_cast(match->image), info, stencil_source, true); match->stencil_initialized = true; } }); } - command->RetainResourceUntilFence(match); - return static_cast(match->image); + command.RetainResourceUntilFence(match); + return *static_cast(match->image); } std::vector retire; std::shared_ptr sampled_depth_source; @@ -2223,8 +2204,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G switch (cached.kind) { case CachedImage::Kind::Texture: { const auto native_overlap = - cached.ctx == ctx ? ClassifyDepthOverlap(cached.info, cached.gpu_modified, info) - : DepthOverlap::Unsupported; + ClassifyDepthOverlap(cached.info, cached.gpu_modified, info); const bool overlaps_depth = ImageRangeOverlaps( cached.info.address, cached.info.size, info.address, info.size); const bool overlaps_stencil = @@ -2242,7 +2222,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G cached.info, info, cached.gpu_modified, cached.buffer_modified, cached.info.IsCpuDirty(), m_memory_tracker.IsRegionGpuModified(cached.info.address, cached.info.size), - cached.ctx == ctx, guest_source_current)) { + guest_source_current)) { overlap = DepthOverlap::RetireSampled; } if (overlap == DepthOverlap::RetireSampled && !info.depth_load_clear && @@ -2252,9 +2232,8 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G } } break; case CachedImage::Kind::DepthTarget: - overlap = - ClassifyDepthTargetOverlap(cached.depth, cached.gpu_modified, - cached.buffer_modified, cached.ctx == ctx, info); + overlap = ClassifyDepthTargetOverlap(cached.depth, cached.gpu_modified, + cached.buffer_modified, info); break; case CachedImage::Kind::StorageTexture: overlap = ClassifyStorageDepthOverlap( @@ -2262,7 +2241,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G cached.info.IsCpuDirty() || m_memory_tracker.IsRegionCpuModified(cached.info.address, cached.info.size), m_memory_tracker.IsRegionGpuModified(cached.info.address, cached.info.size), - cached.ctx == ctx, info); + info); break; case CachedImage::Kind::RenderTarget: { const bool overlaps_depth = ImageRangeOverlaps( @@ -2280,7 +2259,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G cached.target, cached.gpu_modified, cached.buffer_modified, m_memory_tracker.IsRegionGpuModified(cached.target.address, cached.target.size), - cached.ctx == ctx, guest_source_current, info) + guest_source_current, info) ? DepthOverlap::RecreateTarget : DepthOverlap::Unsupported; } break; @@ -2337,7 +2316,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G retire.push_back(&cached); } RequireRetirementIsolation(retire, "depth target", info.address, info.size); - MaterializeImagesToGuestLocked(ctx, recreated_target_sources); + MaterializeImagesToGuestLocked(recreated_target_sources); if (retired_storage_source != nullptr) { if (retired_storage_source->gpu_modified) { m_memory_tracker.UnmarkRegionAsGpuModified(retired_storage_source->info.address, @@ -2384,20 +2363,19 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G "addr=0x%016" PRIx64 " size=0x%016" PRIx64 " samples=%u\n", info.stencil_address, info.stencil_size, info.samples); } - auto cached = std::make_shared(); + auto cached = std::make_shared(m_graphics); cached->kind = CachedImage::Kind::DepthTarget; cached->depth = info; - cached->ctx = ctx; cached->stencil_initialized = !has_stencil || info.stencil_load_clear || initial_stencil_clear; - cached->image = ImageOps::CreateDepthTarget(ctx, info); + cached->image = ImageOps::CreateDepthTarget(info); auto* depth_image = static_cast(cached->image); depth_image->initial_depth_clear_pending = initial_depth_clear; depth_image->initial_stencil_clear_pending = initial_stencil_clear; if (discarded_depth_source != nullptr) { - command->RetainResourceUntilFence(discarded_depth_source); + command.RetainResourceUntilFence(discarded_depth_source); } if (retired_storage_source != nullptr) { - command->RetainResourceUntilFence(retired_storage_source); + command.RetainResourceUntilFence(retired_storage_source); } if (native_depth_source != nullptr) { const auto& old = native_depth_source->depth; @@ -2405,7 +2383,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G EXIT("TextureCache: invalid depth expansion source, old_layers=%u new_layers=%u\n", old.layers, info.layers); } - command->RetainResourceUntilFence(native_depth_source); + command.RetainResourceUntilFence(native_depth_source); const auto tail = SelectDepthLayers(info, old.layers, info.layers - old.layers); const auto depth_tail = SelectSourceRange(depth_source, tail.address, tail.size); if (!info.depth_load_clear && @@ -2416,8 +2394,8 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G tail.address, tail.size, true, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { if (!info.depth_load_clear) { - m_tiler.DetileImage(ctx, static_cast(cached->image), - tail, depth_tail, false, old.layers); + m_tiler.DetileImage(*static_cast(cached->image), tail, + depth_tail, false, old.layers); } }); if (has_stencil) { @@ -2432,8 +2410,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G tail.stencil_address, tail.stencil_size, true, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { if (!info.stencil_load_clear) { - m_tiler.DetileStencil(ctx, - static_cast(cached->image), + m_tiler.DetileStencil(*static_cast(cached->image), tail, stencil_tail, false, old.layers); } }); @@ -2441,12 +2418,12 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G } std::vector regions; regions.reserve(native_depth_source->image->layers * (has_stencil ? 2u : 1u)); - AppendLayerCopies(regions, native_depth_source->image, vk::ImageAspectFlagBits::eDepth); + AppendLayerCopies(regions, *native_depth_source->image, vk::ImageAspectFlagBits::eDepth); if (has_stencil) { - AppendLayerCopies(regions, native_depth_source->image, + AppendLayerCopies(regions, *native_depth_source->image, vk::ImageAspectFlagBits::eStencil); } - Transfer::CopyImage(command, regions, cached->image, + Transfer::CopyImage(command, regions, *cached->image, vk::ImageLayout::eDepthStencilAttachmentOptimal); cached->gpu_modified = true; } else { @@ -2461,7 +2438,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G info.stencil_address, info.stencil_size, false, [](uint64_t, uint64_t) noexcept {}, []() noexcept {}); } - return static_cast(PublishImage(command, std::move(cached))); + return static_cast(PublishImage(command, std::move(cached))); } if (sampled_depth_source != nullptr && (sampled_depth_source->image->type != VulkanImageType::Texture || @@ -2481,16 +2458,14 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G switch (transition_source) { case DepthTransitionSource::None: break; case DepthTransitionSource::Guest: - m_tiler.DetileImage(ctx, - static_cast(cached->image), + m_tiler.DetileImage(*static_cast(cached->image), info, depth_source, false); break; case DepthTransitionSource::Native: - command->RetainResourceUntilFence(sampled_depth_source); + command.RetainResourceUntilFence(sampled_depth_source); Transfer::CopyImageViaBuffer( - command, ctx, sampled_depth_source->image, - vk::ImageAspectFlagBits::eColor, cached->image, - vk::ImageAspectFlagBits::eDepth, info.bytes_per_element, + command, *sampled_depth_source->image, vk::ImageAspectFlagBits::eColor, + *cached->image, vk::ImageAspectFlagBits::eDepth, info.bytes_per_element, vk::ImageLayout::eDepthStencilAttachmentOptimal); break; } @@ -2500,25 +2475,23 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G info.stencil_address, info.stencil_size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { if (!info.stencil_load_clear) { - m_tiler.DetileStencil(ctx, - static_cast(cached->image), + m_tiler.DetileStencil(*static_cast(cached->image), info, stencil_source, false); } }); cached->stencil_initialized = true; } } - return static_cast(PublishImage(command, std::move(cached))); + return static_cast(PublishImage(command, std::move(cached))); } std::vector -TextureCache::RegisterVideoOutSurfaces(GraphicContext* ctx, - const std::vector& infos) { +TextureCache::RegisterVideoOutSurfaces(const std::vector& infos) { if (infos.empty()) { EXIT("TextureCache: video-out registration requires surfaces\n"); } for (const auto& info: infos) { - ImageOps::ValidateVideoOut(ctx, info); + ImageOps::ValidateVideoOut(info); } for (size_t i = 0; i < infos.size(); i++) { for (size_t j = i + 1; j < infos.size(); j++) { @@ -2538,7 +2511,7 @@ TextureCache::RegisterVideoOutSurfaces(GraphicContext* ctx, } FaultSafeTextureLock lock(this, m_lock); for (const auto& info: infos) { - ResolveImageMetadataOverlapsLocked(ctx, info.address, info.size); + ResolveImageMetadataOverlapsLocked(info.address, info.size); for (const auto& cached: m_images) { if (cached->OverlapsRange(info.address, info.size, true)) { EXIT( @@ -2552,16 +2525,15 @@ TextureCache::RegisterVideoOutSurfaces(GraphicContext* ctx, std::vector result; result.reserve(infos.size()); for (const auto& info: infos) { - auto cached = std::make_shared(); + auto cached = std::make_shared(m_graphics); cached->kind = CachedImage::Kind::VideoOut; cached->video_out = info; - cached->ctx = ctx; - cached->image = ImageOps::CreateVideoOut(ctx, info); + cached->image = ImageOps::CreateVideoOut(info); if (info.compression == VideoOutCompression::Uncompressed) { m_memory_tracker.ForEachUploadRange( info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { - ImageOps::UploadVideoOut(ctx, static_cast(cached->image), + ImageOps::UploadVideoOut(*static_cast(cached->image), info, false); }); } else { @@ -2579,18 +2551,14 @@ TextureCache::RegisterVideoOutSurfaces(GraphicContext* ctx, return result; } -void TextureCache::RefreshVideoOut(VideoOutVulkanImage* image, bool render_target) { - if (image == nullptr) { - EXIT("TextureCache: invalid video-out refresh, image=%p\n", - static_cast(image)); - } +void TextureCache::RefreshVideoOut(VideoOutVulkanImage& image, bool render_target) { std::lock_guard transaction(m_resource_mutex); FaultSafeTextureLock lock(this, m_lock); const auto it = std::find_if(m_images.begin(), m_images.end(), - [image](const auto& cached) { return cached->image == image; }); + [&image](const auto& cached) { return cached->image == ℑ }); if (it == m_images.end() || (*it)->kind != CachedImage::Kind::VideoOut) { EXIT("TextureCache: video-out image is not registered, image=%p\n", - static_cast(image)); + static_cast(&image)); } auto& cached = **it; if (cached.gpu_modified) { @@ -2631,7 +2599,7 @@ void TextureCache::RefreshVideoOut(VideoOutVulkanImage* image, bool render_targe } m_memory_tracker.ForEachUploadRange( info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, - [&]() noexcept { ImageOps::UploadVideoOut(cached.ctx, image, info, true); }); + [&]() noexcept { ImageOps::UploadVideoOut(image, info, true); }); } void TextureCache::UnregisterVideoOutSurfaces(const std::vector& images) { @@ -2657,19 +2625,14 @@ void TextureCache::UnregisterVideoOutSurfaces(const std::vectorget()); } - GraphicContext* ctx = selected.front()->ctx; for (auto* cached: selected) { - if (cached->ctx != ctx) { - EXIT("TextureCache: video-out surfaces span graphics contexts, expected=%p actual=%p\n", - static_cast(ctx), static_cast(cached->ctx)); - } if (cached->buffer_modified) { EXIT("TextureCache: cannot unregister a buffer-dirty video-out surface, " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", cached->Address(), cached->Size()); } } - Transfer::WaitForGraphicsIdle(ctx); + Transfer::WaitForGraphicsIdle(); for (auto* cached: selected) { if (cached->gpu_modified) { m_memory_tracker.UnmarkRegionAsGpuModified(cached->Address(), cached->Size()); @@ -2684,13 +2647,13 @@ void TextureCache::UnregisterVideoOutSurfaces(const std::vectorIsInvalid() || vaddr == 0 || size == 0 || - vaddr >= TRACKER_ADDRESS_SIZE || size > TRACKER_ADDRESS_SIZE - vaddr) { + if (command.IsInvalid() || vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || + size > TRACKER_ADDRESS_SIZE - vaddr) { EXIT("TextureCache: invalid compute image clear, command=%p addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", - static_cast(command), vaddr, size); + static_cast(&command), vaddr, size); } m_buffer_cache.ValidateGpuAccess(vaddr, size, false, true); std::lock_guard transaction(m_resource_mutex); @@ -2747,11 +2710,11 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr, float depth_clear = 0.0f; if (aspect == ClearAspect::Depth && - !DecodePackedDepthClear(match->image->format, packed_clear, &depth_clear)) { + !DecodePackedDepthClear(match->image->format, packed_clear, depth_clear)) { return false; } uint8_t stencil_clear = 0; - if (aspect == ClearAspect::Stencil && !DecodePackedStencilClear(packed_clear, &stencil_clear)) { + if (aspect == ClearAspect::Stencil && !DecodePackedStencilClear(packed_clear, stencil_clear)) { return false; } @@ -2791,23 +2754,23 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr, image_cpu_modified); } - auto vk_buffer = command->Handle(); + auto vk_buffer = command.Handle(); if (aspect == ClearAspect::Color) { vk::ClearColorValue clear {}; - if (!DecodePackedColorClear(match->image->format, packed_clear, &clear)) { + if (!DecodePackedColorClear(match->image->format, packed_clear, clear)) { return false; } - GraphicsRenderColorImageBarrier(vk_buffer, match->image, + GraphicsRenderColorImageBarrier(vk_buffer, *match->image, vk::ImageLayout::eTransferDstOptimal); const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, VK_REMAINING_MIP_LEVELS, 0, match->image->layers}; vk_buffer.clearColorImage(match->image->image, match->image->layout, &clear, 1, &range); - GraphicsRenderColorImageBarrier(vk_buffer, match->image, RENDER_COLOR_IMAGE_LAYOUT); + GraphicsRenderColorImageBarrier(vk_buffer, *match->image, RENDER_COLOR_IMAGE_LAYOUT); if (!match->gpu_modified) { m_memory_tracker.MarkRegionAsGpuModified(vaddr, size); match->gpu_modified = true; } - command->RetainResourceUntilFence(match); + command.RetainResourceUntilFence(match); return true; } @@ -2818,7 +2781,7 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr, static_cast(match->image->layout)); } const auto old_layout = match->image->layout; - GraphicsRenderDepthStencilImageBarrier(vk_buffer, match->image, + GraphicsRenderDepthStencilImageBarrier(vk_buffer, *match->image, vk::ImageLayout::eTransferDstOptimal); const vk::ClearDepthStencilValue clear {depth_clear, stencil_clear}; const auto clear_aspect = static_cast( @@ -2827,30 +2790,26 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr, const vk::ImageSubresourceRange range {clear_aspect, 0, VK_REMAINING_MIP_LEVELS, 0, match->image->layers}; vk_buffer.clearDepthStencilImage(match->image->image, match->image->layout, &clear, 1, &range); - GraphicsRenderDepthStencilImageBarrier(vk_buffer, match->image, old_layout); + GraphicsRenderDepthStencilImageBarrier(vk_buffer, *match->image, old_layout); if (aspect == ClearAspect::Stencil) { match->stencil_initialized = true; } - command->RetainResourceUntilFence(match); + command.RetainResourceUntilFence(match); return true; } -void TextureCache::MarkGpuWritten(VulkanImage* image) { - if (image == nullptr) { - EXIT("TextureCache: invalid GPU-write notification, image=%p\n", - static_cast(image)); - } +void TextureCache::MarkGpuWritten(VulkanImage& image) { std::lock_guard transaction(m_resource_mutex); FaultSafeTextureLock lock(this, m_lock); for (auto& cached: m_images) { - if (cached->image != image) { + if (cached->image != &image) { continue; } if (cached->kind != CachedImage::Kind::RenderTarget && cached->kind != CachedImage::Kind::DepthTarget && cached->kind != CachedImage::Kind::VideoOut) { EXIT("TextureCache: sampled texture cannot be marked GPU-written, image=%p kind=%u\n", - static_cast(image), static_cast(cached->kind)); + static_cast(&image), static_cast(cached->kind)); } for (uint32_t i = 0; i < cached->RangeCount(); i++) { if (m_buffer_cache.HasPageOverlap(cached->Address(i), cached->Size(i))) { @@ -2902,7 +2861,7 @@ void TextureCache::MarkGpuWritten(VulkanImage* image) { return; } EXIT("TextureCache: GPU-written image is not registered, image=%p\n", - static_cast(image)); + static_cast(&image)); } void TextureCache::PrepareHostWrite(uint64_t vaddr, uint64_t size) { @@ -2989,13 +2948,13 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint single_slice = true; } else { single_slice = TileGetRenderTargetSize(target.width, target.height, target.pitch, - target.bytes_per_element, &exact); + target.bytes_per_element, exact); } const bool layered_size = single_slice && static_cast(exact.size) * target.layers == target.size; if (storage && target.levels > 1) { single_slice = TileGetRenderTargetMipLayout(target.width, target.height, target.pitch, - target.bytes_per_element, target.levels, &exact, + target.bytes_per_element, target.levels, exact, nullptr, nullptr); } const bool exact_tiled = tiled && exact.align == 65536 && @@ -3033,7 +2992,7 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint target.address, target.size); } - Transfer::WaitForGraphicsIdle(cached.ctx); + Transfer::WaitForGraphicsIdle(); std::vector regions; std::vector tiled_regions; TextureUploadLayout tiled_layout {}; @@ -3068,32 +3027,30 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint std::vector infos; const uint32_t depth = storage ? cached.info.depth : target.layers; EXIT_NOT_IMPLEMENTED(!TextureBuildGpuTileInfos(target.size, tiled_regions, tiled_layout, - tiled_format, depth, target.levels, &infos)); + tiled_format, depth, target.levels, infos)); m_buffer_transition_guest.resize(target.size); - Transfer::DownloadTiledImage(cached.ctx, m_buffer_transition_guest.data(), target.size, - target.size, infos, regions, cached.image, - cached.image->layout); + Transfer::DownloadTiledImage(m_buffer_transition_guest.data(), target.size, target.size, + infos, regions, *cached.image, cached.image->layout); Libs::LibKernel::Memory::WriteBacking(target.address, m_buffer_transition_guest.data(), target.size); } else if (tiled) { std::vector linear_data(target.size); - Transfer::DownloadImage(cached.ctx, linear_data.data(), target.size, regions, cached.image, + Transfer::DownloadImage(linear_data.data(), target.size, regions, *cached.image, cached.image->layout); ImageOps::SwapVideoOutBgra16(linear_data.data(), target.size); TileBlockLayout block {}; EXIT_NOT_IMPLEMENTED(!TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, - target.bytes_per_element, &block)); + target.bytes_per_element, block)); const GpuTileInfo info { block.family, block.bytes_per_element, 0, target.size, 0, target.size, 0, target.width, target.height, 1, target.pitch}; m_buffer_transition_guest.resize(target.size); - GpuTile(cached.ctx, linear_data.data(), m_buffer_transition_guest.data(), target.size, - target.size, std::span(&info, 1)); + GpuTile(linear_data.data(), m_buffer_transition_guest.data(), target.size, target.size, + std::span(&info, 1)); Libs::LibKernel::Memory::WriteBacking(target.address, m_buffer_transition_guest.data(), target.size); } else { - Transfer::ProcessDownloadedImage(cached.ctx, target.size, regions, cached.image, - cached.image->layout, + Transfer::ProcessDownloadedImage(target.size, regions, *cached.image, cached.image->layout, [&](std::span linear_data) { Libs::LibKernel::Memory::WriteBacking( target.address, linear_data.data(), target.size); @@ -3124,12 +3081,11 @@ void TextureCache::SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) && info.format == vk::Format::eD32Sfloat && info.bytes_per_element == 4; const bool layout = - (d16 || d32) && - TileGetDepthSize(info.width, info.height, 0, - Prospero::GpuEnumValue(d16 ? Prospero::DepthFormat::kZ16 - : Prospero::DepthFormat::kZ32F), - Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid), false, - &expected_stencil, &expected_htile, &expected_depth); + (d16 || d32) && TileGetDepthSize(info.width, info.height, 0, + Prospero::GpuEnumValue(d16 ? Prospero::DepthFormat::kZ16 + : Prospero::DepthFormat::kZ32F), + Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid), + false, expected_stencil, expected_htile, expected_depth); if (cached.kind != CachedImage::Kind::DepthTarget || !cached.gpu_modified || cached.buffer_modified || write_address != info.address || write_size != info.size || has_stencil || has_htile || info.layers != 1 || !layout || expected_depth.align != 65536 || @@ -3144,12 +3100,12 @@ void TextureCache::SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint info.layers, static_cast(info.format), info.guest_format, info.bytes_per_element, has_stencil, has_htile, cached.gpu_modified, cached.buffer_modified); } - Transfer::WaitForGraphicsIdle(cached.ctx); + Transfer::WaitForGraphicsIdle(); const auto regions = Transfer::MakeLayeredImageBufferCopies( 1, info.size, info.pitch, info.width, info.height, vk::ImageAspectFlagBits::eDepth); TileBlockLayout block {}; EXIT_NOT_IMPLEMENTED( - !TileGetBlockLayout(TileBlockFamily::Depth64KB, info.bytes_per_element, &block)); + !TileGetBlockLayout(TileBlockFamily::Depth64KB, info.bytes_per_element, block)); const GpuTileInfo tile_info {block.family, block.bytes_per_element, 0, @@ -3162,9 +3118,9 @@ void TextureCache::SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint 1, info.pitch}; m_buffer_transition_guest.resize(info.size); - Transfer::DownloadTiledImage(cached.ctx, m_buffer_transition_guest.data(), info.size, info.size, - std::span(&tile_info, 1), regions, cached.image, - cached.image->layout); + Transfer::DownloadTiledImage(m_buffer_transition_guest.data(), info.size, info.size, + std::span(&tile_info, 1), regions, + *cached.image, cached.image->layout); Libs::LibKernel::Memory::WriteBacking(info.address, m_buffer_transition_guest.data(), info.size); m_memory_tracker.ForEachDownloadRange(info.address, info.size, @@ -3249,10 +3205,10 @@ bool TextureCache::InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size, return false; } -DepthStencilVulkanImage* TextureCache::FindDepthTargetByRange(CommandBuffer* command, +DepthStencilVulkanImage* TextureCache::FindDepthTargetByRange(CommandBuffer& command, uint64_t vaddr, uint64_t size, bool allow_containing_sampled) { - if (command == nullptr || vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || + if (vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || size > TRACKER_ADDRESS_SIZE - vaddr) { EXIT("TextureCache: invalid depth-target range query, addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", @@ -3294,13 +3250,13 @@ DepthStencilVulkanImage* TextureCache::FindDepthTargetByRange(CommandBuffer* com if (owner == m_images.end()) { EXIT("TextureCache: page-table depth target has no cache owner\n"); } - command->RetainResourceUntilFence(*owner); + command.RetainResourceUntilFence(*owner); return static_cast(found->image); } -RenderTextureVulkanImage* TextureCache::FindRenderTargetByRange(CommandBuffer* command, +RenderTextureVulkanImage* TextureCache::FindRenderTargetByRange(CommandBuffer& command, uint64_t vaddr, uint64_t size) { - if (command == nullptr || vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || + if (vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || size > TRACKER_ADDRESS_SIZE - vaddr) { EXIT("TextureCache: invalid render-target range query, addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", @@ -3336,7 +3292,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTargetByRange(CommandBuffer* c if (owner == m_images.end()) { EXIT("TextureCache: page-table render target has no cache owner\n"); } - command->RetainResourceUntilFence(*owner); + command.RetainResourceUntilFence(*owner); return static_cast(found->image); } @@ -3365,8 +3321,8 @@ TextureCache::RegionInfo TextureCache::QueryRegion(uint64_t vaddr, uint64_t size return result; } -bool TextureCache::ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo* info) { - if (info == nullptr || vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || +bool TextureCache::ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo& info) { + if (vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || size > TRACKER_ADDRESS_SIZE - vaddr) { return false; } @@ -3400,13 +3356,12 @@ bool TextureCache::ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo matched = true; } if (matched) { - *info = found; + info = found; } return matched; } -void TextureCache::RegisterMeta(GraphicContext* ctx, uint64_t vaddr, uint64_t size, - uint32_t layers) { +void TextureCache::RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers) { if (vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || size > TRACKER_ADDRESS_SIZE - vaddr || (vaddr & 0x7fffu) != 0 || layers == 0 || layers > 32 || size % layers != 0) { @@ -3467,15 +3422,14 @@ void TextureCache::RegisterMeta(GraphicContext* ctx, uint64_t vaddr, uint64_t si cached->kind == CachedImage::Kind::StorageTexture && (cached->info.IsCpuDirty() || m_memory_tracker.IsRegionCpuModified(cached->info.address, cached->info.size)); - const auto overlap = - ClassifyMetaImageOverlap(sampled, writable_image, gpu_modified, cached->buffer_modified, - cpu_dirty, cached->ctx == ctx); + const auto overlap = ClassifyMetaImageOverlap(sampled, writable_image, gpu_modified, + cached->buffer_modified, cpu_dirty); if (overlap == MetaImageOverlap::Unsupported) { EXIT("TextureCache: metadata aliases image pages, addr=0x%016" PRIx64 " size=0x%016" PRIx64 " image_kind=%u image=0x%016" PRIx64 "+0x%016" PRIx64 - " gpu_modified=%d buffer_modified=%d same_context=%d\n", + " gpu_modified=%d buffer_modified=%d\n", range_vaddr, range_size, static_cast(cached->kind), cached->Address(), - cached->Size(), cached->gpu_modified, cached->buffer_modified, cached->ctx == ctx); + cached->Size(), cached->gpu_modified, cached->buffer_modified); } if (overlap == MetaImageOverlap::RetireImage) { retire.push_back(cached.get()); @@ -3551,8 +3505,7 @@ void TextureCache::RequireNoMetaOverlapLocked(uint64_t vaddr, uint64_t size) con } } -void TextureCache::ResolveImageMetadataOverlapsLocked(GraphicContext* ctx, uint64_t vaddr, - uint64_t size) { +void TextureCache::ResolveImageMetadataOverlapsLocked(uint64_t vaddr, uint64_t size) { std::vector retire; for (const auto& [address, meta]: m_surface_metas) { if (!ImagePageRangesOverlap(vaddr, size, address, meta.size)) { @@ -3575,14 +3528,13 @@ void TextureCache::ResolveImageMetadataOverlapsLocked(GraphicContext* ctx, uint6 if (cached->depth.htile_size != meta.size || !CanRetireGuestCurrentDepthForMetadataReuse( cached->gpu_modified, cached->buffer_modified, tracker_gpu_modified, - meta.gpu_modified, metadata_tracker_gpu_modified, meta.clear_mask, - cached->ctx == ctx)) { + meta.gpu_modified, metadata_tracker_gpu_modified, meta.clear_mask)) { EXIT("TextureCache: image range overlaps owned metadata, image=0x%016" PRIx64 "+0x%016" PRIx64 " metadata=0x%016" PRIx64 "+0x%016" PRIx64 - " layers=%u clear=0x%08x same_context=%d gpu=%d/%d/%d buffer=%d\n", + " layers=%u clear=0x%08x gpu=%d/%d/%d buffer=%d\n", vaddr, size, address, meta.size, meta.layers, meta.clear_mask, - cached->ctx == ctx, cached->gpu_modified, tracker_gpu_modified, - metadata_tracker_gpu_modified, cached->buffer_modified); + cached->gpu_modified, tracker_gpu_modified, metadata_tracker_gpu_modified, + cached->buffer_modified); } if (std::find(retire.begin(), retire.end(), cached.get()) == retire.end()) { retire.push_back(cached.get()); @@ -3831,18 +3783,14 @@ void TextureCache::UnmapMemory(uint64_t vaddr, uint64_t size) { " retained=0x%016" PRIx64 "+0x%016" PRIx64 "\n", vaddr, size, retired.address, retired.size, retained.address, retained.size); } - GraphicContext* wait_ctx = nullptr; + bool wait_idle = false; for (auto& cached: m_images) { if (cached->OverlapsRange(vaddr, size, false)) { - if (wait_ctx != nullptr && wait_ctx != cached->ctx) { - EXIT("TextureCache: unmap spans multiple graphics contexts, first=%p second=%p\n", - static_cast(wait_ctx), static_cast(cached->ctx)); - } - wait_ctx = cached->ctx; + wait_idle = true; } } - if (wait_ctx != nullptr) { - Transfer::WaitForGraphicsIdle(wait_ctx); + if (wait_idle) { + Transfer::WaitForGraphicsIdle(); } for (auto& cached: m_images) { if (!cached->OverlapsRange(vaddr, size, false) || !cached->gpu_modified) { @@ -3887,16 +3835,14 @@ void TextureCache::UnmapMemory(uint64_t vaddr, uint64_t size) { } } -VulkanImage* TextureCache::GetDummySampledTexture(bool uint_format, bool image_3d) { +VulkanImage& TextureCache::GetDummySampledTexture(bool uint_format, bool image_3d) { KYTY_PROFILER_BLOCK("TextureCache::GetDummySampledTexture"); - return m_dummy_textures->Get(g_render_ctx->GetGraphicCtx(), DummyTextureCache::Usage::Sampled, - uint_format, image_3d); + return m_dummy_textures->Get(DummyTextureCache::Usage::Sampled, uint_format, image_3d); } -VulkanImage* TextureCache::GetDummyStorageTexture(bool uint_format, bool image_3d) { +VulkanImage& TextureCache::GetDummyStorageTexture(bool uint_format, bool image_3d) { KYTY_PROFILER_BLOCK("TextureCache::GetDummyStorageTexture"); - return m_dummy_textures->Get(g_render_ctx->GetGraphicCtx(), DummyTextureCache::Usage::Storage, - uint_format, image_3d); + return m_dummy_textures->Get(DummyTextureCache::Usage::Storage, uint_format, image_3d); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/textureCache.h b/src/graphics/host_gpu/renderer/textureCache.h index d9d7c2d47..d79bacfcf 100644 --- a/src/graphics/host_gpu/renderer/textureCache.h +++ b/src/graphics/host_gpu/renderer/textureCache.h @@ -53,77 +53,71 @@ public: bool full = false; }; - TextureCache(PageManager& page_manager, BufferCache& buffer_cache, + TextureCache(GraphicContext& graphics, PageManager& page_manager, BufferCache& buffer_cache, ResourceMutex& resource_mutex); ~TextureCache(); KYTY_CLASS_NO_COPY(TextureCache); - [[nodiscard]] VulkanImage* FindTexture(CommandBuffer* command, GraphicContext* ctx, - const ImageInfo& info, bool metadata_read); - [[nodiscard]] StorageTextureVulkanImage* - FindStorageTexture(CommandBuffer* command, GraphicContext* ctx, const ImageInfo& info); - [[nodiscard]] RenderTextureVulkanImage* - FindRenderTarget(CommandBuffer* command, GraphicContext* ctx, const RenderTargetInfo& info); - [[nodiscard]] DepthStencilVulkanImage* - FindDepthTarget(CommandBuffer* command, GraphicContext* ctx, const DepthTargetInfo& info); + [[nodiscard]] VulkanImage& FindTexture(CommandBuffer& command, const ImageInfo& info, + bool metadata_read); + [[nodiscard]] StorageTextureVulkanImage& FindStorageTexture(CommandBuffer& command, + const ImageInfo& info); + [[nodiscard]] RenderTextureVulkanImage& FindRenderTarget(CommandBuffer& command, + const RenderTargetInfo& info); + [[nodiscard]] DepthStencilVulkanImage& FindDepthTarget(CommandBuffer& command, + const DepthTargetInfo& info); [[nodiscard]] std::vector - RegisterVideoOutSurfaces(GraphicContext* ctx, const std::vector& infos); - void RefreshVideoOut(VideoOutVulkanImage* image, bool render_target = false); - void UnregisterVideoOutSurfaces(const std::vector& images); - [[nodiscard]] bool ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, + RegisterVideoOutSurfaces(const std::vector& infos); + void RefreshVideoOut(VideoOutVulkanImage& image, bool render_target = false); + void UnregisterVideoOutSurfaces(const std::vector& images); + [[nodiscard]] bool ClearImageFromBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size, uint32_t packed_clear); - void MarkGpuWritten(VulkanImage* image); + void MarkGpuWritten(VulkanImage& image); void PrepareHostWrite(uint64_t vaddr, uint64_t size); [[nodiscard]] bool InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size, bool formatted_buffer_write = false); - [[nodiscard]] RenderTextureVulkanImage* FindRenderTargetByRange(CommandBuffer* command, + [[nodiscard]] RenderTextureVulkanImage* FindRenderTargetByRange(CommandBuffer& command, uint64_t vaddr, uint64_t size); - [[nodiscard]] vk::ImageView GetRenderTargetAttachmentView(GraphicContext* ctx, - RenderTextureVulkanImage* image, + [[nodiscard]] vk::ImageView GetRenderTargetAttachmentView(RenderTextureVulkanImage& image, vk::Format format, uint32_t level, uint32_t base_layer, uint32_t layer_count); - [[nodiscard]] vk::ImageView GetDepthTargetAttachmentView(GraphicContext* ctx, - DepthStencilVulkanImage* image, + [[nodiscard]] vk::ImageView GetDepthTargetAttachmentView(DepthStencilVulkanImage& image, uint32_t base_layer, uint32_t layer_count); [[nodiscard]] vk::ImageView - GetDepthTargetSampledView(GraphicContext* ctx, DepthStencilVulkanImage* image, - vk::Format view_format, uint32_t swizzle, uint32_t base_level, - uint32_t level_count, vk::ImageViewType type, uint32_t base_layer, - uint32_t layer_count); - [[nodiscard]] vk::ImageView GetSampledColorView(GraphicContext* ctx, VulkanImage* image, - vk::Format view_format, uint32_t swizzle, - uint32_t base_level, uint32_t level_count, - vk::ImageViewType type, uint32_t base_layer, - uint32_t layer_count); + GetDepthTargetSampledView(DepthStencilVulkanImage& image, vk::Format view_format, + uint32_t swizzle, uint32_t base_level, uint32_t level_count, + vk::ImageViewType type, uint32_t base_layer, uint32_t layer_count); + [[nodiscard]] vk::ImageView GetSampledColorView(VulkanImage& image, vk::Format view_format, + uint32_t swizzle, uint32_t base_level, + uint32_t level_count, vk::ImageViewType type, + uint32_t base_layer, uint32_t layer_count); [[nodiscard]] vk::ImageView - GetRenderTargetStorageView(GraphicContext* ctx, RenderTextureVulkanImage* image, - vk::Format view_format, uint32_t base_level, uint32_t level_count, - vk::ImageViewType type, uint32_t base_layer, uint32_t layer_count); - [[nodiscard]] vk::ImageView GetStorageTextureSampledView(GraphicContext* ctx, - StorageTextureVulkanImage* image, + GetRenderTargetStorageView(RenderTextureVulkanImage& image, vk::Format view_format, + uint32_t base_level, uint32_t level_count, vk::ImageViewType type, + uint32_t base_layer, uint32_t layer_count); + [[nodiscard]] vk::ImageView GetStorageTextureSampledView(StorageTextureVulkanImage& image, const ImageInfo& info); - [[nodiscard]] vk::ImageView GetStorageTextureStorageView(GraphicContext* ctx, - StorageTextureVulkanImage* image, + [[nodiscard]] vk::ImageView GetStorageTextureStorageView(StorageTextureVulkanImage& image, uint32_t base_level); [[nodiscard]] DepthStencilVulkanImage* - FindDepthTargetByRange(CommandBuffer* command, uint64_t vaddr, uint64_t size, + FindDepthTargetByRange(CommandBuffer& command, uint64_t vaddr, uint64_t size, bool allow_containing_sampled = false); [[nodiscard]] RegionInfo QueryRegion(uint64_t vaddr, uint64_t size); - [[nodiscard]] bool ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo* info); - void RegisterMeta(GraphicContext* ctx, uint64_t vaddr, uint64_t size, uint32_t layers = 1); - [[nodiscard]] bool IsMeta(uint64_t vaddr); - [[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size); - [[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice); - [[nodiscard]] bool ClearMeta(uint64_t vaddr); - [[nodiscard]] bool TouchMeta(uint64_t vaddr, uint32_t slice, bool is_clear); - [[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size, - PageFaultPhase phase) noexcept; - void UnmapMemory(uint64_t vaddr, uint64_t size); + [[nodiscard]] bool ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo& info); + void RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers = 1); + [[nodiscard]] bool IsMeta(uint64_t vaddr); + [[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size); + [[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice); + [[nodiscard]] bool ClearMeta(uint64_t vaddr); + [[nodiscard]] bool TouchMeta(uint64_t vaddr, uint32_t slice, bool is_clear); + [[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size, + PageFaultPhase phase) noexcept; + void UnmapMemory(uint64_t vaddr, uint64_t size); - VulkanImage* GetDummySampledTexture(bool uint_format, bool image_3d); - VulkanImage* GetDummyStorageTexture(bool uint_format, bool image_3d); + VulkanImage& GetDummySampledTexture(bool uint_format, bool image_3d); + VulkanImage& GetDummyStorageTexture(bool uint_format, bool image_3d); private: struct CachedImage; @@ -135,20 +129,19 @@ private: uint32_t clear_mask = 0; bool gpu_modified = false; }; - [[nodiscard]] vk::ImageView GetImageView(GraphicContext* ctx, VulkanImage* image, - const ImageViewInfo& info); + [[nodiscard]] vk::ImageView GetImageView(VulkanImage& image, const ImageViewInfo& info); [[nodiscard]] bool HasMetaOverlapLocked(uint64_t vaddr, uint64_t size) const; [[nodiscard]] CachedImage* FindGpuReadbackPageCandidateLocked(uint64_t vaddr, uint64_t size); void RequireNoMetaOverlapLocked(uint64_t vaddr, uint64_t size) const; - void ResolveImageMetadataOverlapsLocked(GraphicContext* ctx, uint64_t vaddr, uint64_t size); - void MarkSampledAliasesCpuDirtyLocked(uint64_t vaddr, uint64_t size); - void RetireSampledTargetAliases(GraphicContext* ctx, const ImageInfo& requested); - void ResolveStorageImageOverlaps(GraphicContext* ctx, const ImageInfo& requested); - void RetireStorageDepthAliasLocked(GraphicContext* ctx, const ImageInfo& requested); - void RegisterImageLocked(CachedImage& image); - void UnregisterImageLocked(CachedImage& image, bool release_tracking); - [[nodiscard]] VulkanImage* PublishImage(CommandBuffer* command, - std::shared_ptr image); + void ResolveImageMetadataOverlapsLocked(uint64_t vaddr, uint64_t size); + void MarkSampledAliasesCpuDirtyLocked(uint64_t vaddr, uint64_t size); + void RetireSampledTargetAliases(const ImageInfo& requested); + void ResolveStorageImageOverlaps(const ImageInfo& requested); + void RetireStorageDepthAliasLocked(const ImageInfo& requested); + void RegisterImageLocked(CachedImage& image); + void UnregisterImageLocked(CachedImage& image, bool release_tracking); + [[nodiscard]] VulkanImage& PublishImage(CommandBuffer& command, + std::shared_ptr image); [[nodiscard]] std::vector FindImagesInRegionLocked(uint64_t vaddr, uint64_t size, bool page_overlap); void RequireRetirementIsolation(const std::vector& retire, const char* operation, @@ -157,13 +150,13 @@ private: const CachedImage* native_image_source = nullptr); void RetireDepthMetadataLocked(const std::vector& retire, uint64_t preserve_address = 0); - void MaterializeImagesToGuestLocked(GraphicContext* ctx, - const std::vector>& images); + void MaterializeImagesToGuestLocked(const std::vector>& images); void SynchronizeColorImageToBufferLocked(CachedImage& cached, uint64_t write_address, uint64_t write_size); void SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint64_t write_address, uint64_t write_size); + GraphicContext& m_graphics; std::unique_ptr m_dummy_textures; TrackingSpinLock m_lock; std::mutex m_fault_mutex; diff --git a/src/graphics/host_gpu/renderer/tiler.cpp b/src/graphics/host_gpu/renderer/tiler.cpp index c238a0f42..5f920b1df 100644 --- a/src/graphics/host_gpu/renderer/tiler.cpp +++ b/src/graphics/host_gpu/renderer/tiler.cpp @@ -26,7 +26,7 @@ DepthTransfer MakeDepthTransfer(uint64_t size, uint32_t layers, uint32_t format, EXIT_IF(size == 0 || layers == 0 || size % layers != 0); TileBlockLayout block {}; EXIT_NOT_IMPLEMENTED( - !TileGetBlockLayout(TileBlockFamily::Depth64KB, bytes_per_element, &block) || + !TileGetBlockLayout(TileBlockFamily::Depth64KB, bytes_per_element, block) || Prospero::NumBytesPerElement(format) != bytes_per_element); const uint64_t slice_size = size / layers; @@ -61,21 +61,20 @@ DepthTransfer MakeDepthTransfer(uint64_t size, uint32_t layers, uint32_t format, return transfer; } -void UploadDepth(GraphicContext* ctx, DepthStencilVulkanImage* image, uint64_t source_address, - uint64_t size, uint32_t layers, uint32_t format, uint32_t bytes_per_element, - uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_layer, +void UploadDepth(DepthStencilVulkanImage& image, uint64_t source_address, uint64_t size, + uint32_t layers, uint32_t format, uint32_t bytes_per_element, uint32_t width, + uint32_t height, uint32_t pitch, uint32_t base_layer, vk::ImageAspectFlags aspect) { auto transfer = MakeDepthTransfer(size, layers, format, bytes_per_element, width, height, pitch, base_layer, aspect); - Transfer::UploadTiledImage(ctx, image, reinterpret_cast(source_address), size, - size, transfer.infos, transfer.regions, + Transfer::UploadTiledImage(image, reinterpret_cast(source_address), size, size, + transfer.infos, transfer.regions, vk::ImageLayout::eDepthStencilAttachmentOptimal); } template -void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image, - const DepthTargetInfo& info, const BufferImageCopySource& source, - uint32_t base_layer) { +void UploadPromotedD16Depth(DepthStencilVulkanImage& image, const DepthTargetInfo& info, + const BufferImageCopySource& source, uint32_t base_layer) { const uint64_t guest_slice_size = info.size / info.layers; const uint64_t texels = static_cast(info.pitch) * info.height; const uint64_t host_slice_size = texels * sizeof(uint32_t); @@ -86,7 +85,7 @@ void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image, info.bytes_per_element, info.width, info.height, info.pitch, base_layer, vk::ImageAspectFlagBits::eDepth); std::vector guest_linear(info.size / sizeof(uint16_t)); - GpuDetile(ctx, reinterpret_cast(source.address), guest_linear.data(), info.size, + GpuDetile(reinterpret_cast(source.address), guest_linear.data(), info.size, info.size, transfer.infos); Transfer::ScratchBuffer host_linear(host_upload_size); @@ -99,63 +98,63 @@ void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image, } transfer.regions[layer].offset = static_cast(host_slice_size * layer); } - Transfer::UploadImage(ctx, image, host_linear.Data(), host_upload_size, transfer.regions, + Transfer::UploadImage(image, host_linear.Data(), host_upload_size, transfer.regions, vk::ImageLayout::eDepthStencilAttachmentOptimal); } } // namespace -void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, +void Tiler::DetileImage(GpuTextureVulkanImage& image, const ImageInfo& info, const BufferImageCopySource& source, bool refresh, bool storage) const { - if (refresh) Transfer::WaitForGraphicsIdle(ctx); + if (refresh) Transfer::WaitForGraphicsIdle(); const bool array_texture = TextureIsLayeredTexture(info.type); const bool volume_texture = TextureIs3DTexture(info.type); auto layout = TextureCalcUploadLayout( info.format, info.width, info.height, info.levels, info.depth, info.pitch, info.tile, info.size, true, volume_texture, storage ? "StorageTextureCache" : "TextureCache"); - auto regions = TextureBuildUploadRegions(layout, image->format, info.width, info.height, + auto regions = TextureBuildUploadRegions(layout, image.format, info.width, info.height, info.depth, info.levels, array_texture, volume_texture, TextureUploadDestination::MipLevels); - TextureUploadGuestImage(ctx, image, reinterpret_cast(source.address), info.size, + TextureUploadGuestImage(image, reinterpret_cast(source.address), info.size, regions, layout, info.format, info.width, info.height, info.depth, info.levels, storage ? "StorageTextureCache" : "TextureCache", storage ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal); } -void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image, - const DepthTargetInfo& info, const BufferImageCopySource& source, - bool refresh, uint32_t base_layer) const { - EXIT_NOT_IMPLEMENTED(info.samples != 1 || image->samples != 1); - if (refresh) Transfer::WaitForGraphicsIdle(ctx); +void Tiler::DetileImage(DepthStencilVulkanImage& image, const DepthTargetInfo& info, + const BufferImageCopySource& source, bool refresh, + uint32_t base_layer) const { + EXIT_NOT_IMPLEMENTED(info.samples != 1 || image.samples != 1); + if (refresh) Transfer::WaitForGraphicsIdle(); if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) { switch (info.format) { case vk::Format::eD24UnormS8Uint: - UploadPromotedD16Depth(ctx, image, info, source, base_layer); + UploadPromotedD16Depth(image, info, source, base_layer); return; case vk::Format::eD32SfloatS8Uint: - UploadPromotedD16Depth(ctx, image, info, source, base_layer); + UploadPromotedD16Depth(image, info, source, base_layer); return; default: EXIT_NOT_IMPLEMENTED(true); } } - UploadDepth(ctx, image, source.address, info.size, info.layers, info.guest_format, + UploadDepth(image, source.address, info.size, info.layers, info.guest_format, info.bytes_per_element, info.width, info.height, info.pitch, base_layer, vk::ImageAspectFlagBits::eDepth); } -void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image, - const DepthTargetInfo& info, const BufferImageCopySource& source, - bool refresh, uint32_t base_layer) const { - EXIT_NOT_IMPLEMENTED(info.samples != 1 || image->samples != 1); - if (refresh) Transfer::WaitForGraphicsIdle(ctx); +void Tiler::DetileStencil(DepthStencilVulkanImage& image, const DepthTargetInfo& info, + const BufferImageCopySource& source, bool refresh, + uint32_t base_layer) const { + EXIT_NOT_IMPLEMENTED(info.samples != 1 || image.samples != 1); + if (refresh) Transfer::WaitForGraphicsIdle(); const auto format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt); const auto pitch = TileGetTexturePitch(format, info.width, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth)); - UploadDepth(ctx, image, source.address, info.stencil_size, info.layers, format, 1, info.width, + UploadDepth(image, source.address, info.stencil_size, info.layers, format, 1, info.width, info.height, pitch, base_layer, vk::ImageAspectFlagBits::eStencil); } diff --git a/src/graphics/host_gpu/renderer/tiler.h b/src/graphics/host_gpu/renderer/tiler.h index 11776e3f4..a45d56701 100644 --- a/src/graphics/host_gpu/renderer/tiler.h +++ b/src/graphics/host_gpu/renderer/tiler.h @@ -9,21 +9,19 @@ namespace Libs::Graphics { struct DepthStencilVulkanImage; struct GpuTextureVulkanImage; -struct GraphicContext; - class Tiler final { public: Tiler() = default; KYTY_CLASS_NO_COPY(Tiler); - void DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, + void DetileImage(GpuTextureVulkanImage& image, const ImageInfo& info, const BufferImageCopySource& source, bool refresh, bool storage) const; - void DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image, - const DepthTargetInfo& info, const BufferImageCopySource& source, bool refresh, + void DetileImage(DepthStencilVulkanImage& image, const DepthTargetInfo& info, + const BufferImageCopySource& source, bool refresh, uint32_t base_layer = 0) const; - void DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image, - const DepthTargetInfo& info, const BufferImageCopySource& source, - bool refresh, uint32_t base_layer = 0) const; + void DetileStencil(DepthStencilVulkanImage& image, const DepthTargetInfo& info, + const BufferImageCopySource& source, bool refresh, + uint32_t base_layer = 0) const; }; } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/transfer.cpp b/src/graphics/host_gpu/transfer.cpp index 9f3933b4e..3be122e54 100644 --- a/src/graphics/host_gpu/transfer.cpp +++ b/src/graphics/host_gpu/transfer.cpp @@ -82,13 +82,14 @@ bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size) { return true; } -void WaitForGraphicsIdle(GraphicContext* ctx) { +void WaitForGraphicsIdle() { + auto& graphics = GetRenderContext().GetGraphics(); Common::Mutex* locked[GraphicContext::QUEUES_NUM] {}; int locked_num = 0; for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) { - auto* mutex = ctx->queues[id].mutex; - if (mutex == nullptr || ctx->queues[id].vk_queue == nullptr) { + auto* mutex = graphics.queues[id].mutex; + if (mutex == nullptr || graphics.queues[id].vk_queue == nullptr) { continue; } @@ -106,7 +107,7 @@ void WaitForGraphicsIdle(GraphicContext* ctx) { } } - auto result = ctx->device.waitIdle(); + auto result = graphics.device.waitIdle(); for (int i = locked_num - 1; i >= 0; i--) { locked[i]->Unlock(); @@ -119,7 +120,7 @@ void WaitForGraphicsIdle(GraphicContext* ctx) { EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); } -static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level, +static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage& dst_image, uint32_t base_level, uint32_t levels, vk::ImageAspectFlags aspect_mask, vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout); @@ -129,7 +130,7 @@ static void ExecuteImmediateCommands(const Recorder& recorder) { // not touch every caller. CommandBuffer command(GraphicContext::QUEUE_UTIL); command.Begin(); - recorder(&command, command.Handle()); + recorder(command, command.Handle()); command.End(); command.Execute(); command.WaitForFence(); @@ -205,12 +206,12 @@ static void RecordBufferToImageCopy(CommandBuffer& command, VulkanBuffer& src_bu vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer); - SetImageLayout(vk_command, &dst_image, 0, VK_REMAINING_MIP_LEVELS, transition_aspects, + SetImageLayout(vk_command, dst_image, 0, VK_REMAINING_MIP_LEVELS, transition_aspects, initial_layout, vk::ImageLayout::eTransferDstOptimal); vk_command.copyBufferToImage(src_buffer.buffer, dst_image.image, vk::ImageLayout::eTransferDstOptimal, static_cast(regions.size()), regions.data()); - SetImageLayout(vk_command, &dst_image, 0, VK_REMAINING_MIP_LEVELS, transition_aspects, + SetImageLayout(vk_command, dst_image, 0, VK_REMAINING_MIP_LEVELS, transition_aspects, vk::ImageLayout::eTransferDstOptimal, final_layout); } @@ -251,7 +252,7 @@ RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image, VulkanBuffer for (const auto& region: regions) { aspects |= GetTransferAspects(src_image, region.aspect); } - SetImageLayout(vk_command, &src_image, 0, VK_REMAINING_MIP_LEVELS, aspects, src_image.layout, + SetImageLayout(vk_command, src_image, 0, VK_REMAINING_MIP_LEVELS, aspects, src_image.layout, vk::ImageLayout::eTransferSrcOptimal); SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, VK_WHOLE_SIZE, vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, @@ -264,7 +265,7 @@ RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image, VulkanBuffer SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, VK_WHOLE_SIZE, vk::AccessFlagBits::eTransferWrite, final_access, vk::PipelineStageFlagBits::eTransfer, final_stage); - SetImageLayout(vk_command, &src_image, 0, VK_REMAINING_MIP_LEVELS, aspects, + SetImageLayout(vk_command, src_image, 0, VK_REMAINING_MIP_LEVELS, aspects, vk::ImageLayout::eTransferSrcOptimal, final_layout); } @@ -279,28 +280,27 @@ static void RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image, class ReusableStagingBuffer { public: - ReusableStagingBuffer() = default; + explicit ReusableStagingBuffer(GraphicContext& graphics): m_graphics(graphics) {} ~ReusableStagingBuffer() = default; KYTY_CLASS_NO_COPY(ReusableStagingBuffer); - void UploadToBuffer(GraphicContext* ctx, VulkanBuffer* dst_buffer, const void* src_data, - uint64_t size, uint64_t dst_offset) { - RecordUpload(ctx, src_data, size, [&](CommandBuffer*, vk::CommandBuffer vk_command) { + void UploadToBuffer(VulkanBuffer& dst_buffer, const void* src_data, uint64_t size, + uint64_t dst_offset) { + RecordUpload(src_data, size, [&](CommandBuffer&, vk::CommandBuffer vk_command) { SetBufferMemoryBarrier( vk_command, m_buffer.buffer, 0, size, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer); SetBufferMemoryBarrier( - vk_command, dst_buffer->buffer, dst_offset, size, + vk_command, dst_buffer.buffer, dst_offset, size, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer); const vk::BufferCopy copy_region { .srcOffset = 0, .dstOffset = dst_offset, .size = size}; - vk_command.copyBuffer(m_buffer.buffer, dst_buffer->buffer, 1, ©_region); + vk_command.copyBuffer(m_buffer.buffer, dst_buffer.buffer, 1, ©_region); SetBufferMemoryBarrier( - vk_command, dst_buffer->buffer, dst_offset, size, - vk::AccessFlagBits::eTransferWrite, + vk_command, dst_buffer.buffer, dst_offset, size, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndexRead | vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, vk::PipelineStageFlagBits::eTransfer, @@ -310,61 +310,57 @@ public: }); } - void UploadToImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size, - uint32_t src_pitch, vk::ImageAspectFlags copy_aspect, - vk::ImageLayout initial_layout, vk::ImageLayout final_layout) { - const auto transition_aspects = GetTransferAspects(*image, copy_aspect); - RecordUpload(ctx, src_data, size, [&](CommandBuffer* command, vk::CommandBuffer) { + void UploadToImage(VulkanImage& image, const void* src_data, uint64_t size, uint32_t src_pitch, + vk::ImageAspectFlags copy_aspect, vk::ImageLayout initial_layout, + vk::ImageLayout final_layout) { + const auto transition_aspects = GetTransferAspects(image, copy_aspect); + RecordUpload(src_data, size, [&](CommandBuffer& command, vk::CommandBuffer) { const auto region = MakeBufferImageCopy(0, src_pitch, copy_aspect, 0, 0, {0, 0, 0}, - {image->extent.width, image->extent.height, 1}); - RecordBufferToImageCopy(*command, m_buffer, *image, + {image.extent.width, image.extent.height, 1}); + RecordBufferToImageCopy(command, m_buffer, image, std::span(®ion, 1), transition_aspects, initial_layout, final_layout); }); } - void UploadToImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, - uint64_t size, std::span regions, - vk::ImageLayout dst_layout) { - RecordUpload(ctx, src_data, size, [&](CommandBuffer* command, vk::CommandBuffer) { + void UploadToImage(VulkanImage& dst_image, const void* src_data, uint64_t size, + std::span regions, vk::ImageLayout dst_layout) { + RecordUpload(src_data, size, [&](CommandBuffer& command, vk::CommandBuffer) { vk::ImageAspectFlags transition_aspects = {}; for (const auto& region: regions) { - transition_aspects |= GetTransferAspects(*dst_image, region.aspect); + transition_aspects |= GetTransferAspects(dst_image, region.aspect); } - RecordBufferToImageCopy(*command, m_buffer, *dst_image, - ConvertBufferImageCopies(regions), transition_aspects, - dst_image->layout, dst_layout); + RecordBufferToImageCopy(command, m_buffer, dst_image, ConvertBufferImageCopies(regions), + transition_aspects, dst_image.layout, dst_layout); }); } - void DownloadFromImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch, - VulkanImage* src_image, vk::ImageLayout src_layout, + void DownloadFromImage(void* dst_data, uint64_t size, uint32_t dst_pitch, + VulkanImage& src_image, vk::ImageLayout src_layout, vk::ImageAspectFlags aspect) { Common::LockGuard lock(m_mutex); - EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst); + EnsureBuffer(size, vk::BufferUsageFlagBits::eTransferDst); - ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) { - RecordImageToBuffer(*command, *src_image, m_buffer, dst_pitch, src_layout, aspect); + ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) { + RecordImageToBuffer(command, src_image, m_buffer, dst_pitch, src_layout, aspect); }); std::memcpy(dst_data, m_mapped_data, size); } - void DownloadFromImage(GraphicContext* ctx, void* dst_data, uint64_t size, - std::span regions, VulkanImage* src_image, - vk::ImageLayout src_layout) { - WithDownloadedImage(ctx, size, regions, src_image, src_layout, + void DownloadFromImage(void* dst_data, uint64_t size, std::span regions, + VulkanImage& src_image, vk::ImageLayout src_layout) { + WithDownloadedImage(size, regions, src_image, src_layout, [&](std::span data) { std::memcpy(dst_data, data.data(), data.size()); }); } - void ProcessDownloadedImage(GraphicContext* ctx, uint64_t size, - std::span regions, VulkanImage* src_image, - vk::ImageLayout src_layout, + void ProcessDownloadedImage(uint64_t size, std::span regions, + VulkanImage& src_image, vk::ImageLayout src_layout, const DownloadedImageConsumer& consumer) { - WithDownloadedImage(ctx, size, regions, src_image, src_layout, + WithDownloadedImage(size, regions, src_image, src_layout, [&](std::span data) { if (m_host_cached) { consumer(data); @@ -378,12 +374,12 @@ public: }); } - void Release(GraphicContext* ctx) { + void Release() { Common::LockGuard lock(m_mutex); if (m_buffer.buffer != nullptr) { - EXIT_IF(ctx == nullptr || m_mapped_data == nullptr); - VulkanUnmapMemory(ctx, &m_buffer.memory); - VulkanDeleteBuffer(ctx, &m_buffer); + EXIT_IF(m_mapped_data == nullptr); + m_graphics.UnmapMemory(m_buffer.memory); + m_graphics.DeleteBuffer(m_buffer); } m_capacity = 0; m_mapped_data = nullptr; @@ -392,42 +388,40 @@ public: private: template - void WithDownloadedImage(GraphicContext* ctx, uint64_t size, - std::span regions, VulkanImage* src_image, - vk::ImageLayout src_layout, const Consumer& consumer) { + void WithDownloadedImage(uint64_t size, std::span regions, + VulkanImage& src_image, vk::ImageLayout src_layout, + const Consumer& consumer) { Common::LockGuard lock(m_mutex); - EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst); - ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) { - RecordImageToBuffer(*command, *src_image, m_buffer, regions, src_layout); + EnsureBuffer(size, vk::BufferUsageFlagBits::eTransferDst); + ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) { + RecordImageToBuffer(command, src_image, m_buffer, regions, src_layout); }); consumer(std::span(static_cast(m_mapped_data), static_cast(size))); } template - void RecordUpload(GraphicContext* ctx, const void* src_data, uint64_t size, - const Recorder& recorder) { + void RecordUpload(const void* src_data, uint64_t size, const Recorder& recorder) { Common::LockGuard lock(m_mutex); - CopyFromHost(ctx, src_data, size, vk::BufferUsageFlagBits::eTransferSrc); + CopyFromHost(src_data, size, vk::BufferUsageFlagBits::eTransferSrc); if constexpr (WaitIdle) { - WaitForGraphicsIdle(ctx); + WaitForGraphicsIdle(); } ExecuteImmediateCommands(recorder); } - void CopyFromHost(GraphicContext* ctx, const void* src_data, uint64_t size, - vk::BufferUsageFlags usage) { - EnsureBuffer(ctx, size, usage); + void CopyFromHost(const void* src_data, uint64_t size, vk::BufferUsageFlags usage) { + EnsureBuffer(size, usage); std::memcpy(m_mapped_data, src_data, size); } - void EnsureBuffer(GraphicContext* ctx, uint64_t size, vk::BufferUsageFlags usage) { + void EnsureBuffer(uint64_t size, vk::BufferUsageFlags usage) { if (m_capacity < size || m_buffer.usage != usage) { if (m_buffer.buffer != nullptr) { - VulkanUnmapMemory(ctx, &m_buffer.memory); + m_graphics.UnmapMemory(m_buffer.memory); m_mapped_data = nullptr; - VulkanDeleteBuffer(ctx, &m_buffer); + m_graphics.DeleteBuffer(m_buffer); } m_buffer.usage = usage; @@ -439,18 +433,19 @@ private: usage & vk::BufferUsageFlagBits::eTransferDst ? vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eHostCached) : vk::MemoryPropertyFlags {}; - VulkanCreateBuffer(ctx, size, &m_buffer); + m_graphics.CreateBuffer(size, m_buffer); m_capacity = size; - const auto& properties = ctx->GetPhysicalDeviceMemoryProperties(); + const auto& properties = m_graphics.GetPhysicalDeviceMemoryProperties(); EXIT_IF(m_buffer.memory.type >= properties.memoryTypeCount); m_host_cached = static_cast(properties.memoryTypes[m_buffer.memory.type].propertyFlags & vk::MemoryPropertyFlagBits::eHostCached); - VulkanMapMemory(ctx, &m_buffer.memory, &m_mapped_data); + m_graphics.MapMemory(m_buffer.memory, m_mapped_data); } } + GraphicContext& m_graphics; Common::Mutex m_mutex; VulkanBuffer m_buffer; uint64_t m_capacity = 0; @@ -459,10 +454,26 @@ private: std::vector m_cached_readback; }; -// Do not replace with one -static ReusableStagingBuffer g_texture_staging_buffer; -static ReusableStagingBuffer g_vertex_staging_buffer; -static ReusableStagingBuffer g_readback_staging_buffer; +struct TransferResources { + explicit TransferResources(GraphicContext& graphics) + : graphics(graphics), texture(graphics), vertex(graphics), readback(graphics) {} + + GraphicContext& graphics; + ReusableStagingBuffer texture; + ReusableStagingBuffer vertex; + ReusableStagingBuffer readback; +}; + +static Common::Mutex g_resources_mutex; +static std::unique_ptr g_resources; + +static TransferResources& GetResources() { + Common::LockGuard lock(g_resources_mutex); + if (!g_resources) { + g_resources = std::make_unique(GetRenderContext().GetGraphics()); + } + return *g_resources; +} bool IsBlockCompressedFormat(vk::Format format) { return format == vk::Format::eBc1RgbUnormBlock || format == vk::Format::eBc1RgbSrgbBlock || @@ -507,55 +518,57 @@ static uint32_t GetFormatTexelSize(vk::Format format) { } } -static ReusableStagingBuffer* GetStagingBuffer(StagingBufferType type) { +static ReusableStagingBuffer& GetStagingBuffer(StagingBufferType type) { + auto& resources = GetResources(); switch (type) { - case StagingBufferType::Texture: return &g_texture_staging_buffer; - case StagingBufferType::Vertex: return &g_vertex_staging_buffer; - case StagingBufferType::ReadBack: return &g_readback_staging_buffer; + case StagingBufferType::Texture: return resources.texture; + case StagingBufferType::Vertex: return resources.vertex; + case StagingBufferType::ReadBack: return resources.readback; default: EXIT("unknown staging buffer type\n"); } - - return nullptr; + return resources.texture; } -void ReleaseCachedResources(GraphicContext* ctx) { - EXIT_IF(ctx == nullptr); - GpuTileRelease(ctx); - g_texture_staging_buffer.Release(ctx); - g_vertex_staging_buffer.Release(ctx); - g_readback_staging_buffer.Release(ctx); +void ReleaseCachedResources() { + GpuTileRelease(); + Common::LockGuard lock(g_resources_mutex); + if (g_resources) { + g_resources->texture.Release(); + g_resources->vertex.Release(); + g_resources->readback.Release(); + } } -void UploadTiledImage(GraphicContext* ctx, VulkanImage* dst_image, const void* tiled_data, - uint64_t tiled_size, uint64_t linear_size, std::span infos, +void UploadTiledImage(VulkanImage& dst_image, const void* tiled_data, uint64_t tiled_size, + uint64_t linear_size, std::span infos, std::span regions, vk::ImageLayout dst_layout) { - EXIT_IF(ctx == nullptr || dst_image == nullptr || tiled_data == nullptr || regions.empty()); - GpuDetile(ctx, tiled_data, nullptr, tiled_size, linear_size, infos, - [&](CommandBuffer* command, VulkanBuffer* linear) { + EXIT_IF(tiled_data == nullptr || regions.empty()); + GpuDetile(tiled_data, nullptr, tiled_size, linear_size, infos, + [&](CommandBuffer& command, VulkanBuffer& linear) { vk::ImageAspectFlags aspects {}; for (const auto& region: regions) { - aspects |= GetTransferAspects(*dst_image, region.aspect); + aspects |= GetTransferAspects(dst_image, region.aspect); } - RecordBufferToImageCopy(*command, *linear, *dst_image, + RecordBufferToImageCopy(command, linear, dst_image, ConvertBufferImageCopies(regions), aspects, - dst_image->layout, dst_layout); + dst_image.layout, dst_layout); }); } -void DownloadTiledImage(GraphicContext* ctx, void* tiled_data, uint64_t tiled_size, - uint64_t linear_size, std::span infos, - std::span regions, VulkanImage* src_image, +void DownloadTiledImage(void* tiled_data, uint64_t tiled_size, uint64_t linear_size, + std::span infos, + std::span regions, VulkanImage& src_image, vk::ImageLayout src_layout) { - EXIT_IF(ctx == nullptr || tiled_data == nullptr || src_image == nullptr || regions.empty()); - GpuTile(ctx, nullptr, tiled_data, tiled_size, linear_size, infos, - [&](CommandBuffer* command, VulkanBuffer* linear) { - RecordImageToBuffer(*command, *src_image, *linear, regions, src_layout, + EXIT_IF(tiled_data == nullptr || regions.empty()); + GpuTile(nullptr, tiled_data, tiled_size, linear_size, infos, + [&](CommandBuffer& command, VulkanBuffer& linear) { + RecordImageToBuffer(command, src_image, linear, regions, src_layout, vk::AccessFlagBits::eShaderRead, vk::PipelineStageFlagBits::eComputeShader); }); } -static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level, +static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage& dst_image, uint32_t base_level, uint32_t levels, vk::ImageAspectFlags aspect_mask, vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout) { if ((old_image_layout == vk::ImageLayout::eTransferDstOptimal && @@ -568,14 +581,14 @@ static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uin if (log_count.fetch_add(1, std::memory_order_relaxed) < 64) { LOGF("set_image_layout: image=%p type=%d tracked=%d requested=%d->%d base=%u " "levels=%u\n", - VulkanHandleToPointer(dst_image->image), static_cast(dst_image->type), - static_cast(dst_image->layout), static_cast(old_image_layout), + VulkanHandleToPointer(dst_image.image), static_cast(dst_image.type), + static_cast(dst_image.layout), static_cast(old_image_layout), static_cast(new_image_layout), base_level, levels); } } if (old_image_layout == new_image_layout) { - dst_image->layout = new_image_layout; + dst_image.layout = new_image_layout; return; } @@ -588,12 +601,12 @@ static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uin image_memory_barrier.newLayout = new_image_layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier.image = dst_image->image; + image_memory_barrier.image = dst_image.image; image_memory_barrier.subresourceRange.aspectMask = aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = base_level; image_memory_barrier.subresourceRange.levelCount = levels; image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = dst_image->layers; + image_memory_barrier.subresourceRange.layerCount = dst_image.layers; switch (old_image_layout) { case vk::ImageLayout::eColorAttachmentOptimal: @@ -663,7 +676,7 @@ static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uin buffer.pipelineBarrier(src_stages, dest_stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); - dst_image->layout = new_image_layout; + dst_image.layout = new_image_layout; } static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r, @@ -674,7 +687,7 @@ static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r, return 0; } - auto src_texel_size = GetFormatTexelSize(r.src_image->format); + auto src_texel_size = GetFormatTexelSize(r.src_image.format); auto dst_block_size = BlockCompressedBytesPerBlock(dst_image.format); if (src_texel_size == 0 || src_texel_size != dst_block_size) { return 0; @@ -682,16 +695,16 @@ static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r, auto block_width = (r.width + 3u) / 4u; auto block_height = (r.height + 3u) / 4u; - if (block_width > r.src_image->extent.width || block_height > r.src_image->extent.height) { + if (block_width > r.src_image.extent.width || block_height > r.src_image.extent.height) { return 0; } return static_cast(block_width) * block_height * dst_block_size; } static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r, - VulkanImage* dst_image, VulkanBuffer* copy_buffer) { - const auto copy_size = CompressedImageCopyBufferSize(r, *dst_image); - EXIT_IF(copy_size == 0 || copy_buffer == nullptr || copy_buffer->buffer_size < copy_size); + VulkanImage& dst_image, VulkanBuffer& copy_buffer) { + const auto copy_size = CompressedImageCopyBufferSize(r, dst_image); + EXIT_IF(copy_size == 0 || copy_buffer.buffer_size < copy_size); const auto block_width = (r.width + 3u) / 4u; const auto block_height = (r.height + 3u) / 4u; @@ -700,17 +713,17 @@ static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const I MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.src_level, r.src_layer, {r.src_x, r.src_y, 0}, {block_width, block_height, 1}); - auto src_layout = r.src_image->layout; + auto src_layout = r.src_image.layout; SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor, src_layout, vk::ImageLayout::eTransferSrcOptimal); - SetBufferMemoryBarrier(vk_buffer, copy_buffer->buffer, 0, VK_WHOLE_SIZE, + SetBufferMemoryBarrier(vk_buffer, copy_buffer.buffer, 0, VK_WHOLE_SIZE, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer); - vk_buffer.copyImageToBuffer(r.src_image->image, vk::ImageLayout::eTransferSrcOptimal, - copy_buffer->buffer, 1, &src_region); - SetBufferMemoryBarrier(vk_buffer, copy_buffer->buffer, 0, VK_WHOLE_SIZE, + vk_buffer.copyImageToBuffer(r.src_image.image, vk::ImageLayout::eTransferSrcOptimal, + copy_buffer.buffer, 1, &src_region); + SetBufferMemoryBarrier(vk_buffer, copy_buffer.buffer, 0, VK_WHOLE_SIZE, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer); @@ -719,22 +732,22 @@ static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const I MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.dst_level, r.dst_layer, {r.dst_x, r.dst_y, 0}, {r.width, r.height, 1}); - vk_buffer.copyBufferToImage(copy_buffer->buffer, dst_image->image, + vk_buffer.copyBufferToImage(copy_buffer.buffer, dst_image.image, vk::ImageLayout::eTransferDstOptimal, 1, &dst_region); SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::eTransferSrcOptimal, src_layout); } -void CopyImage(CommandBuffer* buffer, std::span regions, - VulkanImage* dst_image, vk::ImageLayout dst_layout) { - auto vk_buffer = buffer->Handle(); +void CopyImage(CommandBuffer& buffer, std::span regions, + VulkanImage& dst_image, vk::ImageLayout dst_layout) { + auto vk_buffer = buffer.Handle(); bool same_image_copy = false; vk::ImageAspectFlags dst_transition_aspects = {}; for (const auto& r: regions) { - dst_transition_aspects |= GetTransferAspects(*dst_image, r.dst_aspect); - if (r.src_image == dst_image) { + dst_transition_aspects |= GetTransferAspects(dst_image, r.dst_aspect); + if (&r.src_image == &dst_image) { same_image_copy = true; break; } @@ -742,7 +755,7 @@ void CopyImage(CommandBuffer* buffer, std::span regions, if (same_image_copy) { SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects, - dst_image->layout, vk::ImageLayout::eGeneral); + dst_image.layout, vk::ImageLayout::eGeneral); for (const auto& r: regions) { vk::ImageCopy region; @@ -761,20 +774,20 @@ void CopyImage(CommandBuffer* buffer, std::span regions, auto src_layout = vk::ImageLayout::eGeneral; auto restore_layout = vk::ImageLayout::eGeneral; - if (r.src_image != dst_image) { - restore_layout = r.src_image->layout; + if (&r.src_image != &dst_image) { + restore_layout = r.src_image.layout; SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, - GetTransferAspects(*r.src_image, r.src_aspect), restore_layout, + GetTransferAspects(r.src_image, r.src_aspect), restore_layout, vk::ImageLayout::eTransferSrcOptimal); src_layout = vk::ImageLayout::eTransferSrcOptimal; } - vk_buffer.copyImage(r.src_image->image, src_layout, dst_image->image, + vk_buffer.copyImage(r.src_image.image, src_layout, dst_image.image, vk::ImageLayout::eGeneral, 1, ®ion); - if (r.src_image != dst_image) { + if (&r.src_image != &dst_image) { SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, - GetTransferAspects(*r.src_image, r.src_aspect), + GetTransferAspects(r.src_image, r.src_aspect), vk::ImageLayout::eTransferSrcOptimal, restore_layout); } } @@ -785,11 +798,11 @@ void CopyImage(CommandBuffer* buffer, std::span regions, } SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects, - dst_image->layout, vk::ImageLayout::eTransferDstOptimal); + dst_image.layout, vk::ImageLayout::eTransferDstOptimal); uint64_t compressed_copy_size = 0; for (const auto& r: regions) { compressed_copy_size = - std::max(compressed_copy_size, CompressedImageCopyBufferSize(r, *dst_image)); + std::max(compressed_copy_size, CompressedImageCopyBufferSize(r, dst_image)); } VulkanBuffer* compressed_copy_buffer = nullptr; if (compressed_copy_size != 0) { @@ -797,17 +810,17 @@ void CopyImage(CommandBuffer* buffer, std::span regions, compressed_copy_buffer->usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; compressed_copy_buffer->memory.property = {}; - VulkanCreateBuffer(WindowGetGraphicContext(), compressed_copy_size, compressed_copy_buffer); - buffer->DeleteAfterFence(compressed_copy_buffer); + buffer.GetGraphics().CreateBuffer(compressed_copy_size, *compressed_copy_buffer); + buffer.DeleteAfterFence(*compressed_copy_buffer); } for (const auto& r: regions) { vk::ImageCopy region; - auto src_layout = r.src_image->layout; + auto src_layout = r.src_image.layout; - if (CompressedImageCopyBufferSize(r, *dst_image) != 0) { - CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, compressed_copy_buffer); + if (CompressedImageCopyBufferSize(r, dst_image) != 0) { + CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, *compressed_copy_buffer); continue; } @@ -824,14 +837,14 @@ void CopyImage(CommandBuffer* buffer, std::span regions, region.extent = {r.width, r.height, 1}; SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, - GetTransferAspects(*r.src_image, r.src_aspect), src_layout, + GetTransferAspects(r.src_image, r.src_aspect), src_layout, vk::ImageLayout::eTransferSrcOptimal); - vk_buffer.copyImage(r.src_image->image, vk::ImageLayout::eTransferSrcOptimal, - dst_image->image, vk::ImageLayout::eTransferDstOptimal, 1, ®ion); + vk_buffer.copyImage(r.src_image.image, vk::ImageLayout::eTransferSrcOptimal, + dst_image.image, vk::ImageLayout::eTransferDstOptimal, 1, ®ion); SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, - GetTransferAspects(*r.src_image, r.src_aspect), + GetTransferAspects(r.src_image, r.src_aspect), vk::ImageLayout::eTransferSrcOptimal, src_layout); } @@ -839,59 +852,60 @@ void CopyImage(CommandBuffer* buffer, std::span regions, vk::ImageLayout::eTransferDstOptimal, dst_layout); } -void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image, - vk::ImageAspectFlags src_aspect, VulkanImage* dst_image, +void CopyImageViaBuffer(CommandBuffer& buffer, VulkanImage& src_image, + vk::ImageAspectFlags src_aspect, VulkanImage& dst_image, vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element, vk::ImageLayout dst_layout) { if (!IsSingleImageAspect(src_aspect) || !IsSingleImageAspect(dst_aspect) || - (bytes_per_element != 2 && bytes_per_element != 4) || src_image->layers != 1 || - dst_image->layers != 1 || src_image->mip_levels != 1 || dst_image->mip_levels != 1 || - src_image->extent.width == 0 || src_image->extent.height == 0 || - src_image->extent.width != dst_image->extent.width || - src_image->extent.height != dst_image->extent.height) { + (bytes_per_element != 2 && bytes_per_element != 4) || src_image.layers != 1 || + dst_image.layers != 1 || src_image.mip_levels != 1 || dst_image.mip_levels != 1 || + src_image.extent.width == 0 || src_image.extent.height == 0 || + src_image.extent.width != dst_image.extent.width || + src_image.extent.height != dst_image.extent.height) { EXIT("unsupported image-buffer-image copy, src_aspect=0x%x dst_aspect=0x%x bpe=%u " "src=%ux%u/%u/%u dst=%ux%u/%u/%u\n", static_cast(src_aspect), static_cast(dst_aspect), bytes_per_element, - src_image->extent.width, src_image->extent.height, src_image->layers, - src_image->mip_levels, dst_image->extent.width, dst_image->extent.height, - dst_image->layers, dst_image->mip_levels); + src_image.extent.width, src_image.extent.height, src_image.layers, + src_image.mip_levels, dst_image.extent.width, dst_image.extent.height, + dst_image.layers, dst_image.mip_levels); } - const uint64_t row_bytes = static_cast(src_image->extent.width) * bytes_per_element; + const uint64_t row_bytes = static_cast(src_image.extent.width) * bytes_per_element; constexpr uint64_t MAX_COPY_BUFFER_SIZE = 16ull * 1024ull * 1024ull; if (row_bytes == 0 || row_bytes > MAX_COPY_BUFFER_SIZE) { EXIT("unsupported image-buffer-image row size: 0x%016" PRIx64 "\n", row_bytes); } const auto rows_per_chunk = static_cast( - std::min(src_image->extent.height, MAX_COPY_BUFFER_SIZE / row_bytes)); + std::min(src_image.extent.height, MAX_COPY_BUFFER_SIZE / row_bytes)); const auto copy_buffer_size = row_bytes * rows_per_chunk; // Kyty does not yet have a cross-queue scheduler. Drain submitted work once before // recording the recreate copy; commands already recorded on this buffer remain ordered by the // barriers below. The preservation policy stays isolated here so a future scheduler can replace // this synchronization without changing texture-cache ownership logic. - WaitForGraphicsIdle(ctx); + auto& graphics = buffer.GetGraphics(); + WaitForGraphicsIdle(); auto* copy_buffer = new VulkanBuffer; copy_buffer->usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; copy_buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; - VulkanCreateBuffer(ctx, copy_buffer_size, copy_buffer); - buffer->DeleteAfterFence(copy_buffer); + graphics.CreateBuffer(copy_buffer_size, *copy_buffer); + buffer.DeleteAfterFence(*copy_buffer); - auto vk_buffer = buffer->Handle(); - const auto src_layout = src_image->layout; + auto vk_buffer = buffer.Handle(); + const auto src_layout = src_image.layout; const auto final_layout = dst_layout; SetImageLayout(vk_buffer, src_image, 0, 1, src_aspect, src_layout, vk::ImageLayout::eTransferSrcOptimal); - SetImageLayout(vk_buffer, dst_image, 0, 1, dst_aspect, dst_image->layout, + SetImageLayout(vk_buffer, dst_image, 0, 1, dst_aspect, dst_image.layout, vk::ImageLayout::eTransferDstOptimal); - for (uint32_t row = 0; row < src_image->extent.height; row += rows_per_chunk) { - const auto rows = std::min(rows_per_chunk, src_image->extent.height - row); + for (uint32_t row = 0; row < src_image.extent.height; row += rows_per_chunk) { + const auto rows = std::min(rows_per_chunk, src_image.extent.height - row); auto copy = MakeBufferImageCopy(0, 0, src_aspect, 0, 0, {0, static_cast(row), 0}, - {src_image->extent.width, rows, 1}); - vk_buffer.copyImageToBuffer(src_image->image, vk::ImageLayout::eTransferSrcOptimal, + {src_image.extent.width, rows, 1}); + vk_buffer.copyImageToBuffer(src_image.image, vk::ImageLayout::eTransferSrcOptimal, copy_buffer->buffer, 1, ©); SetBufferMemoryBarrier( @@ -900,9 +914,9 @@ void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* vk::PipelineStageFlagBits::eTransfer); copy.imageSubresource.aspectMask = dst_aspect; - vk_buffer.copyBufferToImage(copy_buffer->buffer, dst_image->image, + vk_buffer.copyBufferToImage(copy_buffer->buffer, dst_image.image, vk::ImageLayout::eTransferDstOptimal, 1, ©); - if (row + rows < src_image->extent.height) { + if (row + rows < src_image.extent.height) { SetBufferMemoryBarrier( vk_buffer, copy_buffer->buffer, 0, copy_buffer_size, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite, @@ -916,22 +930,20 @@ void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* final_layout); } -void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, - VulkanSwapchain* dst_swapchain) { - auto vk_buffer = buffer->Handle(); - if (src_image->layout != vk::ImageLayout::eTransferSrcOptimal) { - EXIT("invalid prepared presentation image, image=%p vk_image=%p layout=%d\n", - static_cast(src_image), - src_image != nullptr ? static_cast(src_image->image) : nullptr, - src_image != nullptr ? static_cast(src_image->layout) : -1); +void BlitToSwapchain(CommandBuffer& buffer, VulkanImage& src_image, + VulkanSwapchain& dst_swapchain) { + auto vk_buffer = buffer.Handle(); + if (src_image.layout != vk::ImageLayout::eTransferSrcOptimal) { + EXIT("invalid prepared presentation image, vk_image=%p layout=%d\n", + static_cast(src_image.image), static_cast(src_image.layout)); } VulkanImage swapchain_image(VulkanImageType::Unknown); - swapchain_image.image = dst_swapchain->swapchain_images[dst_swapchain->current_index]; + swapchain_image.image = dst_swapchain.swapchain_images[dst_swapchain.current_index]; swapchain_image.layout = vk::ImageLayout::eUndefined; - SetImageLayout(vk_buffer, &swapchain_image, 0, 1, vk::ImageAspectFlagBits::eColor, + SetImageLayout(vk_buffer, swapchain_image, 0, 1, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal); vk::ImageBlit region {}; @@ -942,8 +954,8 @@ void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, region.srcOffsets[0].x = 0; region.srcOffsets[0].y = 0; region.srcOffsets[0].z = 0; - region.srcOffsets[1].x = static_cast(src_image->extent.width); - region.srcOffsets[1].y = static_cast(src_image->extent.height); + region.srcOffsets[1].x = static_cast(src_image.extent.width); + region.srcOffsets[1].y = static_cast(src_image.extent.height); region.srcOffsets[1].z = 1; region.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; region.dstSubresource.mipLevel = 0; @@ -952,135 +964,132 @@ void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, region.dstOffsets[0].x = 0; region.dstOffsets[0].y = 0; region.dstOffsets[0].z = 0; - region.dstOffsets[1].x = static_cast(dst_swapchain->swapchain_extent.width); - region.dstOffsets[1].y = static_cast(dst_swapchain->swapchain_extent.height); + region.dstOffsets[1].x = static_cast(dst_swapchain.swapchain_extent.width); + region.dstOffsets[1].y = static_cast(dst_swapchain.swapchain_extent.height); region.dstOffsets[1].z = 1; - vk_buffer.blitImage(src_image->image, vk::ImageLayout::eTransferSrcOptimal, + vk_buffer.blitImage(src_image.image, vk::ImageLayout::eTransferSrcOptimal, swapchain_image.image, vk::ImageLayout::eTransferDstOptimal, 1, ®ion, vk::Filter::eLinear); } -void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color) { - auto vk_buffer = buffer->Handle(); - SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image->layout, +void ClearColorImage(CommandBuffer& buffer, VulkanImage& image, const vk::ClearColorValue& color) { + auto vk_buffer = buffer.Handle(); + SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image.layout, vk::ImageLayout::eTransferDstOptimal); const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; - vk_buffer.clearColorImage(image->image, vk::ImageLayout::eTransferDstOptimal, &color, 1, - &range); + vk_buffer.clearColorImage(image.image, vk::ImageLayout::eTransferDstOptimal, &color, 1, &range); SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal); } -void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, - uint32_t src_pitch, vk::ImageLayout dst_layout) { +void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size, uint32_t src_pitch, + vk::ImageLayout dst_layout) { KYTY_PROFILER_FUNCTION(); EXIT_IF(size == 0); GetStagingBuffer(StagingBufferType::Texture) - ->UploadToImage(ctx, dst_image, src_data, size, src_pitch, vk::ImageAspectFlagBits::eColor, - vk::ImageLayout::eUndefined, dst_layout); + .UploadToImage(dst_image, src_data, size, src_pitch, vk::ImageAspectFlagBits::eColor, + vk::ImageLayout::eUndefined, dst_layout); } -void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch, - VulkanImage* src_image, vk::ImageLayout src_layout, - vk::ImageAspectFlags aspect) { +void DownloadImage(void* dst_data, uint64_t size, uint32_t dst_pitch, VulkanImage& src_image, + vk::ImageLayout src_layout, vk::ImageAspectFlags aspect) { KYTY_PROFILER_FUNCTION(); EXIT_IF(size == 0); GetStagingBuffer(StagingBufferType::ReadBack) - ->DownloadFromImage(ctx, dst_data, size, dst_pitch, src_image, src_layout, aspect); + .DownloadFromImage(dst_data, size, dst_pitch, src_image, src_layout, aspect); } -void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, - std::span regions, VulkanImage* src_image, - vk::ImageLayout src_layout) { +void DownloadImage(void* dst_data, uint64_t size, std::span regions, + VulkanImage& src_image, vk::ImageLayout src_layout) { KYTY_PROFILER_FUNCTION(); EXIT_IF(size == 0 || regions.empty()); GetStagingBuffer(StagingBufferType::ReadBack) - ->DownloadFromImage(ctx, dst_data, size, regions, src_image, src_layout); + .DownloadFromImage(dst_data, size, regions, src_image, src_layout); } -void ProcessDownloadedImage(GraphicContext* ctx, uint64_t size, - std::span regions, VulkanImage* src_image, - vk::ImageLayout src_layout, const DownloadedImageConsumer& consumer) { +void ProcessDownloadedImage(uint64_t size, std::span regions, + VulkanImage& src_image, vk::ImageLayout src_layout, + const DownloadedImageConsumer& consumer) { KYTY_PROFILER_FUNCTION(); EXIT_IF(size == 0 || regions.empty() || !consumer); GetStagingBuffer(StagingBufferType::ReadBack) - ->ProcessDownloadedImage(ctx, size, regions, src_image, src_layout, consumer); + .ProcessDownloadedImage(size, regions, src_image, src_layout, consumer); } -void UploadImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size, +void UploadImage(VulkanImage& image, const void* src_data, uint64_t size, std::span regions, vk::ImageLayout dst_layout) { EXIT_IF(size == 0 || regions.empty()); GetStagingBuffer(StagingBufferType::Texture) - ->UploadToImage(ctx, image, src_data, size, regions, dst_layout); + .UploadToImage(image, src_data, size, regions, dst_layout); } -void CopyImageImmediate(GraphicContext* ctx, std::span regions, - VulkanImage* dst_image, vk::ImageLayout dst_layout) { - ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) { +void CopyImageImmediate(std::span regions, VulkanImage& dst_image, + vk::ImageLayout dst_layout) { + ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) { CopyImage(command, regions, dst_image, dst_layout); }); } -void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data, - uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) { +void UploadImage(DepthStencilVulkanImage& image, const void* src_data, uint64_t size, + uint32_t src_pitch, vk::ImageAspectFlags aspect) { EXIT_IF(size == 0); GetStagingBuffer(StagingBufferType::Texture) - ->UploadToImage(ctx, image, src_data, size, src_pitch, aspect, image->layout, - vk::ImageLayout::eDepthStencilAttachmentOptimal); + .UploadToImage(image, src_data, size, src_pitch, aspect, image.layout, + vk::ImageLayout::eDepthStencilAttachmentOptimal); } -void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer, - uint64_t dst_offset, const void* src_data, uint64_t size) { +void UploadBuffer(StagingBufferType type, VulkanBuffer& dst_buffer, uint64_t dst_offset, + const void* src_data, uint64_t size) { EXIT_IF(size == 0); - EXIT_IF(dst_offset > dst_buffer->buffer_size || size > dst_buffer->buffer_size - dst_offset); - GetStagingBuffer(type)->UploadToBuffer(ctx, dst_buffer, src_data, size, dst_offset); + EXIT_IF(dst_offset > dst_buffer.buffer_size || size > dst_buffer.buffer_size - dst_offset); + GetStagingBuffer(type).UploadToBuffer(dst_buffer, src_data, size, dst_offset); } -void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size) { - EXIT_IF(size == 0 || size > src_buffer->buffer_size || size > dst_buffer->buffer_size); +void CopyBuffer(VulkanBuffer& src_buffer, VulkanBuffer& dst_buffer, uint64_t size) { + EXIT_IF(size == 0 || size > src_buffer.buffer_size || size > dst_buffer.buffer_size); - ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) { - SetBufferMemoryBarrier(vk_command, src_buffer->buffer, 0, size, + ExecuteImmediateCommands([&](CommandBuffer&, vk::CommandBuffer vk_command) { + SetBufferMemoryBarrier(vk_command, src_buffer.buffer, 0, size, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer); - SetBufferMemoryBarrier(vk_command, dst_buffer->buffer, 0, size, + SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, size, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer); const vk::BufferCopy copy_region {.srcOffset = 0, .dstOffset = 0, .size = size}; - vk_command.copyBuffer(src_buffer->buffer, dst_buffer->buffer, 1, ©_region); + vk_command.copyBuffer(src_buffer.buffer, dst_buffer.buffer, 1, ©_region); SetBufferMemoryBarrier( - vk_command, dst_buffer->buffer, 0, size, vk::AccessFlagBits::eTransferWrite, + vk_command, dst_buffer.buffer, 0, size, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands); }); } -void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset, - void* dst_data, uint64_t size) { +void DownloadBuffer(VulkanBuffer& src_buffer, uint64_t src_offset, void* dst_data, uint64_t size) { + auto& graphics = GetRenderContext().GetGraphics(); EXIT_IF(size == 0); - EXIT_IF(src_offset > src_buffer->buffer_size || size > src_buffer->buffer_size - src_offset); - const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family; + EXIT_IF(src_offset > src_buffer.buffer_size || size > src_buffer.buffer_size - src_offset); + const auto family = graphics.queues[GraphicContext::QUEUE_UTIL].family; EXIT_IF(family == static_cast(-1)); for (int i = GraphicContext::QUEUE_COMPUTE_START; i < GraphicContext::QUEUE_COMPUTE_START + GraphicContext::QUEUE_COMPUTE_NUM; i++) { - EXIT_IF(ctx->queues[i].family != family); + EXIT_IF(graphics.queues[i].family != family); } - EXIT_IF(ctx->queues[GraphicContext::QUEUE_GFX].family != family); + EXIT_IF(graphics.queues[GraphicContext::QUEUE_GFX].family != family); - if (src_buffer->memory.property & vk::MemoryPropertyFlagBits::eHostVisible) { + if (src_buffer.memory.property & vk::MemoryPropertyFlagBits::eHostVisible) { void* mapped = nullptr; - VulkanMapMemory(ctx, &src_buffer->memory, &mapped); + graphics.MapMemory(src_buffer.memory, mapped); std::memcpy(dst_data, static_cast(mapped) + src_offset, size); - VulkanUnmapMemory(ctx, &src_buffer->memory); + graphics.UnmapMemory(src_buffer.memory); return; } @@ -1089,15 +1098,15 @@ void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_ readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached; - VulkanCreateBuffer(ctx, size, &readback); + graphics.CreateBuffer(size, readback); - ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) { - SetBufferMemoryBarrier(vk_command, src_buffer->buffer, src_offset, size, + ExecuteImmediateCommands([&](CommandBuffer&, vk::CommandBuffer vk_command) { + SetBufferMemoryBarrier(vk_command, src_buffer.buffer, src_offset, size, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer); const vk::BufferCopy copy {.srcOffset = src_offset, .dstOffset = 0, .size = size}; - vk_command.copyBuffer(src_buffer->buffer, readback.buffer, 1, ©); + vk_command.copyBuffer(src_buffer.buffer, readback.buffer, 1, ©); SetBufferMemoryBarrier(vk_command, readback.buffer, 0, size, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eHostRead, vk::PipelineStageFlagBits::eTransfer, @@ -1105,10 +1114,10 @@ void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_ }); void* mapped = nullptr; - VulkanMapMemory(ctx, &readback.memory, &mapped); + graphics.MapMemory(readback.memory, mapped); std::memcpy(dst_data, mapped, size); - VulkanUnmapMemory(ctx, &readback.memory); - VulkanDeleteBuffer(ctx, &readback); + graphics.UnmapMemory(readback.memory); + graphics.DeleteBuffer(readback); } } // namespace Libs::Graphics::Transfer diff --git a/src/graphics/host_gpu/transfer.h b/src/graphics/host_gpu/transfer.h index 0a278e5c6..f8f76ef91 100644 --- a/src/graphics/host_gpu/transfer.h +++ b/src/graphics/host_gpu/transfer.h @@ -49,7 +49,9 @@ struct ImageBufferCopy { }; struct ImageImageCopy { - VulkanImage* src_image; + explicit ImageImageCopy(VulkanImage& source): src_image(source) {} + + VulkanImage& src_image; uint32_t src_level; uint32_t dst_level; uint32_t width; @@ -89,52 +91,50 @@ private: void* m_data = nullptr; }; -void CopyImage(CommandBuffer* buffer, std::span regions, - VulkanImage* dst_image, vk::ImageLayout dst_layout); -void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image, - vk::ImageAspectFlags src_aspect, VulkanImage* dst_image, +void CopyImage(CommandBuffer& buffer, std::span regions, + VulkanImage& dst_image, vk::ImageLayout dst_layout); +void CopyImageViaBuffer(CommandBuffer& buffer, VulkanImage& src_image, + vk::ImageAspectFlags src_aspect, VulkanImage& dst_image, vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element, vk::ImageLayout dst_layout); -void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchain* dst_swapchain); -void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color); -void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, - uint32_t src_pitch, vk::ImageLayout dst_layout); -void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* dst_image, const void* src_data, - uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect); -void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, +void BlitToSwapchain(CommandBuffer& buffer, VulkanImage& src_image, VulkanSwapchain& dst_swapchain); +void ClearColorImage(CommandBuffer& buffer, VulkanImage& image, const vk::ClearColorValue& color); +void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size, uint32_t src_pitch, + vk::ImageLayout dst_layout); +void UploadImage(DepthStencilVulkanImage& dst_image, const void* src_data, uint64_t size, + uint32_t src_pitch, vk::ImageAspectFlags aspect); +void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size, std::span regions, vk::ImageLayout dst_layout); -void UploadTiledImage(GraphicContext* ctx, VulkanImage* dst_image, const void* tiled_data, - uint64_t tiled_size, uint64_t linear_size, std::span infos, +void UploadTiledImage(VulkanImage& dst_image, const void* tiled_data, uint64_t tiled_size, + uint64_t linear_size, std::span infos, std::span regions, vk::ImageLayout dst_layout); -void CopyImageImmediate(GraphicContext* ctx, std::span regions, - VulkanImage* dst_image, vk::ImageLayout dst_layout); -void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch, - VulkanImage* src_image, vk::ImageLayout src_layout, +void CopyImageImmediate(std::span regions, VulkanImage& dst_image, + vk::ImageLayout dst_layout); +void DownloadImage(void* dst_data, uint64_t size, uint32_t dst_pitch, VulkanImage& src_image, + vk::ImageLayout src_layout, vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor); -void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, - std::span regions, VulkanImage* src_image, - vk::ImageLayout src_layout); +void DownloadImage(void* dst_data, uint64_t size, std::span regions, + VulkanImage& src_image, vk::ImageLayout src_layout); // Invokes consumer synchronously after the image copy fence while the readback staging buffer is // reserved. The supplied span is valid only for the call; the consumer must not retain it or // re-enter Transfer. -void ProcessDownloadedImage(GraphicContext* ctx, uint64_t size, - std::span regions, VulkanImage* src_image, - vk::ImageLayout src_layout, const DownloadedImageConsumer& consumer); -void DownloadTiledImage(GraphicContext* ctx, void* tiled_data, uint64_t tiled_size, - uint64_t linear_size, std::span infos, - std::span regions, VulkanImage* src_image, +void ProcessDownloadedImage(uint64_t size, std::span regions, + VulkanImage& src_image, vk::ImageLayout src_layout, + const DownloadedImageConsumer& consumer); +void DownloadTiledImage(void* tiled_data, uint64_t tiled_size, uint64_t linear_size, + std::span infos, + std::span regions, VulkanImage& src_image, vk::ImageLayout src_layout); -void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer, - uint64_t dst_offset, const void* src_data, uint64_t size); -void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size); -void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset, - void* dst_data, uint64_t size); -void ReleaseCachedResources(GraphicContext* ctx); +void UploadBuffer(StagingBufferType type, VulkanBuffer& dst_buffer, uint64_t dst_offset, + const void* src_data, uint64_t size); +void CopyBuffer(VulkanBuffer& src_buffer, VulkanBuffer& dst_buffer, uint64_t size); +void DownloadBuffer(VulkanBuffer& src_buffer, uint64_t src_offset, void* dst_data, uint64_t size); +void ReleaseCachedResources(); bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size); bool IsBlockCompressedFormat(vk::Format format); uint32_t BlockCompressedBytesPerBlock(vk::Format format); -void WaitForGraphicsIdle(GraphicContext* ctx); +void WaitForGraphicsIdle(); inline std::pair MipmapAtlasOffset(uint32_t lod, uint32_t width, uint32_t height) { uint32_t mip_width = width; diff --git a/src/graphics/host_gpu/vma.cpp b/src/graphics/host_gpu/vma.cpp index adc16cc1b..4da78fdd2 100644 --- a/src/graphics/host_gpu/vma.cpp +++ b/src/graphics/host_gpu/vma.cpp @@ -48,34 +48,32 @@ void UntrackAllocationImpl(const VulkanMemory& memory) { } // namespace -void VulkanTrackAllocation(const VulkanMemory* memory) { - EXIT_IF(memory == nullptr); - TrackAllocationImpl(*memory); +void VulkanTrackAllocation(const VulkanMemory& memory) { + TrackAllocationImpl(memory); } -void VulkanUntrackAllocation(const VulkanMemory* memory) { - EXIT_IF(memory == nullptr); - UntrackAllocationImpl(*memory); +void VulkanUntrackAllocation(const VulkanMemory& memory) { + UntrackAllocationImpl(memory); } -bool VulkanCreateAllocator(GraphicContext* ctx) { +bool GraphicContext::CreateAllocator() { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr || ctx->instance == nullptr || ctx->physical_device == nullptr || - ctx->device == nullptr || ctx->allocator != nullptr); + EXIT_IF(instance == nullptr || physical_device == nullptr || device == nullptr || + allocator != nullptr); VmaVulkanFunctions functions {}; functions.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr; functions.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr; VmaAllocatorCreateInfo info {}; - info.instance = ctx->instance; - info.physicalDevice = ctx->physical_device; - info.device = ctx->device; + info.instance = instance; + info.physicalDevice = physical_device; + info.device = device; info.pVulkanFunctions = &functions; info.vulkanApiVersion = VULKAN_TARGET_API_VERSION; - info.flags = ctx->memory_budget_ext_enabled ? VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT : 0; + info.flags = memory_budget_ext_enabled ? VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT : 0; - const auto result = static_cast(vmaCreateAllocator(&info, &ctx->allocator)); + const auto result = static_cast(vmaCreateAllocator(&info, &allocator)); if (result != vk::Result::eSuccess) { LOGF("vmaCreateAllocator failed: %s\n", VulkanToString(result).c_str()); return false; @@ -83,12 +81,12 @@ bool VulkanCreateAllocator(GraphicContext* ctx) { return true; } -void VulkanDestroyAllocator(GraphicContext* ctx) { - if (ctx == nullptr || ctx->allocator == nullptr) { +void GraphicContext::DestroyAllocator() { + if (allocator == nullptr) { return; } - vmaDestroyAllocator(ctx->allocator); - ctx->allocator = nullptr; + vmaDestroyAllocator(allocator); + allocator = nullptr; } uint64_t VulkanNextMemoryUniqueId() { @@ -96,14 +94,14 @@ uint64_t VulkanNextMemoryUniqueId() { return ++sequence; } -void VulkanLogMemoryBudget(GraphicContext* ctx) { - if (ctx == nullptr || ctx->allocator == nullptr || ctx->physical_device == nullptr) { +void GraphicContext::LogMemoryBudget() const { + if (allocator == nullptr || physical_device == nullptr) { return; } - const auto& properties = ctx->GetPhysicalDeviceMemoryProperties(); + const auto& properties = GetPhysicalDeviceMemoryProperties(); VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {}; - vmaGetHeapBudgets(ctx->allocator, budgets); + vmaGetHeapBudgets(allocator, budgets); for (uint32_t i = 0; i < properties.memoryHeapCount; i++) { LOGF("VMA heap %u: usage=%" PRIu64 ", budget=%" PRIu64 ", allocation=%" PRIu64 ", blocks=%" PRIu64 "\n", @@ -113,115 +111,110 @@ void VulkanLogMemoryBudget(GraphicContext* ctx) { } } -void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer) { +void GraphicContext::CreateBuffer(uint64_t size, VulkanBuffer& buffer) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr || - buffer->buffer != nullptr || buffer->memory.allocation != nullptr || size == 0); + EXIT_IF(allocator == nullptr || buffer.buffer != nullptr || + buffer.memory.allocation != nullptr || size == 0); vk::BufferCreateInfo buffer_info {}; buffer_info.sType = vk::StructureType::eBufferCreateInfo; buffer_info.size = size; - buffer_info.usage = buffer->usage; + buffer_info.usage = buffer.usage; buffer_info.sharingMode = vk::SharingMode::eExclusive; VmaAllocationCreateInfo alloc_info {}; alloc_info.requiredFlags = - static_cast(buffer->memory.property); + static_cast(buffer.memory.property); alloc_info.preferredFlags = - static_cast(buffer->memory.preferred_property); + static_cast(buffer.memory.preferred_property); vk::Buffer::CType native_buffer = VK_NULL_HANDLE; const auto result = static_cast(vmaCreateBuffer( - ctx->allocator, static_cast(buffer_info), - &alloc_info, &native_buffer, &buffer->memory.allocation, &buffer->memory.allocation_info)); - buffer->buffer = native_buffer; + allocator, static_cast(buffer_info), &alloc_info, + &native_buffer, &buffer.memory.allocation, &buffer.memory.allocation_info)); + buffer.buffer = native_buffer; if (result != vk::Result::eSuccess) { - VulkanLogMemoryBudget(ctx); + LogMemoryBudget(); } EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); - ctx->device.getBufferMemoryRequirements(buffer->buffer, &buffer->memory.requirements); - buffer->memory.type = buffer->memory.allocation_info.memoryType; - buffer->memory.memory = buffer->memory.allocation_info.deviceMemory; - buffer->memory.offset = buffer->memory.allocation_info.offset; - buffer->memory.unique_id = VulkanNextMemoryUniqueId(); - buffer->buffer_size = size; - VulkanTrackAllocation(&buffer->memory); + device.getBufferMemoryRequirements(buffer.buffer, &buffer.memory.requirements); + buffer.memory.type = buffer.memory.allocation_info.memoryType; + buffer.memory.memory = buffer.memory.allocation_info.deviceMemory; + buffer.memory.offset = buffer.memory.allocation_info.offset; + buffer.memory.unique_id = VulkanNextMemoryUniqueId(); + buffer.buffer_size = size; + VulkanTrackAllocation(buffer.memory); } -void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer) { +void GraphicContext::DeleteBuffer(VulkanBuffer& buffer) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr || - buffer->buffer == nullptr || buffer->memory.allocation == nullptr); + EXIT_IF(allocator == nullptr || buffer.buffer == nullptr || + buffer.memory.allocation == nullptr); - VulkanUntrackAllocation(&buffer->memory); - vmaDestroyBuffer(ctx->allocator, buffer->buffer, buffer->memory.allocation); - buffer->buffer = nullptr; - buffer->memory.memory = nullptr; - buffer->memory.allocation = nullptr; - buffer->memory.allocation_info = {}; - buffer->memory.offset = 0; + VulkanUntrackAllocation(buffer.memory); + vmaDestroyBuffer(allocator, buffer.buffer, buffer.memory.allocation); + buffer.buffer = nullptr; + buffer.memory.memory = nullptr; + buffer.memory.allocation = nullptr; + buffer.memory.allocation_info = {}; + buffer.memory.offset = 0; } -bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info, - VulkanImage* image) { +bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanImage& image) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr || - image->image != nullptr || image->memory.allocation != nullptr); + EXIT_IF(allocator == nullptr || image.image != nullptr || image.memory.allocation != nullptr); - auto& memory = image->memory; + auto& memory = image.memory; VmaAllocationCreateInfo alloc_info {}; alloc_info.requiredFlags = static_cast(memory.property); alloc_info.preferredFlags = static_cast(memory.preferred_property); vk::Image::CType native_image = VK_NULL_HANDLE; - const auto result = static_cast(vmaCreateImage( - ctx->allocator, static_cast(image_info), - &alloc_info, &native_image, &memory.allocation, &memory.allocation_info)); - image->image = native_image; + const auto result = static_cast( + vmaCreateImage(allocator, static_cast(image_info), + &alloc_info, &native_image, &memory.allocation, &memory.allocation_info)); + image.image = native_image; if (result != vk::Result::eSuccess) { - VulkanLogMemoryBudget(ctx); + LogMemoryBudget(); return false; } - ctx->device.getImageMemoryRequirements(image->image, &memory.requirements); + device.getImageMemoryRequirements(image.image, &memory.requirements); memory.type = memory.allocation_info.memoryType; memory.memory = memory.allocation_info.deviceMemory; memory.offset = memory.allocation_info.offset; memory.unique_id = VulkanNextMemoryUniqueId(); - VulkanTrackAllocation(&memory); + VulkanTrackAllocation(memory); return true; } -void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image) { +void GraphicContext::DeleteImage(VulkanImage& image) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr || - image->image == nullptr || image->memory.allocation == nullptr); + EXIT_IF(allocator == nullptr || image.image == nullptr || image.memory.allocation == nullptr); - auto& memory = image->memory; - VulkanUntrackAllocation(&memory); - vmaDestroyImage(ctx->allocator, image->image, memory.allocation); - image->image = nullptr; + auto& memory = image.memory; + VulkanUntrackAllocation(memory); + vmaDestroyImage(allocator, image.image, memory.allocation); + image.image = nullptr; memory.memory = nullptr; memory.allocation = nullptr; memory.allocation_info = {}; memory.offset = 0; } -void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data) { +void GraphicContext::MapMemory(VulkanMemory& memory, void*& data) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr || memory == nullptr || data == nullptr || ctx->allocator == nullptr || - memory->allocation == nullptr); - EXIT_NOT_IMPLEMENTED(static_cast(vmaMapMemory(ctx->allocator, memory->allocation, - data)) != vk::Result::eSuccess); + EXIT_IF(allocator == nullptr || memory.allocation == nullptr); + EXIT_NOT_IMPLEMENTED(static_cast(vmaMapMemory(allocator, memory.allocation, + &data)) != vk::Result::eSuccess); } -void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory) { +void GraphicContext::UnmapMemory(VulkanMemory& memory) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(ctx == nullptr || memory == nullptr || ctx->allocator == nullptr || - memory->allocation == nullptr); - vmaUnmapMemory(ctx->allocator, memory->allocation); + EXIT_IF(allocator == nullptr || memory.allocation == nullptr); + vmaUnmapMemory(allocator, memory.allocation); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/vma.h b/src/graphics/host_gpu/vma.h index ab4cc572c..a656b676f 100644 --- a/src/graphics/host_gpu/vma.h +++ b/src/graphics/host_gpu/vma.h @@ -2,28 +2,13 @@ #define EMULATOR_SRC_GRAPHICS_HOST_GPU_VMA_H_ #include "common/common.h" -#include "graphics/host_gpu/vulkanCommon.h" +#include "graphics/host_gpu/graphicContext.h" namespace Libs::Graphics { -struct GraphicContext; -struct VulkanBuffer; -struct VulkanImage; -struct VulkanMemory; - -bool VulkanCreateAllocator(GraphicContext* ctx); -void VulkanDestroyAllocator(GraphicContext* ctx); uint64_t VulkanNextMemoryUniqueId(); -void VulkanTrackAllocation(const VulkanMemory* memory); -void VulkanUntrackAllocation(const VulkanMemory* memory); -void VulkanLogMemoryBudget(GraphicContext* ctx); -void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer); -void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer); -bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info, - VulkanImage* image); -void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image); -void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data); -void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory); +void VulkanTrackAllocation(const VulkanMemory& memory); +void VulkanUntrackAllocation(const VulkanMemory& memory); } // namespace Libs::Graphics diff --git a/src/graphics/presentation/displayBuffer.h b/src/graphics/presentation/displayBuffer.h index ab2e7ecfd..bd7726ede 100644 --- a/src/graphics/presentation/displayBuffer.h +++ b/src/graphics/presentation/displayBuffer.h @@ -18,9 +18,9 @@ struct DisplayBufferImage { }; DisplayBufferImage DisplayBufferFind(uint64_t addr, bool render_target = false); -int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer* buffer, int handle, int index, - int flip_mode, int64_t flip_arg, uint64_t* request_id); -uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer* buffer); +int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer& buffer, int handle, int index, + int flip_mode, int64_t flip_arg, uint64_t& request_id); +uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer& buffer); void DisplayBufferCompleteFlipFromGpu(uint64_t request_id); void DisplayBufferWaitForFlipQueueSlot(); diff --git a/src/graphics/presentation/videoOut.cpp b/src/graphics/presentation/videoOut.cpp index 10cc818a8..d384c2550 100644 --- a/src/graphics/presentation/videoOut.cpp +++ b/src/graphics/presentation/videoOut.cpp @@ -172,16 +172,16 @@ public: ~FlipQueue() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(FlipQueue); - bool Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRequestSource source, - uint64_t* request_id); - void Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer); - uint64_t PrepareNextCpu(Graphics::CommandBuffer* buffer); + bool Reserve(VideoOutConfig& cfg, int index, int64_t flip_arg, FlipRequestSource source, + uint64_t& request_id); + void Prepare(uint64_t request_id, Graphics::CommandBuffer& buffer); + uint64_t PrepareNextCpu(Graphics::CommandBuffer& buffer); void Complete(uint64_t request_id); void WaitForSubmitSlot(); bool Flip(uint32_t micros); - bool HasPending(VideoOutConfig* cfg, int start_index, int count); - void GetFlipStatus(VideoOutConfig* cfg, VideoOutFlipStatus* out); - void Wait(VideoOutConfig* cfg, int index); + bool HasPending(VideoOutConfig& cfg, int start_index, int count); + void GetFlipStatus(VideoOutConfig& cfg, VideoOutFlipStatus& out); + void Wait(VideoOutConfig& cfg, int index); private: enum class RequestState { Reserved, Recording, Ready, Presenting }; @@ -225,26 +225,15 @@ public: void Init(uint32_t width, uint32_t height); - Graphics::GraphicContext* GetGraphicCtx() { - Common::LockGuard lock(m_mutex); - - if (m_graphic_ctx == nullptr) { - m_graphic_ctx = Graphics::WindowGetGraphicContext(); - } - - return m_graphic_ctx; - } - FlipQueue& GetFlipQueue() { return m_flip_queue; } void VblankBegin(); void VblankEnd(); private: - Common::Mutex m_mutex; - VideoOutConfig m_video_out_ctx[VIDEO_OUT_NUM_MAX]; - Graphics::GraphicContext* m_graphic_ctx = nullptr; - FlipQueue m_flip_queue; + Common::Mutex m_mutex; + VideoOutConfig m_video_out_ctx[VIDEO_OUT_NUM_MAX]; + FlipQueue m_flip_queue; }; static VideoOutContext* g_video_out_context = nullptr; @@ -438,14 +427,12 @@ static void WaitForNextVblank() { } while (next_vblank_ticks <= now); } -static bool IsFlipDue(VideoOutConfig* cfg) { - EXIT_IF(cfg == nullptr); +static bool IsFlipDue(VideoOutConfig& cfg) { + Common::LockGuard lock(cfg.mutex); - Common::LockGuard lock(cfg->mutex); + const int interval = cfg.flip_rate + 1; - const int interval = cfg->flip_rate + 1; - - return interval <= 1 || (cfg->vblank_status.count % static_cast(interval)) == 0; + return interval <= 1 || (cfg.vblank_status.count % static_cast(interval)) == 0; } static bool IsValidBufferIndex(int index) { @@ -461,8 +448,8 @@ static bool IsValidFlipMode(int mode) { } static int ReserveFlipRequest(int handle, int index, int flip_mode, int64_t flip_arg, - FlipRequestSource source, uint64_t* request_id) { - EXIT_IF(g_video_out_context == nullptr || request_id == nullptr); + FlipRequestSource source, uint64_t& request_id) { + EXIT_IF(g_video_out_context == nullptr); auto* video_out = g_video_out_context->Get(handle); if (video_out == nullptr) { @@ -481,7 +468,7 @@ static int ReserveFlipRequest(int handle, int index, int flip_mode, int64_t flip (video_out->unregistering[index] || video_out->buffers[index].buffer_vulkan == nullptr))) { return VIDEO_OUT_ERROR_INVALID_INDEX; } - if (!g_video_out_context->GetFlipQueue().Reserve(video_out, index, flip_arg, source, + if (!g_video_out_context->GetFlipQueue().Reserve(*video_out, index, flip_arg, source, request_id)) { return VIDEO_OUT_ERROR_FLIP_QUEUE_FULL; } @@ -502,7 +489,7 @@ static Graphics::VideoOutInfo MakeVideoOutInfo(const VideoOutBufferAttribute2& a EXIT("unsupported or invalid video-out surface attributes\n"); } Graphics::VideoOutPixelFormatInfo pixel_format {}; - if (!Graphics::DecodeVideoOutPixelFormat(attribute.pixel_format, &pixel_format)) { + if (!Graphics::DecodeVideoOutPixelFormat(attribute.pixel_format, pixel_format)) { EXIT("unsupported video-out pixel format: 0x%016" PRIx64 "\n", attribute.pixel_format); } const auto tile_mode = @@ -511,7 +498,7 @@ static Graphics::VideoOutInfo MakeVideoOutInfo(const VideoOutBufferAttribute2& a Graphics::TileGetTexturePitch(pixel_format.guest_format, attribute.width, 1, tile_mode); Graphics::TileSizeAlign total {}; Graphics::TileGetTextureTotalSize(pixel_format.guest_format, attribute.width, attribute.height, - 1, pitch, 1, tile_mode, false, &total); + 1, pitch, 1, tile_mode, false, total); if (total.size == 0 || total.align != 65536 || (address & (total.align - 1u)) != 0) { EXIT("invalid video-out surface footprint or alignment\n"); } @@ -606,7 +593,7 @@ void VideoOutContext::Close(int handle) { EXIT("video-out handle is already closing\n"); } config.closing = true; - if (m_flip_queue.HasPending(&config, VIDEO_OUT_BUFFER_INDEX_BLACK, + if (m_flip_queue.HasPending(config, VIDEO_OUT_BUFFER_INDEX_BLACK, VIDEO_OUT_BUFFER_NUM_MAX - VIDEO_OUT_BUFFER_INDEX_BLACK)) { EXIT("cannot close video-out handle with pending flips\n"); } @@ -629,10 +616,7 @@ void VideoOutContext::Close(int handle) { } } if (!images.empty()) { - if (Graphics::g_render_ctx == nullptr) { - EXIT("cannot unregister video-out surfaces without a render context\n"); - } - Graphics::g_render_ctx->GetTextureCache()->UnregisterVideoOutSurfaces(images); + Graphics::GetRenderContext().GetTextureCache().UnregisterVideoOutSurfaces(images); } for (auto& buffer: config.buffers) { buffer = VideoOutBufferInfo {}; @@ -722,8 +706,8 @@ Presentation::DisplayBufferImage VideoOutContext::FindImage(const void* buffer, ret.size = ctx.buffers[j].buffer_size; ret.pitch = ctx.buffers[j].buffer_pitch; ret.index = j - set.start_index; - Graphics::g_render_ctx->GetTextureCache()->RefreshVideoOut(ret.image, - render_target); + Graphics::GetRenderContext().GetTextureCache().RefreshVideoOut(*ret.image, + render_target); return ret; } } @@ -732,9 +716,8 @@ Presentation::DisplayBufferImage VideoOutContext::FindImage(const void* buffer, return ret; } -bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRequestSource source, - uint64_t* request_id) { - EXIT_IF(cfg == nullptr || request_id == nullptr); +bool FlipQueue::Reserve(VideoOutConfig& cfg, int index, int64_t flip_arg, FlipRequestSource source, + uint64_t& request_id) { Common::LockGuard lock(m_mutex); if (m_requests.size() + m_cpu_requests.size() >= VIDEO_OUT_FLIP_QUEUE_CAPACITY) { @@ -744,7 +727,7 @@ bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRe Request r {}; r.id = m_next_request_id++; - r.cfg = cfg; + r.cfg = &cfg; r.index = index; r.flip_arg = flip_arg; r.submit_ptc = LibKernel::KernelGetProcessTimeCounter(); @@ -752,20 +735,18 @@ bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRe r.state = RequestState::Reserved; pending.push_back(r); - *request_id = r.id; + request_id = r.id; - cfg->flip_status.flipPendingNum = static_cast(m_requests.size() + m_cpu_requests.size()); - cfg->flip_status.submitProcessTimeCounter = r.submit_ptc; + cfg.flip_status.flipPendingNum = static_cast(m_requests.size() + m_cpu_requests.size()); + cfg.flip_status.submitProcessTimeCounter = r.submit_ptc; if (source == FlipRequestSource::GpuEop) { - cfg->flip_status.gcQueueNum++; + cfg.flip_status.gcQueueNum++; } return true; } -void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer) { - EXIT_IF(buffer == nullptr); - +void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer& buffer) { VideoOutConfig* cfg = nullptr; int index = 0; { @@ -813,9 +794,9 @@ void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer) { } } } - auto* frame = special ? Graphics::WindowPrepareBlankFrame(buffer, width, height, + auto& frame = special ? Graphics::WindowPrepareBlankFrame(buffer, width, height, index == VIDEO_OUT_BUFFER_INDEX_BLACK) - : Graphics::WindowPrepareFrame(buffer, source); + : Graphics::WindowPrepareFrame(buffer, *source); Common::LockGuard lock(m_mutex); auto request = std::find_if(m_requests.begin(), m_requests.end(), @@ -824,10 +805,10 @@ void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer) { request->frame != nullptr) { EXIT("video-out request changed while recording, id=%" PRIu64 "\n", request_id); } - request->frame = frame; + request->frame = &frame; } -uint64_t FlipQueue::PrepareNextCpu(Graphics::CommandBuffer* buffer) { +uint64_t FlipQueue::PrepareNextCpu(Graphics::CommandBuffer& buffer) { uint64_t request_id = 0; { Common::LockGuard lock(m_mutex); @@ -862,11 +843,11 @@ void FlipQueue::WaitForSubmitSlot() { } } -void FlipQueue::Wait(VideoOutConfig* cfg, int index) { +void FlipQueue::Wait(VideoOutConfig& cfg, int index) { Common::LockGuard lock(m_mutex); - auto has_request = [this, cfg, index] { - auto matches = [cfg, index](const auto& r) { return r.cfg == cfg && r.index == index; }; + auto has_request = [this, &cfg, index] { + auto matches = [&cfg, index](const auto& r) { return r.cfg == &cfg && r.index == index; }; return std::any_of(m_requests.begin(), m_requests.end(), matches) || std::any_of(m_cpu_requests.begin(), m_cpu_requests.end(), matches); }; @@ -875,13 +856,13 @@ void FlipQueue::Wait(VideoOutConfig* cfg, int index) { } } -bool FlipQueue::HasPending(VideoOutConfig* cfg, int start_index, int count) { - if (cfg == nullptr || count <= 0 || start_index > INT_MAX - count) { +bool FlipQueue::HasPending(VideoOutConfig& cfg, int start_index, int count) { + if (count <= 0 || start_index > INT_MAX - count) { EXIT("invalid video-out pending-flip query range\n"); } Common::LockGuard lock(m_mutex); auto matches = [&](const auto& request) { - return request.cfg == cfg && request.index >= start_index && + return request.cfg == &cfg && request.index >= start_index && request.index < start_index + count; }; return std::any_of(m_requests.begin(), m_requests.end(), matches) || @@ -910,7 +891,7 @@ bool FlipQueue::Flip(uint32_t micros) { m_processing = true; auto r = m_requests.front(); m_mutex.Unlock(); - if (!IsFlipDue(r.cfg)) { + if (!IsFlipDue(*r.cfg)) { Common::LockGuard lock(m_mutex); m_processing = false; return false; @@ -924,7 +905,7 @@ bool FlipQueue::Flip(uint32_t micros) { m_requests.front().state = RequestState::Presenting; m_mutex.Unlock(); - Graphics::WindowPresentFrame(r.frame); + Graphics::WindowPresentFrame(*r.frame); m_mutex.Lock(); if (m_requests.empty() || m_requests.front().id != r.id || @@ -962,13 +943,10 @@ bool FlipQueue::Flip(uint32_t micros) { return true; } -void FlipQueue::GetFlipStatus(VideoOutConfig* cfg, VideoOutFlipStatus* out) { - EXIT_IF(cfg == nullptr); - EXIT_IF(out == nullptr); - +void FlipQueue::GetFlipStatus(VideoOutConfig& cfg, VideoOutFlipStatus& out) { Common::LockGuard lock(m_mutex); - *out = cfg->flip_status; + out = cfg.flip_status; } bool VideoOutFlipWindow(uint32_t micros) { @@ -1116,10 +1094,10 @@ KYTY_SYSV_ABI int VideoOutAddOutputModeEvent(LibKernel::EventQueue::KernelEqueue return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::OutputMode, udata); } -static int RegisterBuffersInternal(VideoOutConfig* ctx, int set_id, int start_index, +static int RegisterBuffersInternal(VideoOutConfig& ctx, int set_id, int start_index, const void* const* addresses, int buffer_num, const std::vector& infos) { - if (ctx == nullptr || addresses == nullptr || buffer_num <= 0 || + if (addresses == nullptr || buffer_num <= 0 || infos.size() != static_cast(buffer_num)) { EXIT("invalid internal video-out buffer registration arguments\n"); } @@ -1128,31 +1106,29 @@ static int RegisterBuffersInternal(VideoOutConfig* ctx, int set_id, int start_in } Graphics::WindowWaitForGraphicInitialized(); Graphics::GraphicsRenderCreateContext(); - auto* graphic_ctx = g_video_out_context->GetGraphicCtx(); - Common::LockGuard lock(ctx->mutex); - if (ctx->closing) { + Common::LockGuard lock(ctx.mutex); + if (ctx.closing) { EXIT("cannot register buffers on a closing video-out handle\n"); } - if (std::any_of(ctx->buffers_sets.begin(), ctx->buffers_sets.end(), + if (std::any_of(ctx.buffers_sets.begin(), ctx.buffers_sets.end(), [set_id](const auto& set) { return set.set_id == set_id; })) { return VIDEO_OUT_ERROR_INVALID_INDEX; } for (int i = 0; i < buffer_num; i++) { - if (ctx->unregistering[start_index + i]) { + if (ctx.unregistering[start_index + i]) { EXIT("video-out buffer registration raced with unregistration\n"); } - if (ctx->buffers[start_index + i].buffer != nullptr) { + if (ctx.buffers[start_index + i].buffer != nullptr) { return VIDEO_OUT_ERROR_SLOT_OCCUPIED; } } - auto images = - Graphics::g_render_ctx->GetTextureCache()->RegisterVideoOutSurfaces(graphic_ctx, infos); + auto images = Graphics::GetRenderContext().GetTextureCache().RegisterVideoOutSurfaces(infos); if (images.size() != infos.size()) { EXIT("video-out texture cache returned an incomplete surface set\n"); } - ctx->buffers_sets.push_back({start_index, buffer_num, set_id}); + ctx.buffers_sets.push_back({start_index, buffer_num, set_id}); for (int i = 0; i < buffer_num; i++) { - auto& dst = ctx->buffers[i + start_index]; + auto& dst = ctx.buffers[i + start_index]; dst.set_id = set_id; dst.buffer = addresses[i]; dst.buffer_size = infos[i].size; @@ -1243,8 +1219,8 @@ KYTY_SYSV_ABI int VideoOutRegisterBuffers2(int handle, int set_index, int buffer infos.push_back(MakeVideoOutInfo(*attribute, data_address, metadata_address, compression)); } - return RegisterBuffersInternal(ctx, set_index, buffer_index_start, addresses.data(), buffer_num, - infos); + return RegisterBuffersInternal(*ctx, set_index, buffer_index_start, addresses.data(), + buffer_num, infos); } KYTY_SYSV_ABI int VideoOutSubmitChangeBufferAttribute2(int handle, int set_index, @@ -1309,10 +1285,10 @@ KYTY_SYSV_ABI int VideoOutUnregisterBuffers(int handle, int set_index) { } images.push_back(ctx->buffers[i].buffer_vulkan); } - if (g_video_out_context->GetFlipQueue().HasPending(ctx, set_it->start_index, set_it->num)) { + if (g_video_out_context->GetFlipQueue().HasPending(*ctx, set_it->start_index, set_it->num)) { EXIT("cannot unregister video-out buffers with pending flips\n"); } - Graphics::g_render_ctx->GetTextureCache()->UnregisterVideoOutSurfaces(images); + Graphics::GetRenderContext().GetTextureCache().UnregisterVideoOutSurfaces(images); for (int i = set_it->start_index; i < set_it->start_index + set_it->num; i++) { ctx->buffers[i] = VideoOutBufferInfo {}; ctx->unregistering[i] = false; @@ -1341,7 +1317,7 @@ KYTY_SYSV_ABI int VideoOutSubmitFlip(int handle, int index, int flip_mode, int64 uint64_t request_id = 0; const int result = - ReserveFlipRequest(handle, index, flip_mode, flip_arg, FlipRequestSource::Cpu, &request_id); + ReserveFlipRequest(handle, index, flip_mode, flip_arg, FlipRequestSource::Cpu, request_id); if (result == VIDEO_OUT_ERROR_INVALID_VALUE) { LOGF("\t unsupported flip_mode = %d\n", flip_mode); } @@ -1357,33 +1333,32 @@ KYTY_SYSV_ABI int VideoOutSubmitFlip(int handle, int index, int flip_mode, int64 namespace Libs::Presentation { -int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer* buffer, int handle, int index, - int flip_mode, int64_t flip_arg, uint64_t* request_id) { - EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr || - buffer == nullptr || request_id == nullptr); +int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer& buffer, int handle, int index, + int flip_mode, int64_t flip_arg, uint64_t& request_id) { + EXIT_IF(VideoOut::g_video_out_context == nullptr || buffer.IsInvalid()); const int result = VideoOut::ReserveFlipRequest( handle, index, flip_mode, flip_arg, VideoOut::FlipRequestSource::GpuEop, request_id); if (result != OK) { return result; } - VideoOut::g_video_out_context->GetFlipQueue().Prepare(*request_id, buffer); + VideoOut::g_video_out_context->GetFlipQueue().Prepare(request_id, buffer); return OK; } -uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer* buffer) { - EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr); +uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer& buffer) { + EXIT_IF(VideoOut::g_video_out_context == nullptr); return VideoOut::g_video_out_context->GetFlipQueue().PrepareNextCpu(buffer); } void DisplayBufferCompleteFlipFromGpu(uint64_t request_id) { - EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr); + EXIT_IF(VideoOut::g_video_out_context == nullptr); VideoOut::g_video_out_context->GetFlipQueue().Complete(request_id); } void DisplayBufferWaitForFlipQueueSlot() { - EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr); + EXIT_IF(VideoOut::g_video_out_context == nullptr); VideoOut::g_video_out_context->GetFlipQueue().WaitForSubmitSlot(); } @@ -1398,7 +1373,7 @@ void VideoOutWaitFlipDone(int handle, int index) { EXIT_IF(ctx == nullptr); EXIT_NOT_IMPLEMENTED(!IsValidBufferIndex(index)); - g_video_out_context->GetFlipQueue().Wait(ctx, index); + g_video_out_context->GetFlipQueue().Wait(*ctx, index); } KYTY_SYSV_ABI int VideoOutGetFlipStatus(int handle, VideoOutFlipStatus* status) { @@ -1415,7 +1390,7 @@ KYTY_SYSV_ABI int VideoOutGetFlipStatus(int handle, VideoOutFlipStatus* status) return VIDEO_OUT_ERROR_INVALID_HANDLE; } - g_video_out_context->GetFlipQueue().GetFlipStatus(ctx, status); + g_video_out_context->GetFlipQueue().GetFlipStatus(*ctx, *status); LOGF("\t count = %" PRIu64 "\n" "\t processTime = %" PRIu64 "\n" @@ -1443,7 +1418,7 @@ KYTY_SYSV_ABI int VideoOutIsFlipPending(int handle) { } VideoOutFlipStatus status {}; - g_video_out_context->GetFlipQueue().GetFlipStatus(ctx, &status); + g_video_out_context->GetFlipQueue().GetFlipStatus(*ctx, status); LOGF("\t flipPendingNum = %d\n", status.flipPendingNum); diff --git a/src/graphics/presentation/window.h b/src/graphics/presentation/window.h index 8001d4c91..d0bdca05b 100644 --- a/src/graphics/presentation/window.h +++ b/src/graphics/presentation/window.h @@ -14,15 +14,15 @@ struct PreparedFrame; vk::SurfaceCapabilitiesKHR* VulkanGetSurfaceCapabilities(); -GraphicContext* WindowGetGraphicContext(); +GraphicContext& WindowGetGraphicContext(); void WindowInit(uint32_t width, uint32_t height); void WindowRun(); void WindowWaitForGraphicInitialized(); -PreparedFrame* WindowPrepareFrame(CommandBuffer* buffer, VideoOutVulkanImage* image); -PreparedFrame* WindowPrepareBlankFrame(CommandBuffer* buffer, uint32_t width, uint32_t height, +PreparedFrame& WindowPrepareFrame(CommandBuffer& buffer, VideoOutVulkanImage& image); +PreparedFrame& WindowPrepareBlankFrame(CommandBuffer& buffer, uint32_t width, uint32_t height, bool opaque); -void WindowPresentFrame(PreparedFrame* frame); +void WindowPresentFrame(PreparedFrame& frame); } // namespace Libs::Graphics diff --git a/src/graphics/presentation/window/swapchain.cpp b/src/graphics/presentation/window/swapchain.cpp index b207e149f..e72f182da 100644 --- a/src/graphics/presentation/window/swapchain.cpp +++ b/src/graphics/presentation/window/swapchain.cpp @@ -138,16 +138,15 @@ static PreparedFramePool* GetPreparedFramePool() { return pool; } -static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk::Format format) { - EXIT_IF(frame == nullptr); +static void ConfigurePreparedFrame(PreparedFrame& frame, vk::Extent2D extent, vk::Format format) { EXIT_IF(g_window_ctx == nullptr); if (extent.width == 0 || extent.height == 0 || format == vk::Format::eUndefined) { EXIT("unsupported prepared frame, extent=%ux%u format=%d\n", extent.width, extent.height, static_cast(format)); } - auto* ctx = &g_window_ctx->graphic_ctx; - auto& dst = frame->image; + auto& graphics = g_window_ctx->graphic_ctx; + auto& dst = frame.image; const bool compatible = dst.image != nullptr && dst.extent.width == extent.width && dst.extent.height == extent.height && dst.format == format; if (compatible) { @@ -155,7 +154,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk } if (dst.image != nullptr) { EXIT_IF(!dst.view_cache.views.empty()); - VulkanDeleteImage(ctx, &dst); + graphics.DeleteImage(dst); dst.memory = {}; } @@ -178,7 +177,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk create.usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst; create.sharingMode = vk::SharingMode::eExclusive; create.samples = vk::SampleCountFlagBits::e1; - if (!VulkanCreateImage(ctx, create, &dst)) { + if (!graphics.CreateImage(create, dst)) { EXIT("failed to allocate prepared presentation image, extent=%ux%u format=%d\n", dst.extent.width, dst.extent.height, static_cast(dst.format)); } @@ -188,28 +187,22 @@ VulkanSwapchain::~VulkanSwapchain() = default; [[maybe_unused]] static vk::SwapchainKHR VulkanCreateSwapchainInternal( vk::Device device, vk::SurfaceKHR surface, uint32_t width, uint32_t height, - uint32_t image_count, SurfaceCapabilities* r, vk::Format* swapchain_format, - vk::Extent2D* swapchain_extent, std::unique_ptr* swapchain_images, - std::unique_ptr* swapchain_image_views, uint32_t* swapchain_images_count) { + uint32_t image_count, SurfaceCapabilities& r, vk::Format& swapchain_format, + vk::Extent2D& swapchain_extent, std::unique_ptr& swapchain_images, + std::unique_ptr& swapchain_image_views, uint32_t& swapchain_images_count) { EXIT_IF(device == nullptr); EXIT_IF(surface == nullptr); - EXIT_IF(r == nullptr); - EXIT_IF(swapchain_format == nullptr); - EXIT_IF(swapchain_extent == nullptr); - EXIT_IF(swapchain_images == nullptr); - EXIT_IF(swapchain_image_views == nullptr); - EXIT_IF(swapchain_images_count == nullptr); - EXIT_NOT_IMPLEMENTED(r->formats.empty()); + EXIT_NOT_IMPLEMENTED(r.formats.empty()); vk::Extent2D extent {}; - extent.width = std::clamp(width, r->capabilities.minImageExtent.width, - r->capabilities.maxImageExtent.width); - extent.height = std::clamp(height, r->capabilities.minImageExtent.height, - r->capabilities.maxImageExtent.height); + extent.width = + std::clamp(width, r.capabilities.minImageExtent.width, r.capabilities.maxImageExtent.width); + extent.height = std::clamp(height, r.capabilities.minImageExtent.height, + r.capabilities.maxImageExtent.height); image_count = - std::clamp(image_count, r->capabilities.minImageCount, r->capabilities.maxImageCount); + std::clamp(image_count, r.capabilities.minImageCount, r.capabilities.maxImageCount); vk::SwapchainCreateInfoKHR create_info {}; create_info.sType = vk::StructureType::eSwapchainCreateInfoKHR; @@ -218,14 +211,14 @@ VulkanSwapchain::~VulkanSwapchain() = default; create_info.surface = surface; create_info.minImageCount = image_count; - if (r->format_unorm_bgra32) { + if (r.format_unorm_bgra32) { create_info.imageFormat = vk::Format::eB8G8R8A8Unorm; create_info.imageColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear; - } else if (r->format_srgb_bgra32) { + } else if (r.format_srgb_bgra32) { create_info.imageFormat = vk::Format::eB8G8R8A8Srgb; create_info.imageColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear; } else { - const auto& format = r->formats[0]; + const auto& format = r.formats[0]; create_info.imageFormat = format.format; create_info.imageColorSpace = format.colorSpace; } @@ -237,14 +230,14 @@ VulkanSwapchain::~VulkanSwapchain() = default; create_info.imageSharingMode = vk::SharingMode::eExclusive; create_info.queueFamilyIndexCount = 0; create_info.pQueueFamilyIndices = nullptr; - create_info.preTransform = r->capabilities.currentTransform; + create_info.preTransform = r.capabilities.currentTransform; create_info.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque; create_info.presentMode = vk::PresentModeKHR::eFifo; create_info.clipped = VK_TRUE; create_info.oldSwapchain = nullptr; - *swapchain_format = create_info.imageFormat; - *swapchain_extent = extent; + swapchain_format = create_info.imageFormat; + swapchain_extent = extent; vk::SwapchainKHR swapchain = nullptr; @@ -258,19 +251,19 @@ VulkanSwapchain::~VulkanSwapchain() = default; }); EXIT_NOT_IMPLEMENTED(images.empty()); - *swapchain_images_count = static_cast(images.size()); - *swapchain_images = std::make_unique(images.size()); - std::copy(images.begin(), images.end(), swapchain_images->get()); + swapchain_images_count = static_cast(images.size()); + swapchain_images = std::make_unique(images.size()); + std::copy(images.begin(), images.end(), swapchain_images.get()); - *swapchain_image_views = std::make_unique(*swapchain_images_count); - for (uint32_t i = 0; i < *swapchain_images_count; i++) { + swapchain_image_views = std::make_unique(swapchain_images_count); + for (uint32_t i = 0; i < swapchain_images_count; i++) { vk::ImageViewCreateInfo create_info {}; create_info.sType = vk::StructureType::eImageViewCreateInfo; create_info.pNext = nullptr; create_info.flags = {}; - create_info.image = (*swapchain_images)[i]; + create_info.image = (swapchain_images)[i]; create_info.viewType = vk::ImageViewType::e2D; - create_info.format = *swapchain_format; + create_info.format = swapchain_format; create_info.components.r = vk::ComponentSwizzle::eIdentity; create_info.components.g = vk::ComponentSwizzle::eIdentity; create_info.components.b = vk::ComponentSwizzle::eIdentity; @@ -282,19 +275,19 @@ VulkanSwapchain::~VulkanSwapchain() = default; create_info.subresourceRange.levelCount = 1; RequireVulkanSuccess( - device.createImageView(&create_info, nullptr, &((*swapchain_image_views)[i])), + device.createImageView(&create_info, nullptr, &((swapchain_image_views)[i])), "vkCreateImageView"); - EXIT_IF((*swapchain_image_views)[i] == nullptr); + EXIT_IF((swapchain_image_views)[i] == nullptr); } return swapchain; } -VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count) { +VulkanSwapchain* VulkanCreateSwapchain(uint32_t image_count) { EXIT_IF(g_window_ctx == nullptr); - EXIT_IF(ctx == nullptr); - EXIT_IF(ctx->screen_width == 0); - EXIT_IF(ctx->screen_height == 0); + auto& graphics = g_window_ctx->graphic_ctx; + EXIT_IF(graphics.screen_width == 0); + EXIT_IF(graphics.screen_height == 0); Common::LockGuard lock(g_window_ctx->mutex); @@ -302,9 +295,9 @@ VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count auto* s = swapchain_owner.get(); s->swapchain = VulkanCreateSwapchainInternal( - ctx->device, g_window_ctx->surface, ctx->screen_width, ctx->screen_height, image_count, - g_window_ctx->surface_capabilities, &s->swapchain_format, &s->swapchain_extent, - &s->swapchain_images, &s->swapchain_image_views, &s->swapchain_images_count); + graphics.device, g_window_ctx->surface, graphics.screen_width, graphics.screen_height, + image_count, *g_window_ctx->surface_capabilities, s->swapchain_format, s->swapchain_extent, + s->swapchain_images, s->swapchain_image_views, s->swapchain_images_count); if (s->swapchain == nullptr) { EXIT("Could not create swapchain"); } @@ -320,12 +313,12 @@ VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count s->image_acquired_semaphores = std::make_unique(s->swapchain_images_count); s->render_complete_semaphores = std::make_unique(s->swapchain_images_count); for (uint32_t i = 0; i < s->swapchain_images_count; i++) { - auto result = - ctx->device.createSemaphore(&semaphore_info, nullptr, &s->image_acquired_semaphores[i]); + auto result = graphics.device.createSemaphore(&semaphore_info, nullptr, + &s->image_acquired_semaphores[i]); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); - result = ctx->device.createSemaphore(&semaphore_info, nullptr, - &s->render_complete_semaphores[i]); + result = graphics.device.createSemaphore(&semaphore_info, nullptr, + &s->render_complete_semaphores[i]); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); } GetPreparedFramePool()->EnsureCapacity(s->swapchain_images_count, s->swapchain_format); @@ -333,38 +326,39 @@ VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count return swapchain_owner.release(); } -static void VulkanDeleteSwapchain(GraphicContext* ctx, VulkanSwapchain* s) { - if (ctx == nullptr || s == nullptr) { +static void VulkanDeleteSwapchain(VulkanSwapchain* s) { + if (s == nullptr) { return; } - auto swapchain_owner = std::unique_ptr(s); + auto swapchain_owner = std::unique_ptr(s); + auto& graphics = g_window_ctx->graphic_ctx; - Transfer::WaitForGraphicsIdle(ctx); + Transfer::WaitForGraphicsIdle(); if (s->image_acquired_semaphores != nullptr) { for (uint32_t i = 0; i < s->swapchain_images_count; i++) { if (s->image_acquired_semaphores[i] != nullptr) { - ctx->device.destroySemaphore(s->image_acquired_semaphores[i], nullptr); + graphics.device.destroySemaphore(s->image_acquired_semaphores[i], nullptr); } } } if (s->render_complete_semaphores != nullptr) { for (uint32_t i = 0; i < s->swapchain_images_count; i++) { if (s->render_complete_semaphores[i] != nullptr) { - ctx->device.destroySemaphore(s->render_complete_semaphores[i], nullptr); + graphics.device.destroySemaphore(s->render_complete_semaphores[i], nullptr); } } } if (s->swapchain_image_views != nullptr) { for (uint32_t i = 0; i < s->swapchain_images_count; i++) { if (s->swapchain_image_views[i] != nullptr) { - ctx->device.destroyImageView(s->swapchain_image_views[i], nullptr); + graphics.device.destroyImageView(s->swapchain_image_views[i], nullptr); } } } if (s->swapchain != nullptr) { - ctx->device.destroySwapchainKHR(s->swapchain, nullptr); + graphics.device.destroySwapchainKHR(s->swapchain, nullptr); } } @@ -382,7 +376,7 @@ static void VulkanRefreshSurfaceSize() { } VulkanGetSurfaceCapabilities(g_window_ctx->graphic_ctx.physical_device, g_window_ctx->surface, - g_window_ctx->surface_capabilities); + *g_window_ctx->surface_capabilities); } static void VulkanRecreateSwapchain() { @@ -390,61 +384,60 @@ static void VulkanRecreateSwapchain() { LOGF("Recreating Vulkan swapchain\n"); VulkanRefreshSurfaceSize(); - VulkanDeleteSwapchain(&g_window_ctx->graphic_ctx, g_window_ctx->swapchain); - g_window_ctx->swapchain = VulkanCreateSwapchain(&g_window_ctx->graphic_ctx, 2); + VulkanDeleteSwapchain(g_window_ctx->swapchain); + g_window_ctx->swapchain = VulkanCreateSwapchain(2); } -static void ValidatePreparedCommand(CommandBuffer* buffer) { - if (buffer == nullptr || buffer->IsInvalid() || - buffer->GetQueue() != GraphicContext::QUEUE_GFX) { +static void ValidatePreparedCommand(CommandBuffer& buffer) { + if (buffer.IsInvalid() || buffer.GetQueue() != GraphicContext::QUEUE_GFX) { EXIT("prepared frames must be recorded on the graphics queue\n"); } - EXIT_IF(g_render_ctx == nullptr); } -PreparedFrame* WindowPrepareFrame(CommandBuffer* buffer, VideoOutVulkanImage* image) { +PreparedFrame& WindowPrepareFrame(CommandBuffer& buffer, VideoOutVulkanImage& image) { KYTY_PROFILER_FUNCTION(); ValidatePreparedCommand(buffer); - if (image->format == vk::Format::eUndefined) { - EXIT("unsupported presentation source, image=%p\n", static_cast(image)); + if (image.format == vk::Format::eUndefined) { + EXIT("unsupported presentation source, image=%p\n", static_cast(&image)); } auto* frame = GetPreparedFramePool()->Acquire(); - Common::LockGuard render_lock(g_render_ctx->GetMutex()); - g_render_ctx->GetTextureCache()->RefreshVideoOut(image); - ConfigurePreparedFrame(frame, image->extent, image->format); - const std::array copies {ImageImageCopy { - .src_image = image, .width = image->extent.width, .height = image->extent.height}}; - Transfer::CopyImage(buffer, copies, &frame->image, vk::ImageLayout::eTransferSrcOptimal); - return frame; + Common::LockGuard render_lock(GetRenderContext().GetMutex()); + GetRenderContext().GetTextureCache().RefreshVideoOut(image); + ConfigurePreparedFrame(*frame, image.extent, image.format); + ImageImageCopy copy {image}; + copy.width = image.extent.width; + copy.height = image.extent.height; + const std::array copies {copy}; + Transfer::CopyImage(buffer, copies, frame->image, vk::ImageLayout::eTransferSrcOptimal); + return *frame; } -PreparedFrame* WindowPrepareBlankFrame(CommandBuffer* buffer, uint32_t width, uint32_t height, +PreparedFrame& WindowPrepareBlankFrame(CommandBuffer& buffer, uint32_t width, uint32_t height, bool opaque) { KYTY_PROFILER_FUNCTION(); ValidatePreparedCommand(buffer); auto* pool = GetPreparedFramePool(); auto format = pool->GetFormat(); auto* frame = pool->Acquire(); - Common::LockGuard render_lock(g_render_ctx->GetMutex()); - ConfigurePreparedFrame(frame, {width, height}, format); + Common::LockGuard render_lock(GetRenderContext().GetMutex()); + ConfigurePreparedFrame(*frame, {width, height}, format); vk::ClearColorValue clear {}; clear.float32[3] = opaque ? 1.0f : 0.0f; - Transfer::ClearColorImage(buffer, &frame->image, clear); - return frame; + Transfer::ClearColorImage(buffer, frame->image, clear); + return *frame; } -void WindowPresentFrame(PreparedFrame* frame) { +void WindowPresentFrame(PreparedFrame& frame) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(frame == nullptr); EXIT_IF(g_window_ctx == nullptr); EXIT_IF(g_window_ctx->swapchain == nullptr); struct ReleaseScope { PreparedFrame* frame; ~ReleaseScope() { GetPreparedFramePool()->Release(frame); } }; - ReleaseScope release {frame}; + ReleaseScope release {&frame}; if (g_window_ctx->window_hidden) { WindowUpdateIcon(); @@ -478,17 +471,17 @@ void WindowPresentFrame(PreparedFrame* frame) { default: EXIT("vkAcquireNextImageKHR failed: %s\n", VulkanToString(result).c_str()); } EXIT_NOT_IMPLEMENTED(swapchain->current_index == static_cast(-1)); - if (frame->present_commands == nullptr) { - frame->present_commands = std::make_unique(GraphicContext::QUEUE_GFX); + if (frame.present_commands == nullptr) { + frame.present_commands = std::make_unique(GraphicContext::QUEUE_GFX); } - frame->present_commands->WaitForFenceAndReset(); - auto& buffer = *frame->present_commands; + frame.present_commands->WaitForFenceAndReset(); + auto& buffer = *frame.present_commands; auto vk_buffer = buffer.Handle(); buffer.Begin(); - Transfer::BlitToSwapchain(&buffer, &frame->image, swapchain); + Transfer::BlitToSwapchain(buffer, frame.image, *swapchain); vk::ImageMemoryBarrier pre_present_barrier {}; pre_present_barrier.sType = vk::StructureType::eImageMemoryBarrier; diff --git a/src/graphics/presentation/window/vulkanWindow.cpp b/src/graphics/presentation/window/vulkanWindow.cpp index 46a711ac3..0ce31ace9 100644 --- a/src/graphics/presentation/window/vulkanWindow.cpp +++ b/src/graphics/presentation/window/vulkanWindow.cpp @@ -80,35 +80,35 @@ static bool HasLayer(const std::vector& layers, const char* } void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface, - SurfaceCapabilities* r) { - RequireVulkanSuccess(physical_device.getSurfaceCapabilitiesKHR(surface, &r->capabilities), + SurfaceCapabilities& r) { + RequireVulkanSuccess(physical_device.getSurfaceCapabilitiesKHR(surface, &r.capabilities), "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); - r->formats = EnumerateVulkan( // @suppress("Ambiguous problem") + r.formats = EnumerateVulkan( // @suppress("Ambiguous problem") "vkGetPhysicalDeviceSurfaceFormatsKHR", [&](uint32_t* count, vk::SurfaceFormatKHR* values) { return physical_device.getSurfaceFormatsKHR(surface, count, values); }); - EXIT_NOT_IMPLEMENTED(r->formats.empty()); + EXIT_NOT_IMPLEMENTED(r.formats.empty()); - r->present_modes = EnumerateVulkan( // @suppress("Ambiguous problem") + r.present_modes = EnumerateVulkan( // @suppress("Ambiguous problem") "vkGetPhysicalDeviceSurfacePresentModesKHR", [&](uint32_t* count, vk::PresentModeKHR* values) { return physical_device.getSurfacePresentModesKHR(surface, count, values); }); - EXIT_NOT_IMPLEMENTED(r->present_modes.empty()); + EXIT_NOT_IMPLEMENTED(r.present_modes.empty()); - r->format_srgb_bgra32 = false; - r->format_unorm_bgra32 = false; - for (const auto& f: r->formats) { + r.format_srgb_bgra32 = false; + r.format_unorm_bgra32 = false; + for (const auto& f: r.formats) { if (f.format == vk::Format::eB8G8R8A8Srgb && f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { - r->format_srgb_bgra32 = true; + r.format_srgb_bgra32 = true; } if (f.format == vk::Format::eB8G8R8A8Unorm && f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { - r->format_unorm_bgra32 = true; + r.format_unorm_bgra32 = true; } - if (r->format_srgb_bgra32 && r->format_unorm_bgra32) { + if (r.format_srgb_bgra32 && r.format_unorm_bgra32) { break; } } @@ -244,13 +244,10 @@ static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR s // NOLINTNEXTLINE(readability-function-cognitive-complexity) static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surface, const std::vector& device_extensions, - SurfaceCapabilities* out_capabilities, - vk::PhysicalDevice* out_device, VulkanQueues* out_queues) { + SurfaceCapabilities& out_capabilities, + vk::PhysicalDevice& out_device, VulkanQueues& out_queues) { EXIT_IF(instance == nullptr); EXIT_IF(surface == nullptr); - EXIT_IF(out_capabilities == nullptr); - EXIT_IF(out_device == nullptr); - EXIT_IF(out_queues == nullptr); auto devices = EnumerateVulkan( "vkEnumeratePhysicalDevices", [&](uint32_t* count, vk::PhysicalDevice* values) { @@ -408,7 +405,7 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa SurfaceCapabilities candidate_capabilities; if (!skip_device) { - VulkanGetSurfaceCapabilities(device, surface, &candidate_capabilities); + VulkanGetSurfaceCapabilities(device, surface, candidate_capabilities); if (!(candidate_capabilities.capabilities.supportedUsageFlags & vk::ImageUsageFlagBits::eTransferDst)) { @@ -512,16 +509,16 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa } } - *out_device = best_device; - *out_queues = best_queues; + out_device = best_device; + out_queues = best_queues; if (best_device != nullptr) { - *out_capabilities = std::move(best_capabilities); + out_capabilities = std::move(best_capabilities); } } -static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device, GraphicContext* ctx) { +static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device) { EXIT_IF(physical_device == nullptr); - EXIT_IF(ctx == nullptr); + auto& graphics = g_window_ctx->graphic_ctx; vk::PhysicalDeviceSubgroupSizeControlProperties subgroup_size_control {}; subgroup_size_control.sType = vk::StructureType::ePhysicalDeviceSubgroupSizeControlProperties; @@ -547,28 +544,26 @@ static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device, Gr physical_device.getFeatures2(&features2); - ctx->subgroup_size = properties11.subgroupSize; - ctx->min_subgroup_size = subgroup_size_control.minSubgroupSize; - ctx->max_subgroup_size = subgroup_size_control.maxSubgroupSize; - ctx->required_subgroup_size_stages = subgroup_size_control.requiredSubgroupSizeStages; - ctx->subgroup_size_control_enabled = features13.subgroupSizeControl == VK_TRUE && - subgroup_size_control.minSubgroupSize <= 64 && - subgroup_size_control.maxSubgroupSize >= 64; + graphics.subgroup_size = properties11.subgroupSize; + graphics.min_subgroup_size = subgroup_size_control.minSubgroupSize; + graphics.max_subgroup_size = subgroup_size_control.maxSubgroupSize; + graphics.required_subgroup_size_stages = subgroup_size_control.requiredSubgroupSizeStages; + graphics.subgroup_size_control_enabled = features13.subgroupSizeControl == VK_TRUE && + subgroup_size_control.minSubgroupSize <= 64 && + subgroup_size_control.maxSubgroupSize >= 64; LOGF("Vulkan subgroup: default=%u min=%u max=%u stages=0x%08x size_control=%s\n", - ctx->subgroup_size, ctx->min_subgroup_size, ctx->max_subgroup_size, - static_cast(ctx->required_subgroup_size_stages), - ctx->subgroup_size_control_enabled ? "true" : "false"); + graphics.subgroup_size, graphics.min_subgroup_size, graphics.max_subgroup_size, + static_cast(graphics.required_subgroup_size_stages), + graphics.subgroup_size_control_enabled ? "true" : "false"); } static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface, - const VulkanExtensions* r, const VulkanQueues& queues, - const std::vector& device_extensions, - GraphicContext* ctx) { + const VulkanExtensions& r, const VulkanQueues& queues, + const std::vector& device_extensions) { EXIT_IF(physical_device == nullptr); - EXIT_IF(r == nullptr); + auto& graphics = g_window_ctx->graphic_ctx; EXIT_IF(surface == nullptr); - EXIT_IF(ctx == nullptr); std::vector queue_create_info(queues.family_count); std::vector> queue_priority(queues.family_count); @@ -599,8 +594,8 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::Sur color_write_ext.colorWriteEnable = VK_TRUE; vk::PhysicalDeviceDepthClipEnableFeaturesEXT depth_clip_enable {}; - depth_clip_enable.sType = vk::StructureType::ePhysicalDeviceDepthClipEnableFeaturesEXT; - depth_clip_enable.pNext = &color_write_ext; + depth_clip_enable.sType = vk::StructureType::ePhysicalDeviceDepthClipEnableFeaturesEXT; + depth_clip_enable.pNext = &color_write_ext; depth_clip_enable.depthClipEnable = VK_TRUE; vk::PhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control {}; @@ -646,12 +641,13 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::Sur device_features.shaderImageGatherExtended = VK_TRUE; device_features.independentBlend = VK_TRUE; device_features.tessellationShader = VK_TRUE; - device_features.sampleRateShading = supported_features2.features.sampleRateShading; - ctx->sample_rate_shading_enabled = device_features.sampleRateShading == VK_TRUE; + device_features.sampleRateShading = supported_features2.features.sampleRateShading; + graphics.sample_rate_shading_enabled = device_features.sampleRateShading == VK_TRUE; device_features.vertexPipelineStoresAndAtomics = supported_features2.features.vertexPipelineStoresAndAtomics; - if (ctx->subgroup_size_control_enabled && supported_features13.subgroupSizeControl == VK_TRUE) { + if (graphics.subgroup_size_control_enabled && + supported_features13.subgroupSizeControl == VK_TRUE) { subgroup_size_control.subgroupSizeControl = VK_TRUE; } @@ -685,9 +681,9 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::Sur create_info.pQueueCreateInfos = queue_create_info.data(); create_info.queueCreateInfoCount = queue_create_info_num; create_info.enabledLayerCount = - (r->enable_validation_layers ? static_cast(r->required_layers.size()) : 0); + (r.enable_validation_layers ? static_cast(r.required_layers.size()) : 0); create_info.ppEnabledLayerNames = - (r->enable_validation_layers ? r->required_layers.data() : nullptr); + (r.enable_validation_layers ? r.required_layers.data() : nullptr); create_info.enabledExtensionCount = static_cast(device_extensions.size()); create_info.ppEnabledExtensionNames = device_extensions.data(); create_info.pEnabledFeatures = &device_features; @@ -703,9 +699,8 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::Sur return device; } -static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) { +static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions& r) { EXIT_IF(window == nullptr); - EXIT_IF(r == nullptr); uint32_t required_extensions_count = 0; @@ -714,65 +709,65 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) { EXIT_NOT_IMPLEMENTED(sdl_result == SDL_FALSE); EXIT_NOT_IMPLEMENTED(required_extensions_count == 0); - r->required_extensions = + r.required_extensions = std::vector(required_extensions_count); // @suppress("Ambiguous problem") - std::memset(r->required_extensions.data(), 0, - sizeof(const char*) * r->required_extensions.size()); + std::memset(r.required_extensions.data(), 0, + sizeof(const char*) * r.required_extensions.size()); sdl_result = SDL_Vulkan_GetInstanceExtensions(window, &required_extensions_count, - r->required_extensions.data()); + r.required_extensions.data()); EXIT_NOT_IMPLEMENTED(sdl_result == SDL_FALSE); EXIT_NOT_IMPLEMENTED(required_extensions_count == 0); - EXIT_NOT_IMPLEMENTED(required_extensions_count != r->required_extensions.size()); + EXIT_NOT_IMPLEMENTED(required_extensions_count != r.required_extensions.size()); - r->available_extensions = + r.available_extensions = EnumerateVulkan( // @suppress("Ambiguous problem") "vkEnumerateInstanceExtensionProperties", [](uint32_t* count, vk::ExtensionProperties* values) { return vk::enumerateInstanceExtensionProperties(nullptr, count, values); }); - r->enable_validation_layers = Config::VulkanValidationEnabled(); + r.enable_validation_layers = Config::VulkanValidationEnabled(); - if (HasExtension(r->available_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { - r->required_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + if (HasExtension(r.available_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { + r.required_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } else { - r->enable_validation_layers = false; + r.enable_validation_layers = false; } - for (const char* ext: r->required_extensions) { + for (const char* ext: r.required_extensions) { LOGF("Vulkan required extension: %s\n", ext); } - for (const auto& ext: r->available_extensions) { + for (const auto& ext: r.available_extensions) { LOGF("Vulkan available extension: %s, version = %u\n", ext.extensionName.data(), ext.specVersion); } - r->available_layers = EnumerateVulkan( // @suppress("Ambiguous problem") + r.available_layers = EnumerateVulkan( // @suppress("Ambiguous problem") "vkEnumerateInstanceLayerProperties", [](uint32_t* count, vk::LayerProperties* values) { return vk::enumerateInstanceLayerProperties(count, values); }); - for (const auto& l: r->available_layers) { + for (const auto& l: r.available_layers) { LOGF("Vulkan available layer: %s, specVersion = %u, implVersion = %u, %s\n", l.layerName.data(), l.specVersion, l.implementationVersion, l.description.data()); } - r->required_layers = {"VK_LAYER_KHRONOS_validation"}; + r.required_layers = {"VK_LAYER_KHRONOS_validation"}; - if (r->enable_validation_layers) { - for (const char* l: r->required_layers) { - if (!HasLayer(r->available_layers, l)) { + if (r.enable_validation_layers) { + for (const char* l: r.required_layers) { + if (!HasLayer(r.available_layers, l)) { LOGF("no validation layer: %s\n", l); - r->enable_validation_layers = false; + r.enable_validation_layers = false; break; } } } - if (r->enable_validation_layers) { + if (r.enable_validation_layers) { auto available_extensions = EnumerateVulkan( "vkEnumerateInstanceExtensionProperties", [](uint32_t* count, vk::ExtensionProperties* values) { @@ -786,9 +781,9 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) { } if (HasExtension(available_extensions, VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME)) { - r->required_extensions.push_back(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME); + r.required_extensions.push_back(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME); } else { - r->enable_validation_layers = false; + r.enable_validation_layers = false; } } } @@ -870,28 +865,30 @@ static VKAPI_ATTR vk::Result VKAPI_CALL VulkanCreateDebugUtilsMessengerEXT( return vk::Result::eErrorExtensionNotPresent; } -static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues) { - EXIT_IF(ctx == nullptr); - EXIT_IF(ctx->device == nullptr); +static void VulkanCreateQueues(const VulkanQueues& queues) { + auto& graphics = g_window_ctx->graphic_ctx; + EXIT_IF(graphics.device == nullptr); EXIT_IF(queues.graphics.size() != 1); EXIT_IF(queues.present.size() != 1); EXIT_IF(!(queues.compute.size() >= 1 && queues.compute.size() <= GraphicContext::QUEUE_COMPUTE_NUM)); - auto get_queue = [ctx](int id, const QueueInfo& info) { - ctx->queues[id].family = info.family; - ctx->queues[id].index = info.index; - EXIT_IF(ctx->queues[id].vk_queue != nullptr); - ctx->device.getQueue(ctx->queues[id].family, ctx->queues[id].index, - &ctx->queues[id].vk_queue); - EXIT_NOT_IMPLEMENTED(ctx->queues[id].vk_queue == nullptr); + auto get_queue = [&graphics](int id, const QueueInfo& info) { + graphics.queues[id].family = info.family; + graphics.queues[id].index = info.index; + EXIT_IF(graphics.queues[id].vk_queue != nullptr); + graphics.device.getQueue(graphics.queues[id].family, graphics.queues[id].index, + &graphics.queues[id].vk_queue); + EXIT_NOT_IMPLEMENTED(graphics.queues[id].vk_queue == nullptr); }; get_queue(GraphicContext::QUEUE_GFX, queues.graphics[0]); - ctx->queues[GraphicContext::QUEUE_UTIL].family = ctx->queues[GraphicContext::QUEUE_GFX].family; - ctx->queues[GraphicContext::QUEUE_UTIL].index = ctx->queues[GraphicContext::QUEUE_GFX].index; - ctx->queues[GraphicContext::QUEUE_UTIL].vk_queue = - ctx->queues[GraphicContext::QUEUE_GFX].vk_queue; + graphics.queues[GraphicContext::QUEUE_UTIL].family = + graphics.queues[GraphicContext::QUEUE_GFX].family; + graphics.queues[GraphicContext::QUEUE_UTIL].index = + graphics.queues[GraphicContext::QUEUE_GFX].index; + graphics.queues[GraphicContext::QUEUE_UTIL].vk_queue = + graphics.queues[GraphicContext::QUEUE_GFX].vk_queue; LOGF("Vulkan queue: using graphics queue for utility submissions to preserve resource " "ordering\n"); get_queue(GraphicContext::QUEUE_PRESENT, queues.present[0]); @@ -902,14 +899,14 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues) } for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) { - auto& queue = ctx->queues[id]; + auto& queue = graphics.queues[id]; if (queue.vk_queue == nullptr) { continue; } EXIT_IF(queue.mutex != nullptr); for (int other_id = 0; other_id < id; other_id++) { - auto& other = ctx->queues[other_id]; + auto& other = graphics.queues[other_id]; if (other.vk_queue != queue.vk_queue) { continue; } @@ -921,7 +918,7 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues) } if (queue.mutex == nullptr) { - queue.mutex = &ctx->queue_mutexes[id]; + queue.mutex = &graphics.queue_mutexes[id]; } } } @@ -946,12 +943,12 @@ static void VulkanCheckInstanceVersion() { } } -void VulkanCreate(WindowContext* ctx) { - EXIT_IF(ctx->window == nullptr); - EXIT_IF(ctx->graphic_ctx.instance != nullptr); - EXIT_IF(ctx->graphic_ctx.physical_device != nullptr); - EXIT_IF(ctx->graphic_ctx.device != nullptr); - EXIT_IF(ctx->surface_capabilities != nullptr); +void VulkanCreate(WindowContext& window) { + EXIT_IF(window.window == nullptr); + EXIT_IF(window.graphic_ctx.instance != nullptr); + EXIT_IF(window.graphic_ctx.physical_device != nullptr); + EXIT_IF(window.graphic_ctx.device != nullptr); + EXIT_IF(window.surface_capabilities != nullptr); auto get_instance_proc_addr = reinterpret_cast(SDL_Vulkan_GetVkGetInstanceProcAddr()); @@ -961,7 +958,7 @@ void VulkanCreate(WindowContext* ctx) { VULKAN_HPP_DEFAULT_DISPATCHER.init(get_instance_proc_addr); VulkanExtensions r; - VulkanGetExtensions(ctx->window, &r); + VulkanGetExtensions(window.window, r); VulkanCheckInstanceVersion(); vk::ApplicationInfo app_info {}; @@ -1025,31 +1022,31 @@ void VulkanCreate(WindowContext* ctx) { inst_info.ppEnabledLayerNames = (r.enable_validation_layers ? r.required_layers.data() : nullptr); - const vk::Result result = vk::createInstance(&inst_info, nullptr, &ctx->graphic_ctx.instance); + const vk::Result result = vk::createInstance(&inst_info, nullptr, &window.graphic_ctx.instance); switch (result) { case vk::Result::eSuccess: break; case vk::Result::eErrorIncompatibleDriver: EXIT("Unable to find a compatible Vulkan Driver"); default: EXIT("Could not create a Vulkan instance (for unknown reasons)"); } - VULKAN_HPP_DEFAULT_DISPATCHER.init(ctx->graphic_ctx.instance); + VULKAN_HPP_DEFAULT_DISPATCHER.init(window.graphic_ctx.instance); if (r.enable_validation_layers) { dbg_create_info.pNext = nullptr; - if (VulkanCreateDebugUtilsMessengerEXT(ctx->graphic_ctx.instance, &dbg_create_info, nullptr, - &ctx->graphic_ctx.debug_messenger) != + if (VulkanCreateDebugUtilsMessengerEXT(window.graphic_ctx.instance, &dbg_create_info, + nullptr, &window.graphic_ctx.debug_messenger) != vk::Result::eSuccess) { EXIT("Could not create debug messenger"); } } vk::SurfaceKHR::CType native_surface = VK_NULL_HANDLE; - if (SDL_Vulkan_CreateSurface(ctx->window, - static_cast(ctx->graphic_ctx.instance), + if (SDL_Vulkan_CreateSurface(window.window, + static_cast(window.graphic_ctx.instance), &native_surface) == SDL_FALSE) { EXIT("Could not create a Vulkan surface"); } - ctx->surface = native_surface; + window.surface = native_surface; std::vector device_extensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, @@ -1062,21 +1059,23 @@ void VulkanCreate(WindowContext* ctx) { } #endif - ctx->surface_capabilities = new SurfaceCapabilities {}; + window.surface_capabilities = new SurfaceCapabilities {}; VulkanQueues queues; - VulkanFindPhysicalDevice(ctx->graphic_ctx.instance, ctx->surface, device_extensions, - ctx->surface_capabilities, &ctx->graphic_ctx.physical_device, &queues); + VulkanFindPhysicalDevice(window.graphic_ctx.instance, window.surface, device_extensions, + *window.surface_capabilities, window.graphic_ctx.physical_device, + queues); - if (ctx->graphic_ctx.physical_device == nullptr) { + if (window.graphic_ctx.physical_device == nullptr) { EXIT("Could not find suitable device"); } - ctx->graphic_ctx.physical_device.getProperties(&ctx->graphic_ctx.physical_device_properties); - ctx->graphic_ctx.physical_device.getMemoryProperties( - &ctx->graphic_ctx.physical_device_memory_properties); - const auto& device_properties = ctx->graphic_ctx.GetPhysicalDeviceProperties(); + window.graphic_ctx.physical_device.getProperties( + &window.graphic_ctx.physical_device_properties); + window.graphic_ctx.physical_device.getMemoryProperties( + &window.graphic_ctx.physical_device_memory_properties); + const auto& device_properties = window.graphic_ctx.GetPhysicalDeviceProperties(); LOGF("Select device: %s\n", device_properties.deviceName.data()); @@ -1084,40 +1083,40 @@ void VulkanCreate(WindowContext* ctx) { auto available_extensions = EnumerateVulkan( "vkEnumerateDeviceExtensionProperties", [&](uint32_t* count, vk::ExtensionProperties* values) { - return ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties( + return window.graphic_ctx.physical_device.enumerateDeviceExtensionProperties( nullptr, count, values); }); if (HasExtension(available_extensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) { device_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); - ctx->graphic_ctx.memory_budget_ext_enabled = true; + window.graphic_ctx.memory_budget_ext_enabled = true; } if (HasExtension(available_extensions, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) { device_extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); } } - memcpy(ctx->device_name, device_properties.deviceName, sizeof(ctx->device_name)); - std::snprintf(ctx->processor_name, sizeof(ctx->processor_name), "%s", + memcpy(window.device_name, device_properties.deviceName, sizeof(window.device_name)); + std::snprintf(window.processor_name, sizeof(window.processor_name), "%s", Common::GetSystemInfo().ProcessorName.c_str()); - VulkanInitSubgroupSizeControl(ctx->graphic_ctx.physical_device, &ctx->graphic_ctx); + VulkanInitSubgroupSizeControl(window.graphic_ctx.physical_device); - ctx->graphic_ctx.device = VulkanCreateDevice(ctx->graphic_ctx.physical_device, ctx->surface, &r, - queues, device_extensions, &ctx->graphic_ctx); - if (ctx->graphic_ctx.device == nullptr) { + window.graphic_ctx.device = VulkanCreateDevice(window.graphic_ctx.physical_device, + window.surface, r, queues, device_extensions); + if (window.graphic_ctx.device == nullptr) { EXIT("Could not create device"); } - VULKAN_HPP_DEFAULT_DISPATCHER.init(ctx->graphic_ctx.device); + VULKAN_HPP_DEFAULT_DISPATCHER.init(window.graphic_ctx.device); - if (!VulkanCreateAllocator(&ctx->graphic_ctx)) { + if (!window.graphic_ctx.CreateAllocator()) { EXIT("Could not create Vulkan memory allocator"); } - VulkanCreateQueues(&ctx->graphic_ctx, queues); + VulkanCreateQueues(queues); - ctx->swapchain = VulkanCreateSwapchain(&ctx->graphic_ctx, 2); - RenderDocSetActiveWindow(ctx->graphic_ctx.instance, ctx->window); + window.swapchain = VulkanCreateSwapchain(2); + RenderDocSetActiveWindow(window.graphic_ctx.instance, window.window); } } // namespace Libs::Graphics diff --git a/src/graphics/presentation/window/window.cpp b/src/graphics/presentation/window/window.cpp index 3148c33dd..516a159ab 100644 --- a/src/graphics/presentation/window/window.cpp +++ b/src/graphics/presentation/window/window.cpp @@ -234,11 +234,11 @@ struct WindowGame { }; struct WindowGamePrivate { - WindowGamePrivate() = default; + explicit WindowGamePrivate(GraphicContext& graphics): graphics(graphics) {} Common::Mutex mutex; int skip_frames = 0; - GraphicContext* ctx = nullptr; + GraphicContext& graphics; }; WindowContext* g_window_ctx = nullptr; @@ -248,58 +248,58 @@ constexpr uint32_t KYTY_SDL_WINDOW_FLAGS = (static_cast(SDL_WINDOW_HIDDEN) | static_cast(SDL_WINDOW_VULKAN)); constexpr int KYTY_SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED; /*NOLINT(hicpp-signed-bitwise)*/ -static void CalcFrameTime(WindowGame* game, double game_time_s) { - game->m_previous_time_seconds = game->m_current_time_seconds; - game->m_current_time_seconds = game_time_s; +static void CalcFrameTime(WindowGame& game, double game_time_s) { + game.m_previous_time_seconds = game.m_current_time_seconds; + game.m_current_time_seconds = game_time_s; - game->m_frame_num++; - game->m_fps_frames_num++; + game.m_frame_num++; + game.m_fps_frames_num++; - const auto fps_time = game->m_current_time_seconds - game->m_fps_start_time; + const auto fps_time = game.m_current_time_seconds - game.m_fps_start_time; if (fps_time > FPS_UPDATE_TIME) { - game->m_current_fps = static_cast(game->m_fps_frames_num) / fps_time; - game->m_fps_frames_num = 0; - game->m_fps_start_time = game->m_current_time_seconds; + game.m_current_fps = static_cast(game.m_fps_frames_num) / fps_time; + game.m_fps_frames_num = 0; + game.m_fps_start_time = game.m_current_time_seconds; } } -static bool Init(WindowGame* /*game*/) { +static bool Init(WindowGame& /*game*/) { return true; } -static bool Update(WindowGame* /*game*/) { +static bool Update(WindowGame& /*game*/) { return true; } -static bool Render(WindowGame* /*game*/) { +static bool Render(WindowGame& /*game*/) { return true; } -static bool Close(WindowGame* /*game*/) { +static bool Close(WindowGame& /*game*/) { return true; } -static void SetPause(WindowGame* game, bool flag) { +static void SetPause(WindowGame& game, bool flag) { LOGF("Pause: %s\n", flag ? "true" : "false"); - game->m_game_is_paused = flag; + game.m_game_is_paused = flag; } -static bool RenderAndUpdate(WindowGame* game) { +static bool RenderAndUpdate(WindowGame& game) { static double lag = 0.0; - lag += game->m_current_time_seconds - game->m_previous_time_seconds; + lag += game.m_current_time_seconds - game.m_previous_time_seconds; int num = 0; bool ok = true; - while (lag >= game->m_update_fixed_time) { - if (num < game->m_max_updates_per_frame) { + while (lag >= game.m_update_fixed_time) { + if (num < game.m_max_updates_per_frame) { ok = ok && Update(game); - game->m_update_num++; + game.m_update_num++; num++; - game->m_update_time_seconds = game->m_update_num * game->m_update_fixed_time; + game.m_update_time_seconds = game.m_update_num * game.m_update_fixed_time; } - lag -= game->m_update_fixed_time; + lag -= game.m_update_fixed_time; } ok = ok && Render(game); @@ -307,44 +307,36 @@ static bool RenderAndUpdate(WindowGame* game) { return ok; } -bool GameInit(WindowGame* game, const Common::Timer& timer, void* data) { - EXIT_IF(game == nullptr); - EXIT_IF(data == nullptr); - EXIT_IF(game->private_data || game->event); +bool GameInit(WindowGame& game, const Common::Timer& timer) { + EXIT_IF(game.private_data || game.event); + auto& graphics = WindowGetGraphicContext(); - auto* ctx = static_cast(data); + EXIT_IF(graphics.screen_width == 0 || graphics.screen_height == 0); - EXIT_IF(ctx->screen_width == 0 || ctx->screen_height == 0); + auto* pdata = new WindowGamePrivate(graphics); - auto* pdata = new WindowGamePrivate; - pdata->ctx = ctx; + game.private_data = pdata; + game.event = new SDL_Event; - game->private_data = pdata; - game->event = new SDL_Event; - - game->m_screen_width = ctx->screen_width; - game->m_screen_height = ctx->screen_height; + game.m_screen_width = graphics.screen_width; + game.m_screen_height = graphics.screen_height; CalcFrameTime(game, timer.GetTimeS()); return Init(game); } -bool GameClose(WindowGame* game) { - EXIT_IF(!game); +bool GameClose(WindowGame& game) { + EXIT_IF(!game.private_data || !game.event); - EXIT_IF(!game->private_data || !game->event); - - delete (static_cast(game->private_data)); - delete (static_cast(game->event)); + delete (static_cast(game.private_data)); + delete (static_cast(game.event)); return Close(game); } -void GameShowWindow(WindowGame* game, const Common::Timer& timer) { - EXIT_IF(!game); - - auto* p = static_cast(game->private_data); +void GameShowWindow(WindowGame& game, const Common::Timer& timer) { + auto* p = static_cast(game.private_data); EXIT_IF(!p); @@ -364,33 +356,33 @@ void GameShowWindow(WindowGame* game, const Common::Timer& timer) { p->mutex.Unlock(); } -void GameEventQuit(WindowGame* game) { +void GameEventQuit(WindowGame& game) { LOGF("Event: quit\n"); - game->m_game_need_exit = true; + game.m_game_need_exit = true; } -void GameEventTerminate(WindowGame* game) { +void GameEventTerminate(WindowGame& game) { LOGF("Event: terminate\n"); - game->m_game_need_exit = true; + game.m_game_need_exit = true; } -void GameEventKeyboard(WindowGame* game, const EventKeyboard* key) { +void GameEventKeyboard(WindowGame& game, const EventKeyboard& key) { #ifdef KYTY_DBG_INPUT LOGF("Key: time = %.04f, %s%s, %s%s, %s, scan = %d, key = %d, mod = %04" PRIx16 "\n", - key->timestamp_seconds, (key->down ? "down" : ""), (key->up ? "up" : ""), - (key->pressed ? "pressed" : ""), (key->released ? "released" : ""), - (key->repeat ? "repeat" : ""), key->scan_code, key->key_code, key->mod); + key.timestamp_seconds, (key.down ? "down" : ""), (key.up ? "up" : ""), + (key.pressed ? "pressed" : ""), (key.released ? "released" : ""), + (key.repeat ? "repeat" : ""), key.scan_code, key.key_code, key.mod); #endif #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX - if (key->down) { - switch (key->key_code) { - case SDLK_ESCAPE: game->m_game_need_exit = true; break; - case SDLK_SPACE: SetPause(game, !game->m_game_is_paused); break; + if (key.down) { + switch (key.key_code) { + case SDLK_ESCAPE: game.m_game_need_exit = true; break; + case SDLK_SPACE: SetPause(game, !game.m_game_is_paused); break; case SDLK_F1: - if (!key->repeat) { + if (!key.repeat) { RenderDocRequestCapture(); } break; @@ -398,159 +390,153 @@ void GameEventKeyboard(WindowGame* game, const EventKeyboard* key) { } } - const auto button = KeyboardKeyToPadButton(key->key_code); - if (button != 0 && (key->down || key->up) && !key->repeat) { + const auto button = KeyboardKeyToPadButton(key.key_code); + if (button != 0 && (key.down || key.up) && !key.repeat) { static bool keyboard_connected = false; if (!keyboard_connected) { Controller::ControllerConnect(KEYBOARD_CONTROLLER_ID); keyboard_connected = true; } - Controller::ControllerButton(KEYBOARD_CONTROLLER_ID, button, key->down); + Controller::ControllerButton(KEYBOARD_CONTROLLER_ID, button, key.down); } #endif } -void GameEventMouse([[maybe_unused]] WindowGame* game, [[maybe_unused]] const EventMouse* mb) { +void GameEventMouse([[maybe_unused]] WindowGame& game, [[maybe_unused]] const EventMouse& mb) { #ifdef KYTY_DBG_INPUT - if (mb->wheel) { - LOGF("Mouse wheel: time = %.04f, %s[%d, %d]\n", mb->timestamp_seconds, - (mb->touch ? "touch, " : ""), mb->x, mb->y); - } else if (mb->motion) { - LOGF("Mouse motion: time = %.04f, %s%s%s%s%s%s, [%d, %d], (%d, %d)\n", - mb->timestamp_seconds, (mb->left ? "left" : ""), (mb->middle ? "middle" : ""), - (mb->right ? "right" : ""), (mb->x1 ? "x1" : ""), (mb->x2 ? "x2" : ""), - (mb->touch ? "_touch" : ""), mb->x, mb->y, mb->motion_x, mb->motion_y); + if (mb.wheel) { + LOGF("Mouse wheel: time = %.04f, %s[%d, %d]\n", mb.timestamp_seconds, + (mb.touch ? "touch, " : ""), mb.x, mb.y); + } else if (mb.motion) { + LOGF("Mouse motion: time = %.04f, %s%s%s%s%s%s, [%d, %d], (%d, %d)\n", mb.timestamp_seconds, + (mb.left ? "left" : ""), (mb.middle ? "middle" : ""), (mb.right ? "right" : ""), + (mb.x1 ? "x1" : ""), (mb.x2 ? "x2" : ""), (mb.touch ? "_touch" : ""), mb.x, mb.y, + mb.motion_x, mb.motion_y); } else { LOGF("Mouse click: time = %.04f, %d, %s%s%s%s%s%s, %s%s, %s%s, [%d, %d]\n", - mb->timestamp_seconds, mb->num_of_clicks, (mb->left ? "left" : ""), - (mb->middle ? "middle" : ""), (mb->right ? "right" : ""), (mb->x1 ? "x1" : ""), - (mb->x2 ? "x2" : ""), (mb->touch ? "_touch" : ""), (mb->down ? "down" : ""), - (mb->up ? "up" : ""), (mb->pressed ? "pressed" : ""), (mb->released ? "released" : ""), - mb->x, mb->y); + mb.timestamp_seconds, mb.num_of_clicks, (mb.left ? "left" : ""), + (mb.middle ? "middle" : ""), (mb.right ? "right" : ""), (mb.x1 ? "x1" : ""), + (mb.x2 ? "x2" : ""), (mb.touch ? "_touch" : ""), (mb.down ? "down" : ""), + (mb.up ? "up" : ""), (mb.pressed ? "pressed" : ""), (mb.released ? "released" : ""), + mb.x, mb.y); } #endif } -void GameEventFinger([[maybe_unused]] WindowGame* game, [[maybe_unused]] const EventFinger* f) { +void GameEventFinger([[maybe_unused]] WindowGame& game, [[maybe_unused]] const EventFinger& f) { #ifdef KYTY_DBG_INPUT - if (f->motion) { + if (f.motion) { LOGF("Finger motion: time = %.04f, %d, %d, (x,y) = [%f, %f], (dx,dy) = [%f, %f], pressure " "= %f\n", - f->timestamp_seconds, f->touch_id, f->finger_id, f->x, f->y, f->dx, f->dy, - f->pressure); + f.timestamp_seconds, f.touch_id, f.finger_id, f.x, f.y, f.dx, f.dy, f.pressure); } else { LOGF("Finger press: time = %.04f, %d, %d, %s%s, (x,y) = [%f, %f], (dx,dy) = [%f, %f], " "pressure = %f\n", - f->timestamp_seconds, f->touch_id, f->finger_id, (f->down ? "down" : ""), - (f->up ? "up" : ""), f->x, f->y, f->dx, f->dy, f->pressure); + f.timestamp_seconds, f.touch_id, f.finger_id, (f.down ? "down" : ""), + (f.up ? "up" : ""), f.x, f.y, f.dx, f.dy, f.pressure); } #endif } -void GameEventController([[maybe_unused]] WindowGame* game, - [[maybe_unused]] const EventController* f) { - EXIT_NOT_IMPLEMENTED(f->remapped); +void GameEventController([[maybe_unused]] WindowGame& game, + [[maybe_unused]] const EventController& f) { + EXIT_NOT_IMPLEMENTED(f.remapped); #ifdef KYTY_DBG_INPUT - if (f->added || f->removed) { - LOGF("Controller %s: %d, time = %.04f\n", (f->added ? "added" : "removed"), f->id, - f->timestamp_seconds); - } else if (f->axis) { - LOGF("Controller axis: %d, axis = %d, value = %d, time = %.04f\n", f->id, f->axis_id, - f->axis_value, f->timestamp_seconds); + if (f.added || f.removed) { + LOGF("Controller %s: %d, time = %.04f\n", (f.added ? "added" : "removed"), f.id, + f.timestamp_seconds); + } else if (f.axis) { + LOGF("Controller axis: %d, axis = %d, value = %d, time = %.04f\n", f.id, f.axis_id, + f.axis_value, f.timestamp_seconds); } else { LOGF("Controller button: " "%d, %s%s, %s%s, button = %d, time = %.04f\n", - f->id, (f->down ? "down" : ""), (f->up ? "up" : ""), (f->pressed ? "pressed" : ""), - (f->released ? "released" : ""), f->button, f->timestamp_seconds); + f.id, (f.down ? "down" : ""), (f.up ? "up" : ""), (f.pressed ? "pressed" : ""), + (f.released ? "released" : ""), f.button, f.timestamp_seconds); } #endif - if (f->added) { - auto* pad = SDL_GameControllerOpen(f->id); + if (f.added) { + auto* pad = SDL_GameControllerOpen(f.id); EXIT_NOT_IMPLEMENTED(pad == nullptr); int id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(pad)); Controller::ControllerConnect(id); } - if (f->removed) { - Controller::ControllerDisconnect(f->id); - SDL_GameControllerClose(SDL_GameControllerFromInstanceID(f->id)); + if (f.removed) { + Controller::ControllerDisconnect(f.id); + SDL_GameControllerClose(SDL_GameControllerFromInstanceID(f.id)); } - if (f->down || f->up) { - const auto button = ControllerButtonToPadButton(f->button); + if (f.down || f.up) { + const auto button = ControllerButtonToPadButton(f.button); if (button != 0) { - Controller::ControllerButton(f->id, button, f->down); + Controller::ControllerButton(f.id, button, f.down); } } - if (f->axis) { - const auto axis = ControllerAxisFromSdl(f->axis_id); + if (f.axis) { + const auto axis = ControllerAxisFromSdl(f.axis_id); if (axis != Controller::Axis::AxisMax) { - Controller::ControllerAxis(f->id, axis, - ControllerAxisValueFromSdl(f->axis_id, f->axis_value)); + Controller::ControllerAxis(f.id, axis, + ControllerAxisValueFromSdl(f.axis_id, f.axis_value)); } } } -void GameEventDisplay([[maybe_unused]] WindowGame* game, [[maybe_unused]] const EventDisplay* d) { - auto* p = static_cast(game->private_data); - auto* ctx = static_cast(p->ctx); +void GameEventDisplay([[maybe_unused]] WindowGame& game) { + auto* p = static_cast(game.private_data); p->mutex.Lock(); - game->m_screen_width = ctx->screen_width; - game->m_screen_height = ctx->screen_height; + game.m_screen_width = p->graphics.screen_width; + game.m_screen_height = p->graphics.screen_height; p->mutex.Unlock(); } -void GameEventLowMemory(WindowGame* /*game*/) { +void GameEventLowMemory(WindowGame& /*game*/) { LOGF("Event: low_memory\n"); } -void GameEventWillEnterBackground(WindowGame* game) { +void GameEventWillEnterBackground(WindowGame& game) { LOGF("Event: will_enter_background\n"); SetPause(game, true); } -void GameEventDidEnterBackground(WindowGame* /*game*/) { +void GameEventDidEnterBackground(WindowGame& /*game*/) { LOGF("Event: did_enter_background\n"); } -void GameEventWillEnterForeground(WindowGame* /*game*/) { +void GameEventWillEnterForeground(WindowGame& /*game*/) { LOGF("Event: will_enter_foreground\n"); } -void GameEventDidEnterForeground(WindowGame* game) { +void GameEventDidEnterForeground(WindowGame& game) { LOGF("Event: did_enter_foreground\n"); SetPause(game, false); } -void GameEventResize(WindowGame* game, uint32_t new_width, uint32_t new_height) { +void GameEventResize(WindowGame& game, uint32_t new_width, uint32_t new_height) { EXIT_IF(new_width == 0 || new_height == 0); - EXIT_IF(!game); - auto* p = static_cast(game->private_data); + auto* p = static_cast(game.private_data); EXIT_IF(p == nullptr); - auto* ctx = static_cast(p->ctx); - EXIT_IF(ctx == nullptr); - p->mutex.Lock(); { p->skip_frames++; - ctx->screen_width = new_width; - ctx->screen_height = new_height; + p->graphics.screen_width = new_width; + p->graphics.screen_height = new_height; - game->m_screen_width = ctx->screen_width; - game->m_screen_height = ctx->screen_height; + game.m_screen_width = p->graphics.screen_width; + game.m_screen_height = p->graphics.screen_height; } p->mutex.Unlock(); } -static void ProcessWindowEvent(WindowGame* game, SDL_WindowEvent window) { +static void ProcessWindowEvent(WindowGame& game, SDL_WindowEvent window) { switch (window.event) { case SDL_WINDOWEVENT_SHOWN: LOGF("Window %" PRIu32 " shown\n", window.windowID); break; @@ -608,7 +594,7 @@ static void ProcessWindowEvent(WindowGame* game, SDL_WindowEvent window) { } } -static void ProcessDisplayEvent(WindowGame* game, SDL_DisplayEvent display) { +static void ProcessDisplayEvent(WindowGame& game, SDL_DisplayEvent display) { bool sdl = false; switch (display.event) { @@ -617,32 +603,17 @@ static void ProcessDisplayEvent(WindowGame* game, SDL_DisplayEvent display) { LOGF("Display %" PRIu32 "[%s] changed orientation to %d - ", display.display, sdl ? "SDL" : "Kyty", static_cast(display.data1)); - EventDisplay d {}; - d.orientation = DisplayOrientation::Unknown; - switch (display.data1) { case SDL_ORIENTATION_UNKNOWN: LOGF("UNKNOWN\n"); break; - case SDL_ORIENTATION_LANDSCAPE: - LOGF("LANDSCAPE\n"); - d.orientation = DisplayOrientation::Landscape; - break; - case SDL_ORIENTATION_LANDSCAPE_FLIPPED: - LOGF("LANDSCAPE_FLIPPED\n"); - d.orientation = DisplayOrientation::LandscapeFlipped; - break; - case SDL_ORIENTATION_PORTRAIT: - LOGF("PORTRAIT\n"); - d.orientation = DisplayOrientation::Portrait; - break; - case SDL_ORIENTATION_PORTRAIT_FLIPPED: - d.orientation = DisplayOrientation::PortraitFlipped; - LOGF("PORTRAIT_FLIPPED\n"); - break; + case SDL_ORIENTATION_LANDSCAPE: LOGF("LANDSCAPE\n"); break; + case SDL_ORIENTATION_LANDSCAPE_FLIPPED: LOGF("LANDSCAPE_FLIPPED\n"); break; + case SDL_ORIENTATION_PORTRAIT: LOGF("PORTRAIT\n"); break; + case SDL_ORIENTATION_PORTRAIT_FLIPPED: LOGF("PORTRAIT_FLIPPED\n"); break; default: LOGF("???\n"); } if (!sdl) { - GameEventDisplay(game, &d); + GameEventDisplay(game); } break; @@ -654,30 +625,24 @@ static void ProcessDisplayEvent(WindowGame* game, SDL_DisplayEvent display) { } } -int GamePollEvent(WindowGame* game) { - EXIT_IF(!game); - - auto* event = static_cast(game->event); +int GamePollEvent(WindowGame& game) { + auto* event = static_cast(game.event); EXIT_IF(!event); return SDL_PollEvent(event); } -int GameWaitEvent(WindowGame* game) { - EXIT_IF(!game); - - auto* event = static_cast(game->event); +int GameWaitEvent(WindowGame& game) { + auto* event = static_cast(game.event); EXIT_IF(!event); return SDL_WaitEvent(event); } -void GameProcessEvent(WindowGame* game, double time_s) { - EXIT_IF(!game); - - auto* event = static_cast(game->event); +void GameProcessEvent(WindowGame& game, double time_s) { + auto* event = static_cast(game.event); EXIT_IF(!event); @@ -712,7 +677,7 @@ void GameProcessEvent(WindowGame* game, double time_s) { key.mod = event->key.keysym.mod; key.timestamp_seconds = time_s; - GameEventKeyboard(game, &key); + GameEventKeyboard(game, key); break; } @@ -744,7 +709,7 @@ void GameProcessEvent(WindowGame* game, double time_s) { mb.motion_y = 0; mb.timestamp_seconds = time_s; - GameEventMouse(game, &mb); + GameEventMouse(game, mb); break; } @@ -771,7 +736,7 @@ void GameProcessEvent(WindowGame* game, double time_s) { mb.motion_y = 0; mb.timestamp_seconds = time_s; - GameEventMouse(game, &mb); + GameEventMouse(game, mb); break; } @@ -798,7 +763,7 @@ void GameProcessEvent(WindowGame* game, double time_s) { mb.motion_y = event->motion.yrel; mb.timestamp_seconds = time_s; - GameEventMouse(game, &mb); + GameEventMouse(game, mb); break; } @@ -820,7 +785,7 @@ void GameProcessEvent(WindowGame* game, double time_s) { f.pressure = event->tfinger.pressure; f.timestamp_seconds = time_s; - GameEventFinger(game, &f); + GameEventFinger(game, f); break; } @@ -842,7 +807,7 @@ void GameProcessEvent(WindowGame* game, double time_s) { c.released = false; c.timestamp_seconds = time_s; - GameEventController(game, &c); + GameEventController(game, c); break; } @@ -865,7 +830,7 @@ void GameProcessEvent(WindowGame* game, double time_s) { c.released = (event->cbutton.state == SDL_RELEASED); c.timestamp_seconds = time_s; - GameEventController(game, &c); + GameEventController(game, c); break; } @@ -889,20 +854,20 @@ void GameProcessEvent(WindowGame* game, double time_s) { c.released = false; c.timestamp_seconds = time_s; - GameEventController(game, &c); + GameEventController(game, c); break; } } } -void GameMainLoop(WindowGame* game, void* data) { +void GameMainLoop(WindowGame& game) { bool need_exit = false; Common::Timer timer; timer.Start(); - if (!GameInit(game, timer, data)) { + if (!GameInit(game, timer)) { need_exit = true; } @@ -916,7 +881,7 @@ void GameMainLoop(WindowGame* game, void* data) { continue; } - if (game->m_game_is_paused) { + if (game.m_game_is_paused) { if (!timer.IsPaused()) { timer.Pause(); } @@ -924,13 +889,13 @@ void GameMainLoop(WindowGame* game, void* data) { GameWaitEvent(game); GameProcessEvent(game, timer.GetTimeS()); - need_exit = game->m_game_need_exit; + need_exit = game.m_game_need_exit; continue; } - need_exit = game->m_game_need_exit; + need_exit = game.m_game_need_exit; - if (game->m_game_is_paused) { + if (game.m_game_is_paused) { if (!timer.IsPaused()) { timer.Pause(); } @@ -952,14 +917,13 @@ void GameMainLoop(WindowGame* game, void* data) { GameClose(game); } -static void WindowCreate(WindowContext* ctx) { - EXIT_IF(ctx == nullptr); - EXIT_IF(ctx->window != nullptr); - EXIT_IF(ctx->graphic_ctx.screen_width == 0); - EXIT_IF(ctx->graphic_ctx.screen_height == 0); +static void WindowCreate(WindowContext& context) { + EXIT_IF(context.window != nullptr); + EXIT_IF(context.graphic_ctx.screen_width == 0); + EXIT_IF(context.graphic_ctx.screen_height == 0); - int width = static_cast(ctx->graphic_ctx.screen_width); - int height = static_cast(ctx->graphic_ctx.screen_height); + int width = static_cast(context.graphic_ctx.screen_width); + int height = static_cast(context.graphic_ctx.screen_height); #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, "0"); @@ -971,17 +935,17 @@ static void WindowCreate(WindowContext* ctx) { LOGF("WindowCreate(): width = %d, height = %d\n", width, height); - ctx->window = + context.window = SDL_CreateWindow(KYTY_SDL_WINDOW_CAPTION, KYTY_SDL_WINDOWPOS_CENTERED, KYTY_SDL_WINDOWPOS_CENTERED, width, height, KYTY_SDL_WINDOW_FLAGS); - ctx->window_hidden = true; + context.window_hidden = true; - if (ctx->window == nullptr) { + if (context.window == nullptr) { EXIT("%s\n", SDL_GetError()); } - SDL_SetWindowResizable(ctx->window, SDL_FALSE); + SDL_SetWindowResizable(context.window, SDL_FALSE); } void WindowInit(uint32_t width, uint32_t height) { @@ -1015,19 +979,21 @@ void WindowRun() { { EXIT_IF(g_window_ctx->graphic_initialized); - WindowCreate(g_window_ctx); - VulkanCreate(g_window_ctx); + WindowCreate(*g_window_ctx); + VulkanCreate(*g_window_ctx); g_window_ctx->game = &game; - - g_window_ctx->graphic_initialized = true; - g_window_ctx->graphic_initialized_condvar.Signal(); } g_window_ctx->mutex.Unlock(); GraphicsRenderCreateContext(); - GameMainLoop(&game, &g_window_ctx->graphic_ctx); + g_window_ctx->mutex.Lock(); + g_window_ctx->graphic_initialized = true; + g_window_ctx->graphic_initialized_condvar.Signal(); + g_window_ctx->mutex.Unlock(); + + GameMainLoop(game); // TODO: replace std::_Exit shutdown with full Vulkan teardown, then destroy // the VMA allocator immediately before vkDestroyDevice. @@ -1043,12 +1009,12 @@ vk::SurfaceCapabilitiesKHR* VulkanGetSurfaceCapabilities() { return &g_window_ctx->surface_capabilities->capabilities; } -GraphicContext* WindowGetGraphicContext() { +GraphicContext& WindowGetGraphicContext() { EXIT_IF(g_window_ctx == nullptr); Common::LockGuard lock(g_window_ctx->mutex); - return &g_window_ctx->graphic_ctx; + return g_window_ctx->graphic_ctx; } static int WindowIconRead(void* user, char* data, int size) { diff --git a/src/graphics/presentation/window/windowInternal.h b/src/graphics/presentation/window/windowInternal.h index f2e0c78ee..9befc5d5d 100644 --- a/src/graphics/presentation/window/windowInternal.h +++ b/src/graphics/presentation/window/windowInternal.h @@ -41,9 +41,9 @@ struct WindowContext { extern WindowContext* g_window_ctx; void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface, - SurfaceCapabilities* capabilities); -VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count); -void VulkanCreate(WindowContext* ctx); + SurfaceCapabilities& capabilities); +VulkanSwapchain* VulkanCreateSwapchain(uint32_t image_count); +void VulkanCreate(WindowContext& window); void WindowUpdateIcon(); void WindowUpdateTitle(); diff --git a/src/graphics/rt/hardware.cpp b/src/graphics/rt/hardware.cpp index aa9cbee91..dcb28cb22 100644 --- a/src/graphics/rt/hardware.cpp +++ b/src/graphics/rt/hardware.cpp @@ -6,7 +6,7 @@ #include #include -namespace Libs::Graphics::Rt { +namespace Libs::Graphics { namespace { bool ExtensionAvailable(const std::vector& available, const char* name) { @@ -25,10 +25,9 @@ void AppendExtensionIfMissing(std::vector& extensions, const char* } // namespace -void AppendHardwareRayTracingDeviceExtensions( +void GraphicContext::AppendHardwareRayTracingDeviceExtensions( const std::vector& available_extensions, - std::vector* device_extensions, GraphicContext* ctx) { - EXIT_IF(device_extensions == nullptr || ctx == nullptr); + std::vector& device_extensions) { const char* required[] = { VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, @@ -40,27 +39,27 @@ void AppendHardwareRayTracingDeviceExtensions( if (!ExtensionAvailable(available_extensions, extension)) { LOGF("Vulkan RT: extension %s is unavailable; hardware ray tracing disabled\n", extension); - ctx->rt_extensions_enabled = false; + rt_extensions_enabled = false; return; } } for (const auto* extension: required) { - AppendExtensionIfMissing(*device_extensions, extension); + AppendExtensionIfMissing(device_extensions, extension); } if (ExtensionAvailable(available_extensions, VK_KHR_SPIRV_1_4_EXTENSION_NAME)) { - AppendExtensionIfMissing(*device_extensions, VK_KHR_SPIRV_1_4_EXTENSION_NAME); + AppendExtensionIfMissing(device_extensions, VK_KHR_SPIRV_1_4_EXTENSION_NAME); } if (ExtensionAvailable(available_extensions, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)) { - AppendExtensionIfMissing(*device_extensions, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); + AppendExtensionIfMissing(device_extensions, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); } - ctx->rt_extensions_enabled = true; + rt_extensions_enabled = true; LOGF("Vulkan RT: enabling hardware ray query extensions\n"); } -void LoadHardwareRayTracingFunctions(GraphicContext* ctx) { - EXIT_IF(ctx == nullptr || ctx->device == nullptr); - if (!ctx->rt_extensions_enabled) { +void GraphicContext::LoadHardwareRayTracingFunctions() const { + EXIT_IF(device == nullptr); + if (!rt_extensions_enabled) { return; } @@ -75,4 +74,4 @@ void LoadHardwareRayTracingFunctions(GraphicContext* ctx) { } } -} // namespace Libs::Graphics::Rt +} // namespace Libs::Graphics diff --git a/src/graphics/rt/hardware.h b/src/graphics/rt/hardware.h index ced5652c9..afe967415 100644 --- a/src/graphics/rt/hardware.h +++ b/src/graphics/rt/hardware.h @@ -5,18 +5,6 @@ #include -namespace Libs::Graphics { - -namespace Rt { - -void AppendHardwareRayTracingDeviceExtensions( - const std::vector& available_extensions, - std::vector* device_extensions, GraphicContext* ctx); - -void LoadHardwareRayTracingFunctions(GraphicContext* ctx); - -} // namespace Rt - -} // namespace Libs::Graphics +namespace Libs::Graphics {} // namespace Libs::Graphics #endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_RT_HARDWARE_H_ */ diff --git a/src/graphics/shader/recompiler/BindingLayout.cpp b/src/graphics/shader/recompiler/BindingLayout.cpp index 4bc15ad49..bef599d17 100644 --- a/src/graphics/shader/recompiler/BindingLayout.cpp +++ b/src/graphics/shader/recompiler/BindingLayout.cpp @@ -58,21 +58,21 @@ bool ImageBinding(const ImageResource& image, DescriptorBindingKind& result) { } } -bool CollectValue(const ScalarProvenance& provenance, uint32_t id, std::vector* visited, - std::set* registers) { +bool CollectValue(const ScalarProvenance& provenance, uint32_t id, std::vector& visited, + std::set& registers) { if (id <= ScalarProvenance::Unknown) { return true; } if (id >= provenance.values.size()) { return false; } - if ((*visited)[id] != 0) { + if (visited[id] != 0) { return true; } - (*visited)[id] = 1; + visited[id] = 1; const auto& value = provenance.values[id]; if (value.op == ScalarValueOp::UserData) { - registers->insert(value.imm); + registers.insert(value.imm); return true; } if (value.op == ScalarValueOp::Phi) { @@ -92,7 +92,7 @@ bool CollectValue(const ScalarProvenance& provenance, uint32_t id, std::vector* visited, std::set* registers) { + std::vector& visited, std::set& registers) { if (allow_unknown && source == ScalarProvenance::Unknown) { return true; } @@ -112,49 +112,49 @@ bool CollectUserData(const Program& program, std::vector& result) { std::set registers; std::vector visited(program.provenance.values.size()); for (const auto& buffer: program.info.buffers) { - if (!CollectSource(program, buffer.source, false, &visited, ®isters)) { + if (!CollectSource(program, buffer.source, false, visited, registers)) { return false; } } for (const auto& image: program.info.images) { - if (!CollectSource(program, image.source, false, &visited, ®isters)) { + if (!CollectSource(program, image.source, false, visited, registers)) { return false; } } for (const auto& sampler: program.info.samplers) { - if (!CollectSource(program, sampler.source, false, &visited, ®isters)) { + if (!CollectSource(program, sampler.source, false, visited, registers)) { return false; } } for (const auto& address: program.info.addresses) { - if (!CollectSource(program, address.source, true, &visited, ®isters)) { + if (!CollectSource(program, address.source, true, visited, registers)) { return false; } } for (const auto& read: program.srt.reads) { - if (!CollectValue(program.provenance, read.value, &visited, ®isters)) { + if (!CollectValue(program.provenance, read.value, visited, registers)) { return false; } } for (const auto read: program.srt.dynamic_reads) { - if (!CollectValue(program.provenance, read, &visited, ®isters)) { + if (!CollectValue(program.provenance, read, visited, registers)) { return false; } } for (const auto source: program.srt.dynamic_sources) { - if (!CollectSource(program, source, true, &visited, ®isters)) { + if (!CollectSource(program, source, true, visited, registers)) { return false; } } for (const auto& block: program.blocks) { for (const auto& inst: block.instructions) { if (inst.op == Opcode::SLoadDword && inst.memory.kind == ResourceKind::ScalarBuffer && - !CollectValue(program.provenance, inst.scalar_value, &visited, ®isters)) { + !CollectValue(program.provenance, inst.scalar_value, visited, registers)) { return false; } for (uint32_t i = 0; i < inst.src_count; i++) { - if (!CollectValue(program.provenance, inst.scalar_sources[i], &visited, - ®isters)) { + if (!CollectValue(program.provenance, inst.scalar_sources[i], visited, + registers)) { return false; } } @@ -164,10 +164,10 @@ bool CollectUserData(const Program& program, std::vector& result) { return true; } -void AddBinding(BindingLayout* layout, DescriptorBindingKind kind, +void AddBinding(BindingLayout& layout, DescriptorBindingKind kind, std::vector resources = {}) { - layout->descriptors.push_back( - {kind, static_cast(layout->descriptors.size()), std::move(resources)}); + layout.descriptors.push_back( + {kind, static_cast(layout.descriptors.size()), std::move(resources)}); } bool UsesGds(const Program& program) { @@ -183,12 +183,11 @@ bool UsesGds(const Program& program) { } // namespace -bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std::string* error) { - if (program == nullptr || !program->shader_info_complete || program->binding_layout_complete) { +bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std::string* error) { + if (!program.shader_info_complete || program.binding_layout_complete) { if (error != nullptr) { - *error = program == nullptr ? "invalid binding-layout program" - : !program->shader_info_complete ? "shader info is not ready" - : "binding layout already allocated"; + *error = !program.shader_info_complete ? "shader info is not ready" + : "binding layout already allocated"; } return false; } @@ -208,25 +207,25 @@ bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std BindingLayout next; next.descriptor_set = options.descriptor_set; next.push_constant_offset = options.push_constant_offset; - if (!CollectUserData(*program, next.user_data_registers)) { + if (!CollectUserData(program, next.user_data_registers)) { if (error != nullptr) { *error = "shader plan contains an invalid scalar provenance reference"; } return false; } - if (!program->info.buffers.empty()) { - std::vector resources(program->info.buffers.size()); + if (!program.info.buffers.empty()) { + std::vector resources(program.info.buffers.size()); for (uint32_t i = 0; i < resources.size(); i++) { resources[i] = i; } - AddBinding(&next, DescriptorBindingKind::Buffers, std::move(resources)); + AddBinding(next, DescriptorBindingKind::Buffers, std::move(resources)); } std::array, ImageBindingKinds.size()> image_groups; - for (uint32_t i = 0; i < program->info.images.size(); i++) { + for (uint32_t i = 0; i < program.info.images.size(); i++) { DescriptorBindingKind kind; - if (!ImageBinding(program->info.images[i], kind)) { + if (!ImageBinding(program.info.images[i], kind)) { if (error != nullptr) { *error = "shader info contains an invalid image binding class"; } @@ -243,29 +242,29 @@ bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std } for (uint32_t i = 0; i < image_groups.size(); i++) { if (!image_groups[i].empty()) { - AddBinding(&next, ImageBindingKinds[i], std::move(image_groups[i])); + AddBinding(next, ImageBindingKinds[i], std::move(image_groups[i])); } } - if (!program->info.samplers.empty()) { - std::vector resources(program->info.samplers.size()); + if (!program.info.samplers.empty()) { + std::vector resources(program.info.samplers.size()); for (uint32_t i = 0; i < resources.size(); i++) { resources[i] = i; } - AddBinding(&next, DescriptorBindingKind::Samplers, std::move(resources)); + AddBinding(next, DescriptorBindingKind::Samplers, std::move(resources)); } - if (UsesGds(*program)) { - AddBinding(&next, DescriptorBindingKind::Gds); + if (UsesGds(program)) { + AddBinding(next, DescriptorBindingKind::Gds); } - if (!program->info.addresses.empty()) { - std::vector resources(program->info.addresses.size()); + if (!program.info.addresses.empty()) { + std::vector resources(program.info.addresses.size()); for (uint32_t i = 0; i < resources.size(); i++) { resources[i] = i; } - AddBinding(&next, DescriptorBindingKind::AddressMemory, std::move(resources)); + AddBinding(next, DescriptorBindingKind::AddressMemory, std::move(resources)); } - if (!program->srt.reads.empty()) { - AddBinding(&next, DescriptorBindingKind::FlattenedSrt); + if (!program.srt.reads.empty()) { + AddBinding(next, DescriptorBindingKind::FlattenedSrt); } const auto available_push_dwords = (MaxPushConstantBytes - options.push_constant_offset) / 4u; @@ -273,11 +272,11 @@ bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std if (next.user_data_registers.size() <= push_limit) { next.push_constant_size = static_cast(next.user_data_registers.size() * 4u); } else { - AddBinding(&next, DescriptorBindingKind::UserData); + AddBinding(next, DescriptorBindingKind::UserData); } - program->bindings = std::move(next); - program->binding_layout_complete = true; + program.bindings = std::move(next); + program.binding_layout_complete = true; return true; } diff --git a/src/graphics/shader/recompiler/BindingLayout.h b/src/graphics/shader/recompiler/BindingLayout.h index 9af42360e..f82bea338 100644 --- a/src/graphics/shader/recompiler/BindingLayout.h +++ b/src/graphics/shader/recompiler/BindingLayout.h @@ -11,7 +11,7 @@ struct BindingLayoutOptions { uint32_t max_push_dwords = 32; }; -bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std::string* error); +bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std::string* error); const DescriptorBinding* FindBinding(const BindingLayout& layout, DescriptorBindingKind kind); diff --git a/src/graphics/shader/recompiler/ExportOps.cpp b/src/graphics/shader/recompiler/ExportOps.cpp index a554c5510..04db9c3e2 100644 --- a/src/graphics/shader/recompiler/ExportOps.cpp +++ b/src/graphics/shader/recompiler/ExportOps.cpp @@ -4,7 +4,7 @@ namespace Libs::Graphics::ShaderRecompiler::Decoder { -bool DecodeExp(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeExp(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { @@ -18,33 +18,33 @@ bool DecodeExp(uint32_t pc, std::span code, uint32_t word_index, const uint32_t target = (word0 >> 4u) & 0x3fu; const uint32_t en = word0 & 0xfu; - inst->pc = pc; - inst->word = word0; - inst->word_count = 2; - inst->family = Family::EXP; - inst->opcode_id = target; - inst->opcode = Opcode::Exp; - inst->exp.target = target; - inst->exp.en = en; - inst->exp.compr = ((word0 >> 10u) & 1u) != 0; - inst->exp.done = ((word0 >> 11u) & 1u) != 0; - inst->exp.vm = ((word0 >> 12u) & 1u) != 0; + inst.pc = pc; + inst.word = word0; + inst.word_count = 2; + inst.family = Family::EXP; + inst.opcode_id = target; + inst.opcode = Opcode::Exp; + inst.exp.target = target; + inst.exp.en = en; + inst.exp.compr = ((word0 >> 10u) & 1u) != 0; + inst.exp.done = ((word0 >> 11u) & 1u) != 0; + inst.exp.vm = ((word0 >> 12u) & 1u) != 0; SetRawWords(inst, code, word_index, 2); - if (!DecodeVectorGpr(word1 & 0xffu, &inst->src0, error) || - !DecodeVectorGpr((word1 >> 8u) & 0xffu, &inst->src1, error) || - !DecodeVectorGpr((word1 >> 16u) & 0xffu, &inst->src2, error) || - !DecodeVectorGpr((word1 >> 24u) & 0xffu, &inst->src3, error)) { + if (!DecodeVectorGpr(word1 & 0xffu, inst.src0, error) || + !DecodeVectorGpr((word1 >> 8u) & 0xffu, inst.src1, error) || + !DecodeVectorGpr((word1 >> 16u) & 0xffu, inst.src2, error) || + !DecodeVectorGpr((word1 >> 24u) & 0xffu, inst.src3, error)) { return false; } - if (target == 0x14u && inst->exp.done && en == 0x1u) { - inst->src_count = 1u; + if (target == 0x14u && inst.exp.done && en == 0x1u) { + inst.src_count = 1u; } else { - inst->src_count = inst->exp.compr ? 2u : 4u; + inst.src_count = inst.exp.compr ? 2u : 4u; } if (en == 0u) { - inst->src_count = 0; + inst.src_count = 0; } return true; diff --git a/src/graphics/shader/recompiler/ExportOps.h b/src/graphics/shader/recompiler/ExportOps.h index 2f7fbf498..8a17b582b 100644 --- a/src/graphics/shader/recompiler/ExportOps.h +++ b/src/graphics/shader/recompiler/ExportOps.h @@ -5,7 +5,7 @@ namespace Libs::Graphics::ShaderRecompiler::Decoder { -bool DecodeExp(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeExp(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::Decoder diff --git a/src/graphics/shader/recompiler/ImageOps.cpp b/src/graphics/shader/recompiler/ImageOps.cpp index 6f4d30a47..0e861b71b 100644 --- a/src/graphics/shader/recompiler/ImageOps.cpp +++ b/src/graphics/shader/recompiler/ImageOps.cpp @@ -226,7 +226,7 @@ bool IsSingleDmaskBit(uint32_t dmask) { } // namespace -bool DecodeMimg(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeMimg(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { @@ -257,12 +257,12 @@ bool DecodeMimg(uint32_t pc, std::span code, uint32_t word_index const auto* gather = LookupGather(opcode); const auto* atomic = LookupAtomic(opcode); - inst->pc = pc; - inst->word = word0; - inst->word_count = word_count; - inst->family = Family::MIMG; - inst->opcode_id = opcode; - inst->opcode = (sample != nullptr ? Opcode::ImageSample + inst.pc = pc; + inst.word = word0; + inst.word_count = word_count; + inst.family = Family::MIMG; + inst.opcode_id = opcode; + inst.opcode = (sample != nullptr ? Opcode::ImageSample : gather != nullptr ? gather->decoded : atomic != nullptr ? atomic->decoded : opcode == 0x00u ? Opcode::ImageLoad @@ -272,20 +272,20 @@ bool DecodeMimg(uint32_t pc, std::span code, uint32_t word_index : opcode == 0x0eu ? Opcode::ImageGetResinfo : opcode == 0x60u ? Opcode::ImageGetLod : Opcode::Unsupported); - inst->dmask = (word0 >> 8u) & 0xfu; - inst->data_dwords = gather != nullptr ? 4u : CountDmaskComponents(inst->dmask); - inst->glc = ((word0 >> 13u) & 1u) != 0; - inst->slc = ((word0 >> 25u) & 1u) != 0; - inst->image_sample_flags = (sample != nullptr ? sample->flags + inst.dmask = (word0 >> 8u) & 0xfu; + inst.data_dwords = gather != nullptr ? 4u : CountDmaskComponents(inst.dmask); + inst.glc = ((word0 >> 13u) & 1u) != 0; + inst.slc = ((word0 >> 25u) & 1u) != 0; + inst.image_sample_flags = (sample != nullptr ? sample->flags : gather != nullptr ? gather->flags : 0u) | (a16 ? ImageSampleFlagA16 : 0u); - inst->image_dimension = dimension; - inst->image_nsa_dwords = nsa_dwords; + inst.image_dimension = dimension; + inst.image_nsa_dwords = nsa_dwords; for (uint32_t i = 0; i < nsa_dwords * 4u && i < MaxImageNsaAddressComponents; i++) { - inst->image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu; + inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu; } - inst->image_address_components = + inst.image_address_components = sample != nullptr ? ImageSampleAddressComponents(sample->flags, dimension) : gather != nullptr ? ImageSampleAddressComponents(gather->flags, dimension) : atomic != nullptr ? 3u @@ -297,19 +297,19 @@ bool DecodeMimg(uint32_t pc, std::span code, uint32_t word_index : 0u); SetRawWords(inst, code, word_index, word_count); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::MIMG, opcode, "MIMG opcode is not implemented"); } - if (gather != nullptr && !IsSingleDmaskBit(inst->dmask)) { + if (gather != nullptr && !IsSingleDmaskBit(inst.dmask)) { SetUnsupported(inst, Family::MIMG, opcode, "MIMG image gather requires exactly one dmask bit"); } - DecodeVectorGpr(vdata, &inst->dst, nullptr); - DecodeVectorGpr(vaddr, &inst->src0, nullptr); - DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr); - DecodeScalarSource(ssamp * 4u, pc, &inst->src2, nullptr); - inst->src_count = 3; + DecodeVectorGpr(vdata, inst.dst, nullptr); + DecodeVectorGpr(vaddr, inst.src0, nullptr); + DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr); + DecodeScalarSource(ssamp * 4u, pc, inst.src2, nullptr); + inst.src_count = 3; return true; } diff --git a/src/graphics/shader/recompiler/ImageOps.h b/src/graphics/shader/recompiler/ImageOps.h index 0994e8f15..62862b4ee 100644 --- a/src/graphics/shader/recompiler/ImageOps.h +++ b/src/graphics/shader/recompiler/ImageOps.h @@ -5,7 +5,7 @@ namespace Libs::Graphics::ShaderRecompiler::Decoder { -bool DecodeMimg(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeMimg(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); const char* MimgSampleOpcodeName(uint32_t opcode); diff --git a/src/graphics/shader/recompiler/MemoryOps.cpp b/src/graphics/shader/recompiler/MemoryOps.cpp index c01a83f02..b10dcd552 100644 --- a/src/graphics/shader/recompiler/MemoryOps.cpp +++ b/src/graphics/shader/recompiler/MemoryOps.cpp @@ -125,24 +125,24 @@ uint32_t SignExtendU32(uint32_t value, uint32_t bits) { return (value ^ sign) - sign; } -void MarkMemoryUnsupported(Instruction* inst, Family family, uint32_t opcode, const char* reason) { - inst->family = family; - inst->opcode_id = opcode; - inst->opcode = Opcode::Unsupported; +void MarkMemoryUnsupported(Instruction& inst, Family family, uint32_t opcode, const char* reason) { + inst.family = family; + inst.opcode_id = opcode; + inst.opcode = Opcode::Unsupported; SetUnsupported(inst, family, opcode, reason); } -void ApplyMemoryInfo(Instruction* inst, const MemoryOpcodeInfo* info) { +void ApplyMemoryInfo(Instruction& inst, const MemoryOpcodeInfo* info) { if (info == nullptr) { - inst->opcode = Opcode::Unsupported; + inst.opcode = Opcode::Unsupported; return; } - inst->opcode = info->decoded; - inst->data_dwords = info->data_dwords; - inst->data_bits = info->data_bits; - inst->data_signed = info->data_signed; - inst->typed = info->typed; - inst->formatted = info->formatted; + inst.opcode = info->decoded; + inst.data_dwords = info->data_dwords; + inst.data_bits = info->data_bits; + inst.data_signed = info->data_signed; + inst.typed = info->typed; + inst.formatted = info->formatted; } bool IsDsWriteOpcode(Opcode opcode) { @@ -215,7 +215,7 @@ bool IsFlatStoreOpcode(Opcode opcode) { } // namespace -bool DecodeSmem(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSmem(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { @@ -231,32 +231,32 @@ bool DecodeSmem(uint32_t pc, std::span code, uint32_t word_index const uint32_t sbase = word0 & 0x3fu; const uint32_t soffset = (word1 >> 25u) & 0x7fu; - inst->pc = pc; - inst->word = word0; - inst->word_count = 2; - inst->offset = SignExtendU32(word1 & 0x1fffffu, 21u); - inst->glc = ((word0 >> 16u) & 1u) != 0; - inst->family = Family::SMEM; - inst->opcode_id = opcode; + inst.pc = pc; + inst.word = word0; + inst.word_count = 2; + inst.offset = SignExtendU32(word1 & 0x1fffffu, 21u); + inst.glc = ((word0 >> 16u) & 1u) != 0; + inst.family = Family::SMEM; + inst.opcode_id = opcode; const auto* info = LookupMemoryOpcode(SMEM_OPS, static_cast(std::size(SMEM_OPS)), opcode); ApplyMemoryInfo(inst, info); SetRawWords(inst, code, word_index, 2); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { MarkMemoryUnsupported(inst, Family::SMEM, opcode, "SMEM opcode is not implemented"); } - DecodeScalarDestination(sdst, pc, &inst->dst, nullptr); + DecodeScalarDestination(sdst, pc, inst.dst, nullptr); // SMEM encodes SBASE in SGPR pairs. Scalar-buffer loads still use the same // pair index; their descriptor operand consumes four SGPRs from that base. - DecodeScalarSource(sbase * 2u, pc, &inst->src0, nullptr); - DecodeScalarSource(soffset, pc, &inst->src1, nullptr); - inst->src_count = 2; + DecodeScalarSource(sbase * 2u, pc, inst.src0, nullptr); + DecodeScalarSource(soffset, pc, inst.src1, nullptr); + inst.src_count = 2; return true; } bool DecodeMubuf(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error) { + Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { *error = fmt::format("truncated MUBUF instruction at pc 0x{:08x}", pc); @@ -272,34 +272,34 @@ bool DecodeMubuf(uint32_t pc, std::span code, uint32_t word_inde const uint32_t srsrc = (word1 >> 16u) & 0x1fu; const uint32_t soffset = (word1 >> 24u) & 0xffu; - inst->pc = pc; - inst->word = word0; - inst->word_count = 2; - inst->offset = word0 & 0xfffu; - inst->idxen = ((word0 >> 13u) & 1u) != 0; - inst->offen = ((word0 >> 12u) & 1u) != 0; - inst->glc = ((word0 >> 14u) & 1u) != 0; - inst->slc = ((word1 >> 22u) & 1u) != 0; - inst->family = Family::MUBUF; - inst->opcode_id = opcode; + inst.pc = pc; + inst.word = word0; + inst.word_count = 2; + inst.offset = word0 & 0xfffu; + inst.idxen = ((word0 >> 13u) & 1u) != 0; + inst.offen = ((word0 >> 12u) & 1u) != 0; + inst.glc = ((word0 >> 14u) & 1u) != 0; + inst.slc = ((word1 >> 22u) & 1u) != 0; + inst.family = Family::MUBUF; + inst.opcode_id = opcode; const auto* info = LookupMemoryOpcode(MUBUF_OPS, static_cast(std::size(MUBUF_OPS)), opcode); ApplyMemoryInfo(inst, info); SetRawWords(inst, code, word_index, 2); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { MarkMemoryUnsupported(inst, Family::MUBUF, opcode, "MUBUF opcode is not implemented"); } - DecodeVectorGpr(vdata, &inst->dst, nullptr); - DecodeVectorGpr(vaddr, &inst->src0, nullptr); - DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr); - DecodeScalarSource(soffset, pc, &inst->src2, nullptr); - inst->src_count = 3; + DecodeVectorGpr(vdata, inst.dst, nullptr); + DecodeVectorGpr(vaddr, inst.src0, nullptr); + DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr); + DecodeScalarSource(soffset, pc, inst.src2, nullptr); + inst.src_count = 3; return true; } bool DecodeMtbuf(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error) { + Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { *error = fmt::format("truncated MTBUF instruction at pc 0x{:08x}", pc); @@ -317,35 +317,35 @@ bool DecodeMtbuf(uint32_t pc, std::span code, uint32_t word_inde const uint32_t srsrc = (word1 >> 16u) & 0x1fu; const uint32_t soffset = (word1 >> 24u) & 0xffu; - inst->pc = pc; - inst->word = word0; - inst->word_count = 2; - inst->offset = word0 & 0xfffu; - inst->idxen = ((word0 >> 13u) & 1u) != 0; - inst->offen = ((word0 >> 12u) & 1u) != 0; - inst->glc = ((word0 >> 14u) & 1u) != 0; - inst->slc = ((word1 >> 22u) & 1u) != 0; - inst->family = Family::MTBUF; - inst->opcode_id = opcode; - inst->data_format = dfmt; - inst->number_format = nfmt; + inst.pc = pc; + inst.word = word0; + inst.word_count = 2; + inst.offset = word0 & 0xfffu; + inst.idxen = ((word0 >> 13u) & 1u) != 0; + inst.offen = ((word0 >> 12u) & 1u) != 0; + inst.glc = ((word0 >> 14u) & 1u) != 0; + inst.slc = ((word1 >> 22u) & 1u) != 0; + inst.family = Family::MTBUF; + inst.opcode_id = opcode; + inst.data_format = dfmt; + inst.number_format = nfmt; const auto* info = LookupMemoryOpcode(MTBUF_OPS, static_cast(std::size(MTBUF_OPS)), opcode); ApplyMemoryInfo(inst, info); SetRawWords(inst, code, word_index, 2); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { MarkMemoryUnsupported(inst, Family::MTBUF, opcode, "MTBUF opcode is not implemented"); } - DecodeVectorGpr(vdata, &inst->dst, nullptr); - DecodeVectorGpr(vaddr, &inst->src0, nullptr); - DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr); - DecodeScalarSource(soffset, pc, &inst->src2, nullptr); - inst->src_count = 3; + DecodeVectorGpr(vdata, inst.dst, nullptr); + DecodeVectorGpr(vaddr, inst.src0, nullptr); + DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr); + DecodeScalarSource(soffset, pc, inst.src2, nullptr); + inst.src_count = 3; return true; } -bool DecodeFlat(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeFlat(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { @@ -366,43 +366,43 @@ bool DecodeFlat(uint32_t pc, std::span code, uint32_t word_index const uint32_t data = (word1 >> 8u) & 0xffu; const uint32_t addr = word1 & 0xffu; - inst->pc = pc; - inst->word = word0; - inst->word_count = 2; - inst->offset = seg == 0u ? (offset & 0x7ffu) : SignExtendU32(offset, 12u); - inst->glc = ((word0 >> 16u) & 1u) != 0; - inst->slc = ((word0 >> 17u) & 1u) != 0; - inst->family = Family::FLAT; - inst->opcode_id = opcode; - inst->memory_segment = seg; + inst.pc = pc; + inst.word = word0; + inst.word_count = 2; + inst.offset = seg == 0u ? (offset & 0x7ffu) : SignExtendU32(offset, 12u); + inst.glc = ((word0 >> 16u) & 1u) != 0; + inst.slc = ((word0 >> 17u) & 1u) != 0; + inst.family = Family::FLAT; + inst.opcode_id = opcode; + inst.memory_segment = seg; const auto* info = LookupMemoryOpcode(FLAT_OPS, static_cast(std::size(FLAT_OPS)), opcode); ApplyMemoryInfo(inst, info); SetRawWords(inst, code, word_index, 2); - if (dlc != 0 || lds != 0 || inst->glc || inst->slc || seg == 3u) { + if (dlc != 0 || lds != 0 || inst.glc || inst.slc || seg == 3u) { SetUnsupported(inst, Family::FLAT, opcode, "FLAT modifiers or segment are not implemented"); return true; } - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { MarkMemoryUnsupported(inst, Family::FLAT, opcode, "FLAT opcode is not implemented"); return true; } - DecodeVectorGpr(IsFlatStoreOpcode(inst->opcode) ? data : vdst, &inst->dst, nullptr); - DecodeVectorGpr(addr, &inst->src0, nullptr); - inst->src_count = 1; + DecodeVectorGpr(IsFlatStoreOpcode(inst.opcode) ? data : vdst, inst.dst, nullptr); + DecodeVectorGpr(addr, inst.src0, nullptr); + inst.src_count = 1; if (seg == 0u || saddr == 0x7du || saddr == 0x7fu) { - DecodeVectorGpr(addr + 1u, &inst->src1, nullptr); - inst->src_count = 2; + DecodeVectorGpr(addr + 1u, inst.src1, nullptr); + inst.src_count = 2; } else { - DecodeScalarSource(saddr, pc, &inst->src1, nullptr); - inst->src_count = 2; + DecodeScalarSource(saddr, pc, inst.src1, nullptr); + inst.src_count = 2; } return true; } -bool DecodeDs(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeDs(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { @@ -421,59 +421,59 @@ bool DecodeDs(uint32_t pc, std::span code, uint32_t word_index, const uint32_t data0 = (word1 >> 8u) & 0xffu; const uint32_t addr = word1 & 0xffu; - inst->pc = pc; - inst->word = word0; - inst->word_count = 2; - inst->offset = offset0 | (offset1 << 8u); - inst->gds = ((word0 >> 17u) & 1u) != 0u; - inst->family = Family::DS; - inst->opcode_id = opcode; + inst.pc = pc; + inst.word = word0; + inst.word_count = 2; + inst.offset = offset0 | (offset1 << 8u); + inst.gds = ((word0 >> 17u) & 1u) != 0u; + inst.family = Family::DS; + inst.opcode_id = opcode; const auto* info = LookupMemoryOpcode(DS_OPS, static_cast(std::size(DS_OPS)), opcode); ApplyMemoryInfo(inst, info); SetRawWords(inst, code, word_index, 2); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { MarkMemoryUnsupported(inst, Family::DS, opcode, "DS opcode is not implemented"); } - if (inst->opcode == Opcode::DsSwizzleB32 && inst->offset >= 0xe000u) { + if (inst.opcode == Opcode::DsSwizzleB32 && inst.offset >= 0xe000u) { SetUnsupported(inst, Family::DS, opcode, "DS swizzle FFT mode is not implemented"); } - if (inst->gds && - (inst->opcode == Opcode::DsSwizzleB32 || inst->opcode == Opcode::DsWriteAddtidB32 || - inst->opcode == Opcode::DsReadAddtidB32)) { + if (inst.gds && + (inst.opcode == Opcode::DsSwizzleB32 || inst.opcode == Opcode::DsWriteAddtidB32 || + inst.opcode == Opcode::DsReadAddtidB32)) { SetUnsupported(inst, Family::DS, opcode, "DS swizzle/addtid is available only for LDS"); } - if (inst->gds && (inst->opcode == Opcode::DsAppend || inst->opcode == Opcode::DsConsume) && - inst->offset != 0u) { + if (inst.gds && (inst.opcode == Opcode::DsAppend || inst.opcode == Opcode::DsConsume) && + inst.offset != 0u) { SetUnsupported(inst, Family::DS, opcode, "GDS append/consume requires a zero instruction offset"); } - if (inst->opcode == Opcode::DsWriteAddtidB32 && data1 != 0u) { + if (inst.opcode == Opcode::DsWriteAddtidB32 && data1 != 0u) { SetUnsupported(inst, Family::DS, opcode, "DS write addtid data1 operand is not implemented"); } - if (inst->opcode == Opcode::DsReadAddtidB32 && (data0 != 0u || data1 != 0u)) { + if (inst.opcode == Opcode::DsReadAddtidB32 && (data0 != 0u || data1 != 0u)) { SetUnsupported(inst, Family::DS, opcode, "DS read addtid data operands are not implemented"); } - if (inst->opcode == Opcode::DsWrite2B32 || opcode == 0x37u) { - inst->offset = offset0 * 4u; - inst->secondary_offset = offset1 * 4u; - } else if (inst->opcode == Opcode::DsWrite2St64B32 || opcode == 0x38u) { - inst->offset = offset0 * 256u; - inst->secondary_offset = offset1 * 256u; - } else if (inst->opcode == Opcode::DsWrite2B64 || inst->opcode == Opcode::DsRead2B64) { - inst->offset = offset0 * 8u; - inst->secondary_offset = offset1 * 8u; - } else if (inst->opcode == Opcode::DsWrite2St64B64 || inst->opcode == Opcode::DsRead2St64B64) { - inst->offset = offset0 * 512u; - inst->secondary_offset = offset1 * 512u; + if (inst.opcode == Opcode::DsWrite2B32 || opcode == 0x37u) { + inst.offset = offset0 * 4u; + inst.secondary_offset = offset1 * 4u; + } else if (inst.opcode == Opcode::DsWrite2St64B32 || opcode == 0x38u) { + inst.offset = offset0 * 256u; + inst.secondary_offset = offset1 * 256u; + } else if (inst.opcode == Opcode::DsWrite2B64 || inst.opcode == Opcode::DsRead2B64) { + inst.offset = offset0 * 8u; + inst.secondary_offset = offset1 * 8u; + } else if (inst.opcode == Opcode::DsWrite2St64B64 || inst.opcode == Opcode::DsRead2St64B64) { + inst.offset = offset0 * 512u; + inst.secondary_offset = offset1 * 512u; } - DecodeVectorGpr(vdst, &inst->dst, nullptr); - DecodeVectorGpr(addr, &inst->src0, nullptr); - DecodeVectorGpr(data0, &inst->src1, nullptr); - DecodeVectorGpr(data1, &inst->src2, nullptr); - inst->src_count = DsSourceCount(inst->opcode); + DecodeVectorGpr(vdst, inst.dst, nullptr); + DecodeVectorGpr(addr, inst.src0, nullptr); + DecodeVectorGpr(data0, inst.src1, nullptr); + DecodeVectorGpr(data1, inst.src2, nullptr); + inst.src_count = DsSourceCount(inst.opcode); return true; } diff --git a/src/graphics/shader/recompiler/MemoryOps.h b/src/graphics/shader/recompiler/MemoryOps.h index ce0369430..6e212ee51 100644 --- a/src/graphics/shader/recompiler/MemoryOps.h +++ b/src/graphics/shader/recompiler/MemoryOps.h @@ -5,15 +5,15 @@ namespace Libs::Graphics::ShaderRecompiler::Decoder { -bool DecodeSmem(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSmem(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); bool DecodeMubuf(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error); + Instruction& inst, std::string* error); bool DecodeMtbuf(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error); -bool DecodeFlat(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, + Instruction& inst, std::string* error); +bool DecodeFlat(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); -bool DecodeDs(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeDs(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::Decoder diff --git a/src/graphics/shader/recompiler/ResourceMaterialization.cpp b/src/graphics/shader/recompiler/ResourceMaterialization.cpp index 785791251..da2008138 100644 --- a/src/graphics/shader/recompiler/ResourceMaterialization.cpp +++ b/src/graphics/shader/recompiler/ResourceMaterialization.cpp @@ -5,6 +5,7 @@ #include #include +#include namespace Libs::Graphics::ShaderRecompiler::IR { namespace { @@ -200,11 +201,10 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh } bool MaterializeResources(const Program& program, const SrtRuntime& runtime, - ResourceSnapshot* snapshot, std::string* error) { - if (snapshot == nullptr || !program.resource_tracking_complete) { + ResourceSnapshot& snapshot, std::string* error) { + if (!program.resource_tracking_complete) { if (error != nullptr) { - *error = snapshot == nullptr ? "invalid resource snapshot" - : "shader resources were not tracked"; + *error = "shader resources were not tracked"; } return false; } @@ -229,7 +229,7 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime, std::vector values; std::vector flattened_srt; - if (!EvaluateRuntimeSources(program, requests, runtime, &values, &flattened_srt, error)) { + if (!EvaluateRuntimeSources(program, requests, runtime, values, flattened_srt, error)) { return false; } @@ -280,25 +280,24 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime, if (!ValidateResourceSnapshot(program, next, error)) { return false; } - *snapshot = std::move(next); + snapshot = std::move(next); return true; } -bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std::string* error) { - if (program == nullptr || !program->resource_tracking_complete || - program->shader_info_complete || program->binding_layout_complete) { +bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std::string* error) { + if (!program.resource_tracking_complete || program.shader_info_complete || + program.binding_layout_complete) { if (error != nullptr) { - *error = program == nullptr ? "invalid resource specialization program" - : !program->resource_tracking_complete ? "shader resources were not tracked" - : "resource specialization is too late"; + *error = !program.resource_tracking_complete ? "shader resources were not tracked" + : "resource specialization is too late"; } return false; } - if (!ValidateResourceSnapshot(*program, snapshot, error)) { + if (!ValidateResourceSnapshot(program, snapshot, error)) { return false; } - auto next = program->info; + auto next = program.info; for (uint32_t i = 0; i < next.buffers.size(); i++) { ShaderBufferResource descriptor; if (!DecodeBufferDescriptor(snapshot.buffers[i], descriptor)) { @@ -347,12 +346,12 @@ bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std } } struct ImagePatch { - Instruction* inst; + std::reference_wrapper inst; ResourceKind kind; Decoder::ImageDimension dimension; }; std::vector patches; - for (auto& block: program->blocks) { + for (auto& block: program.blocks) { for (auto& inst: block.instructions) { if (inst.memory.kind != ResourceKind::Image && inst.memory.kind != ResourceKind::ImageUint && @@ -368,13 +367,13 @@ bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std return false; } const auto& image = next.images[inst.memory.resource]; - patches.push_back({&inst, image.kind, image.dimension}); + patches.push_back({std::ref(inst), image.kind, image.dimension}); } } - program->info = std::move(next); + program.info = std::move(next); for (const auto& patch: patches) { - patch.inst->memory.kind = patch.kind; - patch.inst->memory.image_dimension = patch.dimension; + patch.inst.get().memory.kind = patch.kind; + patch.inst.get().memory.image_dimension = patch.dimension; } return true; } diff --git a/src/graphics/shader/recompiler/ResourceMaterialization.h b/src/graphics/shader/recompiler/ResourceMaterialization.h index 714f858ad..7b40c7d53 100644 --- a/src/graphics/shader/recompiler/ResourceMaterialization.h +++ b/src/graphics/shader/recompiler/ResourceMaterialization.h @@ -31,11 +31,11 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh // Resolves the immutable dense resource topology against one runtime user-data/SRT snapshot. // On failure the destination is unchanged. bool MaterializeResources(const Program& program, const SrtRuntime& runtime, - ResourceSnapshot* snapshot, std::string* error); + ResourceSnapshot& snapshot, std::string* error); // Applies runtime descriptor shape/format facts to a copied dense topology before layout and // emission. On failure the program is unchanged. -bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std::string* error); +bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::IR diff --git a/src/graphics/shader/recompiler/ResourceTracking.cpp b/src/graphics/shader/recompiler/ResourceTracking.cpp index 232d15c5e..e35bc70a8 100644 --- a/src/graphics/shader/recompiler/ResourceTracking.cpp +++ b/src/graphics/shader/recompiler/ResourceTracking.cpp @@ -4,6 +4,7 @@ #include #include +#include namespace Libs::Graphics::ShaderRecompiler::IR { namespace { @@ -82,17 +83,17 @@ uint32_t ByteExtent(const Instruction& inst) { return end > UINT32_MAX ? UINT32_MAX : static_cast(end); } -bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vector* visited, - std::vector* path) { - path->push_back(id); +bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vector& visited, + std::vector& path) { + path.push_back(id); if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) { return true; } - if ((*visited)[id] != 0) { - path->pop_back(); + if (visited[id] != 0) { + path.pop_back(); return false; } - (*visited)[id] = 1; + visited[id] = 1; const auto& value = provenance.values[id]; if (value.op == ScalarValueOp::Phi) { for (const auto arg: value.phi_args) { @@ -100,7 +101,7 @@ bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vecto return true; } } - path->pop_back(); + path.pop_back(); return false; } const auto args = ScalarValueArgCount(value.op); @@ -109,19 +110,19 @@ bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vecto return true; } } - path->pop_back(); + path.pop_back(); return false; } bool IsLoopInvariantValue(const ScalarProvenance& provenance, uint32_t id, - std::vector* visiting) { + std::vector& visiting) { if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) { return false; } - if ((*visiting)[id] != 0) { + if (visiting[id] != 0) { return true; } - (*visiting)[id] = 1; + visiting[id] = 1; const auto& value = provenance.values[id]; if (value.op == ScalarValueOp::Phi) { uint32_t invariant = ScalarProvenance::Undefined; @@ -150,7 +151,7 @@ bool IsLoopInvariantDescriptor(const ScalarProvenance& provenance, const DescriptorValue& descriptor) { std::vector visiting(provenance.values.size()); for (uint32_t i = 0; i < descriptor.dword_count; i++) { - if (!IsLoopInvariantValue(provenance, descriptor.dwords[i], &visiting)) { + if (!IsLoopInvariantValue(provenance, descriptor.dwords[i], visiting)) { return false; } } @@ -173,7 +174,7 @@ public: } for (auto& block: m_program.blocks) { for (auto& inst: block.instructions) { - if (!Collect(&inst, error)) { + if (!Collect(inst, error)) { return false; } } @@ -181,10 +182,11 @@ public: LinkImageAliases(); m_program.info = std::move(m_info); for (const auto& patch: m_patches) { - patch.inst->memory.resource = patch.resource; - patch.inst->memory.sampler = patch.sampler; - patch.inst->memory.resource_source = ScalarProvenance::Undefined; - patch.inst->memory.sampler_source = ScalarProvenance::Undefined; + auto& inst = patch.inst.get(); + inst.memory.resource = patch.resource; + inst.memory.sampler = patch.sampler; + inst.memory.resource_source = ScalarProvenance::Undefined; + inst.memory.sampler_source = ScalarProvenance::Undefined; } m_program.resource_tracking_complete = true; return true; @@ -192,9 +194,9 @@ public: private: struct Patch { - Instruction* inst = nullptr; - uint32_t resource = 0; - uint32_t sampler = 0; + std::reference_wrapper inst; + uint32_t resource = 0; + uint32_t sampler = 0; }; bool Fail(uint32_t pc, std::string* error, const std::string& reason) const { @@ -214,7 +216,7 @@ private: std::vector visited(m_program.provenance.values.size()); for (uint32_t i = 0; i < descriptor->dword_count; i++) { std::vector path; - if (ContainsUnknown(m_program.provenance, descriptor->dwords[i], &visited, &path)) { + if (ContainsUnknown(m_program.provenance, descriptor->dwords[i], visited, path)) { const auto value = descriptor->dwords[i]; std::string chain; for (const auto id: path) { @@ -400,50 +402,49 @@ private: return true; } - bool Collect(Instruction* inst, std::string* error) { - if (IsAddress(*inst)) { - const bool unbased = inst->memory.resource_source == ScalarProvenance::Unknown; - if ((!unbased && !ValidateSource(inst->memory.resource_source, 2, inst->pc, error)) || - (unbased && inst->memory.kind != ResourceKind::Flat && - inst->memory.kind != ResourceKind::Global && - inst->memory.kind != ResourceKind::Scratch)) { - return unbased ? Fail(inst->pc, error, "scalar memory base is unresolved") : false; + bool Collect(Instruction& inst, std::string* error) { + if (IsAddress(inst)) { + const bool unbased = inst.memory.resource_source == ScalarProvenance::Unknown; + if ((!unbased && !ValidateSource(inst.memory.resource_source, 2, inst.pc, error)) || + (unbased && inst.memory.kind != ResourceKind::Flat && + inst.memory.kind != ResourceKind::Global && + inst.memory.kind != ResourceKind::Scratch)) { + return unbased ? Fail(inst.pc, error, "scalar memory base is unresolved") : false; } - const auto resource = AddAddress(*inst); + const auto resource = AddAddress(inst); if (resource == UINT32_MAX) { - return Fail(inst->pc, error, "address resource limit exceeded"); + return Fail(inst.pc, error, "address resource limit exceeded"); } - m_patches.push_back({inst, resource, 0}); + m_patches.push_back({std::ref(inst), resource, 0}); return true; } - if (!IsBuffer(*inst) && !IsImage(*inst)) { + if (!IsBuffer(inst) && !IsImage(inst)) { return true; } - if (!ValidateSource(inst->memory.resource_source, IsBuffer(*inst) ? 4u : 8u, inst->pc, + if (!ValidateSource(inst.memory.resource_source, IsBuffer(inst) ? 4u : 8u, inst.pc, error)) { return false; } - Patch patch; - patch.inst = inst; - patch.resource = IsBuffer(*inst) ? AddBuffer(*inst) : AddImage(*inst); - if (patch.resource == UINT32_MAX) { - return Fail(inst->pc, error, - IsBuffer(*inst) ? "buffer resource limit exceeded" - : "image resource limit exceeded"); + const auto resource = IsBuffer(inst) ? AddBuffer(inst) : AddImage(inst); + if (resource == UINT32_MAX) { + return Fail(inst.pc, error, + IsBuffer(inst) ? "buffer resource limit exceeded" + : "image resource limit exceeded"); } - if (NeedsSampler(inst->op)) { - if (!ValidateSource(inst->memory.sampler_source, 4, inst->pc, error)) { + uint32_t sampler = 0; + if (NeedsSampler(inst.op)) { + if (!ValidateSource(inst.memory.sampler_source, 4, inst.pc, error)) { return false; } - patch.sampler = AddSampler(*inst); - if (patch.sampler == UINT32_MAX) { - return Fail(inst->pc, error, "sampler resource limit exceeded"); + sampler = AddSampler(inst); + if (sampler == UINT32_MAX) { + return Fail(inst.pc, error, "sampler resource limit exceeded"); } - if (!AddSampledPair(patch.resource, patch.sampler, inst->pc, error)) { + if (!AddSampledPair(resource, sampler, inst.pc, error)) { return false; } } - m_patches.push_back(patch); + m_patches.push_back({std::ref(inst), resource, sampler}); return true; } @@ -454,15 +455,8 @@ private: } // namespace -bool TrackResources(Program* program, std::string* error) { - if (program == nullptr) { - if (error != nullptr) { - *error = "shader resource tracking: hash=0x0000000000000000 stage=unknown " - "pc=0x00000000 invalid program"; - } - return false; - } - return Tracker(*program).Run(error); +bool TrackResources(Program& program, std::string* error) { + return Tracker(program).Run(error); } } // namespace Libs::Graphics::ShaderRecompiler::IR diff --git a/src/graphics/shader/recompiler/ResourceTracking.h b/src/graphics/shader/recompiler/ResourceTracking.h index 23245a332..3bd17e519 100644 --- a/src/graphics/shader/recompiler/ResourceTracking.h +++ b/src/graphics/shader/recompiler/ResourceTracking.h @@ -7,7 +7,7 @@ namespace Libs::Graphics::ShaderRecompiler::IR { // Collects immutable resource topology, then replaces descriptor operands with dense indices. // On failure the program is left unpatched. -bool TrackResources(Program* program, std::string* error); +bool TrackResources(Program& program, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::IR diff --git a/src/graphics/shader/recompiler/ScalarAluOps.cpp b/src/graphics/shader/recompiler/ScalarAluOps.cpp index 2597e20f6..5b7792514 100644 --- a/src/graphics/shader/recompiler/ScalarAluOps.cpp +++ b/src/graphics/shader/recompiler/ScalarAluOps.cpp @@ -89,59 +89,59 @@ Opcode Lookup(const OpcodeMap* ops, uint32_t count, uint32_t opcode) { } bool DecodeBinarySources(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) { - if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error) || - !DecodeScalarSource(ssrc1, pc, &inst->src1, error)) { + Instruction& inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) { + if (!DecodeScalarSource(ssrc0, pc, inst.src0, error) || + !DecodeScalarSource(ssrc1, pc, inst.src1, error)) { return false; } - inst->src_count = 2; + inst.src_count = 2; return ReadLiteralOperands(code, word_index, inst, error); } } // namespace -bool DecodeSop1(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSop1(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { const uint32_t word = code[word_index]; const uint32_t opcode = (word >> 8u) & 0xffu; const uint32_t ssrc0 = word & 0xffu; const uint32_t sdst = (word >> 16u) & 0x7fu; - inst->pc = pc; - inst->word = word; - inst->family = Family::SOP1; - inst->opcode_id = opcode; - inst->opcode = Lookup(SOP1_OPS, static_cast(std::size(SOP1_OPS)), opcode); + inst.pc = pc; + inst.word = word; + inst.family = Family::SOP1; + inst.opcode_id = opcode; + inst.opcode = Lookup(SOP1_OPS, static_cast(std::size(SOP1_OPS)), opcode); SetRawWords(inst, code, word_index, 1); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::SOP1, opcode, "SOP1 opcode is not implemented"); return true; } - switch (inst->opcode) { + switch (inst.opcode) { case Opcode::SGetpcB64: - inst->src_count = 0; - return DecodeScalarDestination(sdst, pc, &inst->dst, error); + inst.src_count = 0; + return DecodeScalarDestination(sdst, pc, inst.dst, error); case Opcode::SSetpcB64: - inst->src_count = 1; - inst->dst.kind = OperandKind::Null; - if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error)) { + inst.src_count = 1; + inst.dst.kind = OperandKind::Null; + if (!DecodeScalarSource(ssrc0, pc, inst.src0, error)) { return false; } return ReadLiteralOperands(code, word_index, inst, error); default: break; } - if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error) || - !DecodeScalarDestination(sdst, pc, &inst->dst, error)) { + if (!DecodeScalarSource(ssrc0, pc, inst.src0, error) || + !DecodeScalarDestination(sdst, pc, inst.dst, error)) { return false; } - inst->src_count = 1; + inst.src_count = 1; return ReadLiteralOperands(code, word_index, inst, error); } -bool DecodeSop2(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSop2(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { const uint32_t word = code[word_index]; const uint32_t opcode = (word >> 23u) & 0x7fu; @@ -149,25 +149,25 @@ bool DecodeSop2(uint32_t pc, std::span code, uint32_t word_index const uint32_t ssrc0 = word & 0xffu; const uint32_t sdst = (word >> 16u) & 0x7fu; - inst->pc = pc; - inst->word = word; - inst->family = Family::SOP2; - inst->opcode_id = opcode; - inst->opcode = Lookup(SOP2_OPS, static_cast(std::size(SOP2_OPS)), opcode); + inst.pc = pc; + inst.word = word; + inst.family = Family::SOP2; + inst.opcode_id = opcode; + inst.opcode = Lookup(SOP2_OPS, static_cast(std::size(SOP2_OPS)), opcode); SetRawWords(inst, code, word_index, 1); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::SOP2, opcode, "SOP2 opcode is not implemented"); return true; } - if (!DecodeScalarDestination(sdst, pc, &inst->dst, error)) { + if (!DecodeScalarDestination(sdst, pc, inst.dst, error)) { return false; } return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error); } -bool DecodeSopk(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSopk(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { const uint32_t word = code[word_index]; const uint32_t opcode = (word >> 23u) & 0x1fu; @@ -176,72 +176,72 @@ bool DecodeSopk(uint32_t pc, std::span code, uint32_t word_index (void)error; - inst->pc = pc; - inst->word = word; - inst->family = Family::SOPK; - inst->opcode_id = opcode; - inst->opcode = Lookup(SOPK_OPS, static_cast(std::size(SOPK_OPS)), opcode); - inst->src0.kind = OperandKind::IntegerInlineConstant; - inst->src0.signed_val = imm; - inst->src0.value = static_cast(imm); - inst->src_count = 1; + inst.pc = pc; + inst.word = word; + inst.family = Family::SOPK; + inst.opcode_id = opcode; + inst.opcode = Lookup(SOPK_OPS, static_cast(std::size(SOPK_OPS)), opcode); + inst.src0.kind = OperandKind::IntegerInlineConstant; + inst.src0.signed_val = imm; + inst.src0.value = static_cast(imm); + inst.src_count = 1; SetRawWords(inst, code, word_index, 1); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::SOPK, opcode, "SOPK opcode is not implemented"); return true; } - switch (inst->opcode) { - case Opcode::SMovkI32: return DecodeScalarDestination(sdst, pc, &inst->dst, error); + switch (inst.opcode) { + case Opcode::SMovkI32: return DecodeScalarDestination(sdst, pc, inst.dst, error); case Opcode::SWaitcnt: { const uint32_t waitcnt = word & 0xffffu; - inst->dst.kind = OperandKind::Null; - inst->src0.signed_val = static_cast(waitcnt); - inst->src0.value = waitcnt; - inst->src_count = 1; + inst.dst.kind = OperandKind::Null; + inst.src0.signed_val = static_cast(waitcnt); + inst.src0.value = waitcnt; + inst.src_count = 1; return true; } case Opcode::SSetregB32: - inst->dst.kind = OperandKind::Null; - inst->src1.kind = OperandKind::LiteralConstant; - inst->src1.value = word & 0xffffu; - inst->src1.signed_val = static_cast(imm); - inst->src_count = 2; - return DecodeScalarSource(sdst, pc, &inst->src0, error); + inst.dst.kind = OperandKind::Null; + inst.src1.kind = OperandKind::LiteralConstant; + inst.src1.value = word & 0xffffu; + inst.src1.signed_val = static_cast(imm); + inst.src_count = 2; + return DecodeScalarSource(sdst, pc, inst.src0, error); default: break; } - inst->src1 = inst->src0; - if (!DecodeScalarSource(sdst, pc, &inst->src0, error)) { + inst.src1 = inst.src0; + if (!DecodeScalarSource(sdst, pc, inst.src0, error)) { return false; } - if (inst->opcode == Opcode::SAddI32 || inst->opcode == Opcode::SMulkI32) { - inst->src_count = 2; - return DecodeScalarDestination(sdst, pc, &inst->dst, error); + if (inst.opcode == Opcode::SAddI32 || inst.opcode == Opcode::SMulkI32) { + inst.src_count = 2; + return DecodeScalarDestination(sdst, pc, inst.dst, error); } - inst->dst.kind = OperandKind::Scc; - inst->src_count = 2; + inst.dst.kind = OperandKind::Scc; + inst.src_count = 2; return true; } -bool DecodeSopc(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSopc(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { const uint32_t word = code[word_index]; const uint32_t ssrc1 = (word >> 8u) & 0xffu; const uint32_t ssrc0 = word & 0xffu; const uint32_t opcode = (word >> 16u) & 0x7fu; - inst->pc = pc; - inst->word = word; - inst->family = Family::SOPC; - inst->opcode_id = opcode; - inst->opcode = Lookup(SOPC_OPS, static_cast(std::size(SOPC_OPS)), opcode); - inst->dst.kind = OperandKind::Scc; + inst.pc = pc; + inst.word = word; + inst.family = Family::SOPC; + inst.opcode_id = opcode; + inst.opcode = Lookup(SOPC_OPS, static_cast(std::size(SOPC_OPS)), opcode); + inst.dst.kind = OperandKind::Scc; SetRawWords(inst, code, word_index, 1); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::SOPC, opcode, "SOPC opcode is not implemented"); return true; } @@ -249,7 +249,7 @@ bool DecodeSopc(uint32_t pc, std::span code, uint32_t word_index return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error); } -bool DecodeSopp(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSopp(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { const uint32_t word = code[word_index]; const uint32_t opcode = (word >> 16u) & 0x7fu; @@ -257,24 +257,24 @@ bool DecodeSopp(uint32_t pc, std::span code, uint32_t word_index (void)error; - inst->pc = pc; - inst->word = word; - inst->family = Family::SOPP; - inst->opcode_id = opcode; - inst->opcode = Lookup(SOPP_OPS, static_cast(std::size(SOPP_OPS)), opcode); - inst->src0.kind = OperandKind::LiteralConstant; - inst->src0.value = simm; - inst->src0.signed_val = static_cast(simm); - inst->src_count = (inst->opcode == Opcode::SNop || inst->opcode == Opcode::SWaitcnt || - inst->opcode == Opcode::SSleep || inst->opcode == Opcode::SSendmsg || - inst->opcode == Opcode::STtraceData || inst->opcode == Opcode::SInstPrefetch) + inst.pc = pc; + inst.word = word; + inst.family = Family::SOPP; + inst.opcode_id = opcode; + inst.opcode = Lookup(SOPP_OPS, static_cast(std::size(SOPP_OPS)), opcode); + inst.src0.kind = OperandKind::LiteralConstant; + inst.src0.value = simm; + inst.src0.signed_val = static_cast(simm); + inst.src_count = (inst.opcode == Opcode::SNop || inst.opcode == Opcode::SWaitcnt || + inst.opcode == Opcode::SSleep || inst.opcode == Opcode::SSendmsg || + inst.opcode == Opcode::STtraceData || inst.opcode == Opcode::SInstPrefetch) ? 1 : 0; - inst->branch_offset = static_cast(static_cast(simm)) * 4; - inst->branch_target = pc + 4u + static_cast(inst->branch_offset); + inst.branch_offset = static_cast(static_cast(simm)) * 4; + inst.branch_target = pc + 4u + static_cast(inst.branch_offset); SetRawWords(inst, code, word_index, 1); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::SOPP, opcode, "SOPP control-flow opcode is not implemented"); } return true; diff --git a/src/graphics/shader/recompiler/ScalarAluOps.h b/src/graphics/shader/recompiler/ScalarAluOps.h index 2e7658231..3d073dd05 100644 --- a/src/graphics/shader/recompiler/ScalarAluOps.h +++ b/src/graphics/shader/recompiler/ScalarAluOps.h @@ -5,15 +5,15 @@ namespace Libs::Graphics::ShaderRecompiler::Decoder { -bool DecodeSop1(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSop1(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); -bool DecodeSop2(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSop2(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); -bool DecodeSopk(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSopk(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); -bool DecodeSopc(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSopc(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); -bool DecodeSopp(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeSopp(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::Decoder diff --git a/src/graphics/shader/recompiler/ScalarProvenance.cpp b/src/graphics/shader/recompiler/ScalarProvenance.cpp index 1266a6be2..56771ae3f 100644 --- a/src/graphics/shader/recompiler/ScalarProvenance.cpp +++ b/src/graphics/shader/recompiler/ScalarProvenance.cpp @@ -140,20 +140,20 @@ bool ScalarMemoryLoad(Opcode op) { return op == Opcode::SLoadDword || op == Opcode::SBufferLoadDword; } -bool ValueResolved(const ScalarProvenance& provenance, uint32_t id, std::vector* visited) { +bool ValueResolved(const ScalarProvenance& provenance, uint32_t id, std::vector& visited) { if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) { return false; } - if ((*visited)[id] == 1) { + if (visited[id] == 1) { return false; } - if ((*visited)[id] == 2) { + if (visited[id] == 2) { return true; } - if ((*visited)[id] == 3) { + if (visited[id] == 3) { return false; } - (*visited)[id] = 1; + visited[id] = 1; const auto& value = provenance.values[id]; bool resolved = true; if (value.op == ScalarValueOp::Phi) { @@ -167,13 +167,13 @@ bool ValueResolved(const ScalarProvenance& provenance, uint32_t id, std::vector< resolved = ValueResolved(provenance, value.args[i], visited); } } - (*visited)[id] = resolved ? 2 : 3; + visited[id] = resolved ? 2 : 3; return resolved; } class Builder { public: - explicit Builder(Program* program): m_program(program), m_graph(program->provenance) {} + explicit Builder(Program& program): m_program(program), m_graph(program.provenance) {} bool Run(std::string* error) { m_graph = {}; @@ -181,7 +181,7 @@ public: m_graph.values[ScalarProvenance::Undefined].op = ScalarValueOp::Undefined; m_graph.values[ScalarProvenance::Unknown].op = ScalarValueOp::Unknown; - const auto block_count = m_program->blocks.size(); + const auto block_count = m_program.blocks.size(); m_entry.resize(block_count); m_exit.resize(block_count); m_phi.resize(block_count); @@ -200,8 +200,8 @@ public: m_user_data.Fill(ScalarProvenance::Undefined); for (uint32_t reg = 0; reg < ScalarRegisters; reg++) { m_user_data.regs[reg] = - reg >= m_program->user_data_base && - reg - m_program->user_data_base < m_program->user_data_count + reg >= m_program.user_data_base && + reg - m_program.user_data_base < m_program.user_data_count ? InternValue({ScalarValueOp::UserData, 0, reg}) : ScalarProvenance::Unknown; } @@ -211,7 +211,7 @@ public: if (block_count == 0) { return true; } - for (const auto& block: m_program->blocks) { + for (const auto& block: m_program.blocks) { for (const auto predecessor: block.predecessors) { if (predecessor >= block_count) { return Fail(error, fmt::format("scalar provenance has invalid predecessor {}", @@ -238,20 +238,20 @@ public: const bool entry_changed = next_entry != m_entry[block_index]; m_entry[block_index] = next_entry; - auto next_exit = Execute(m_program->blocks[block_index], next_entry, false); + auto next_exit = Execute(m_program.blocks[block_index], next_entry, false); const bool was_ready = m_exit_ready[block_index]; if (was_ready && !entry_changed && next_exit == m_exit[block_index]) { continue; } m_exit[block_index] = next_exit; m_exit_ready[block_index] = true; - for (const auto successor: m_program->blocks[block_index].successors) { + for (const auto successor: m_program.blocks[block_index].successors) { Queue(successor); } } for (size_t block = 0; block < block_count; block++) { - Execute(m_program->blocks[block], m_entry[block], true); + Execute(m_program.blocks[block], m_entry[block], true); } return true; } @@ -366,40 +366,37 @@ private: return InternValue(std::move(node)); } - bool ConstantOperand(const Operand& operand, const ScalarState& state, uint32_t* value) { - if (value == nullptr) { - return false; - } + bool ConstantOperand(const Operand& operand, const ScalarState& state, uint32_t& value) { const auto id = OperandValue(operand, state); if (id >= m_graph.values.size() || m_graph.values[id].op != ScalarValueOp::Constant) { return false; } - *value = m_graph.values[id].imm; + value = m_graph.values[id].imm; return true; } uint32_t ReadVectorLane(const Instruction& inst, const ScalarState& state) { if (inst.src_count < 2 || inst.src[0].kind != OperandKind::Register || inst.src[0].reg.file != RegisterFile::Vector || - (m_program->wave_size != 32 && m_program->wave_size != 64)) { + (m_program.wave_size != 32 && m_program.wave_size != 64)) { return ScalarProvenance::Unknown; } uint32_t lane = 0; - if (!ConstantOperand(inst.src[1], state, &lane)) { + if (!ConstantOperand(inst.src[1], state, lane)) { return ScalarProvenance::Unknown; } const auto found = state.vector_lanes.find( - VectorLaneKey(inst.src[0].reg.index, lane % m_program->wave_size)); + VectorLaneKey(inst.src[0].reg.index, lane % m_program.wave_size)); return found != state.vector_lanes.end() ? found->second : ScalarProvenance::Unknown; } - void ClearVectorLanes(uint32_t reg, ScalarState* state) { - const auto first = state->vector_lanes.lower_bound(VectorLaneKey(reg, 0)); - const auto last = state->vector_lanes.lower_bound((static_cast(reg) + 1u) << 32u); - state->vector_lanes.erase(first, last); + void ClearVectorLanes(uint32_t reg, ScalarState& state) { + const auto first = state.vector_lanes.lower_bound(VectorLaneKey(reg, 0)); + const auto last = state.vector_lanes.lower_bound((static_cast(reg) + 1u) << 32u); + state.vector_lanes.erase(first, last); } - void WriteVectorDestination(const Instruction& inst, ScalarState* state) { + void WriteVectorDestination(const Instruction& inst, ScalarState& state) { if (inst.dst.kind != OperandKind::Register || inst.dst.reg.file != RegisterFile::Vector) { return; } @@ -410,8 +407,8 @@ private: for (uint32_t i = 0; i < inst.src_count; i++) { uint32_t src_reg = 0; if (VectorRegister(inst.src[i], src_reg) && - state->address_bases[src_reg] > ScalarProvenance::Unknown) { - address_base = state->address_bases[src_reg]; + state.address_bases[src_reg] > ScalarProvenance::Unknown) { + address_base = state.address_bases[src_reg]; break; } } @@ -419,16 +416,16 @@ private: for (uint32_t i = 0; i < inst.src_count; i++) { uint32_t src_reg = 0; if (ScalarRegister(inst.src[i], src_reg) && - state->regs[src_reg] > ScalarProvenance::Unknown) { - address_base = state->regs[src_reg]; + state.regs[src_reg] > ScalarProvenance::Unknown) { + address_base = state.regs[src_reg]; break; } } } } - state->address_bases[reg] = ScalarProvenance::Unknown; + state.address_bases[reg] = ScalarProvenance::Unknown; if (inst.op == Opcode::MoveRelDestU32) { - state->vector_lanes.clear(); + state.vector_lanes.clear(); return; } if (inst.op != Opcode::WriteLaneU32) { @@ -438,24 +435,24 @@ private: } for (uint32_t i = 0; i < dwords && reg <= UINT32_MAX - i; i++) { ClearVectorLanes(reg + i, state); - if (reg + i < state->address_bases.size()) { - state->address_bases[reg + i] = ScalarProvenance::Unknown; + if (reg + i < state.address_bases.size()) { + state.address_bases[reg + i] = ScalarProvenance::Unknown; } } - state->address_bases[reg] = address_base; + state.address_bases[reg] = address_base; return; } - if (inst.src_count < 2 || (m_program->wave_size != 32 && m_program->wave_size != 64)) { + if (inst.src_count < 2 || (m_program.wave_size != 32 && m_program.wave_size != 64)) { ClearVectorLanes(reg, state); return; } uint32_t lane = 0; - if (!ConstantOperand(inst.src[1], *state, &lane)) { + if (!ConstantOperand(inst.src[1], state, lane)) { ClearVectorLanes(reg, state); return; } - state->vector_lanes[VectorLaneKey(reg, lane % m_program->wave_size)] = - OperandValue(inst.src[0], *state); + state.vector_lanes[VectorLaneKey(reg, lane % m_program.wave_size)] = + OperandValue(inst.src[0], state); } uint32_t ReadConst(const Instruction& inst, const ScalarState& state, bool buffer) { @@ -514,31 +511,31 @@ private: } } - void UpdateScc(const Instruction& inst, const ScalarState& before, ScalarState* state) { + void UpdateScc(const Instruction& inst, const ScalarState& before, ScalarState& state) { switch (inst.op) { case Opcode::ScalarAddCarryU32: - state->scc = Define(inst, ScalarValueOp::Carry, before); + state.scc = Define(inst, ScalarValueOp::Carry, before); break; case Opcode::ScalarSubBorrowU32: - case Opcode::ScalarSubBorrowCarryU32: state->scc = DefineBorrow(inst, before); break; + case Opcode::ScalarSubBorrowCarryU32: state.scc = DefineBorrow(inst, before); break; case Opcode::ScalarShiftLeftAddCarryU32: - state->scc = Define(inst, ScalarValueOp::ShiftLeftAddCarry, before); + state.scc = Define(inst, ScalarValueOp::ShiftLeftAddCarry, before); break; default: break; } } - void WriteDestination(const Instruction& inst, ScalarState* state) { + void WriteDestination(const Instruction& inst, ScalarState& state) { if (inst.dst.kind == OperandKind::Register && inst.dst.reg.file == RegisterFile::Scc) { - state->scc = inst.op == Opcode::MoveU32 && inst.src_count != 0 - ? OperandValue(inst.src[0], *state) + state.scc = inst.op == Opcode::MoveU32 && inst.src_count != 0 + ? OperandValue(inst.src[0], state) : ScalarProvenance::Unknown; return; } if (inst.dst.kind == OperandKind::Register && inst.dst.reg.file == RegisterFile::M0) { - const auto before = *state; + const auto before = state; const auto op = Operation(inst.op); - state->m0 = inst.op == Opcode::MoveU32 && inst.src_count != 0 + state.m0 = inst.op == Opcode::MoveU32 && inst.src_count != 0 ? OperandValue(inst.src[0], before) : op != ScalarValueOp::Unknown ? Define(inst, op, before) : ScalarProvenance::Unknown; @@ -551,10 +548,10 @@ private: return; } - const auto before = *state; - state->regs[dst] = ScalarProvenance::Unknown; + const auto before = state; + state.regs[dst] = ScalarProvenance::Unknown; if (PairDwordOpcode(inst.op) && dst + 1 < ScalarRegisters) { - state->regs[dst + 1] = ScalarProvenance::Unknown; + state.regs[dst + 1] = ScalarProvenance::Unknown; } uint32_t value = ScalarProvenance::Unknown; @@ -582,10 +579,10 @@ private: if (inst.src_count != 0 && dst + 1 < ScalarRegisters) { if (ScalarRegister(inst.src[0], src) && src + 1 < ScalarRegisters) { value = before.regs[src]; - state->regs[dst + 1] = before.regs[src + 1]; + state.regs[dst + 1] = before.regs[src + 1]; } else { value = OperandValue(inst.src[0], before); - state->regs[dst + 1] = Constant( + state.regs[dst + 1] = Constant( inst.src[0].kind == OperandKind::ImmediateU32 && inst.src[0].sext_64 ? UINT32_MAX : 0u); @@ -596,7 +593,7 @@ private: case Opcode::BitFieldMaskU64: value = Define(inst, ScalarValueOp::BitFieldMaskU64Low, before); if (dst + 1 < ScalarRegisters) { - state->regs[dst + 1] = Define(inst, ScalarValueOp::BitFieldMaskU64High, before); + state.regs[dst + 1] = Define(inst, ScalarValueOp::BitFieldMaskU64High, before); } break; case Opcode::SLoadDword: value = ReadConst(inst, before, false); break; @@ -610,12 +607,12 @@ private: break; } } - state->regs[dst] = value; + state.regs[dst] = value; UpdateScc(inst, before, state); uint32_t dst2 = 0; if (ScalarRegister(inst.dst2, dst2)) { - state->regs[dst2] = + state.regs[dst2] = inst.src_count > 1 ? OperandValue(inst.src[1], before) : ScalarProvenance::Unknown; } } @@ -663,57 +660,57 @@ private: return AddDescriptor(descriptor); } - void AttachSources(Instruction* inst, const ScalarState& state) { - inst->memory.resource_source = 0; - inst->memory.sampler_source = 0; - if (inst->op == Opcode::SLoadDword) { - inst->memory.resource_source = AddDescriptor(state, inst->memory.resource, 2); + void AttachSources(Instruction& inst, const ScalarState& state) { + inst.memory.resource_source = 0; + inst.memory.sampler_source = 0; + if (inst.op == Opcode::SLoadDword) { + inst.memory.resource_source = AddDescriptor(state, inst.memory.resource, 2); return; } - if (inst->memory.kind == ResourceKind::Flat || inst->memory.kind == ResourceKind::Global || - inst->memory.kind == ResourceKind::Scratch) { - inst->memory.resource_source = ScalarProvenance::Unknown; - if (inst->memory.kind == ResourceKind::Flat) { - inst->memory.resource_source = AddFlatAddressDescriptor(*inst, state); + if (inst.memory.kind == ResourceKind::Flat || inst.memory.kind == ResourceKind::Global || + inst.memory.kind == ResourceKind::Scratch) { + inst.memory.resource_source = ScalarProvenance::Unknown; + if (inst.memory.kind == ResourceKind::Flat) { + inst.memory.resource_source = AddFlatAddressDescriptor(inst, state); } - for (uint32_t i = 0; i < inst->src_count; i++) { - const auto& source = inst->src[i]; - if (inst->memory.resource_source == ScalarProvenance::Unknown && + for (uint32_t i = 0; i < inst.src_count; i++) { + const auto& source = inst.src[i]; + if (inst.memory.resource_source == ScalarProvenance::Unknown && source.kind == OperandKind::Register && source.reg.file == RegisterFile::Scalar) { - inst->memory.resource_source = AddDescriptor(state, source.reg.index, 2); + inst.memory.resource_source = AddDescriptor(state, source.reg.index, 2); break; } } return; } - if (inst->memory.kind == ResourceKind::Buffer || - (inst->memory.kind == ResourceKind::ScalarBuffer && - inst->op == Opcode::SBufferLoadDword)) { - const auto base = inst->memory.resource * 4u; - inst->memory.resource_source = AddDescriptor(state, base, 4); + if (inst.memory.kind == ResourceKind::Buffer || + (inst.memory.kind == ResourceKind::ScalarBuffer && + inst.op == Opcode::SBufferLoadDword)) { + const auto base = inst.memory.resource * 4u; + inst.memory.resource_source = AddDescriptor(state, base, 4); return; } - if (inst->memory.kind == ResourceKind::Image || - inst->memory.kind == ResourceKind::ImageUint || - inst->memory.kind == ResourceKind::StorageImage || - inst->memory.kind == ResourceKind::StorageImageUint) { - inst->memory.resource_source = AddDescriptor(state, inst->memory.resource * 4u, 8); - if (inst->op == Opcode::ImageSample || inst->op == Opcode::ImageGather4 || - inst->op == Opcode::ImageGetLod) { - inst->memory.sampler_source = AddDescriptor(state, inst->memory.sampler * 4u, 4); + if (inst.memory.kind == ResourceKind::Image || + inst.memory.kind == ResourceKind::ImageUint || + inst.memory.kind == ResourceKind::StorageImage || + inst.memory.kind == ResourceKind::StorageImageUint) { + inst.memory.resource_source = AddDescriptor(state, inst.memory.resource * 4u, 8); + if (inst.op == Opcode::ImageSample || inst.op == Opcode::ImageGather4 || + inst.op == Opcode::ImageGetLod) { + inst.memory.sampler_source = AddDescriptor(state, inst.memory.sampler * 4u, 4); } } } - void AttachScalarSources(Instruction* inst, const ScalarState& state) { - std::fill(std::begin(inst->scalar_sources), std::end(inst->scalar_sources), + void AttachScalarSources(Instruction& inst, const ScalarState& state) { + std::fill(std::begin(inst.scalar_sources), std::end(inst.scalar_sources), ScalarProvenance::Undefined); - for (uint32_t i = 0; i < inst->src_count; i++) { - const auto& source = inst->src[i]; + for (uint32_t i = 0; i < inst.src_count; i++) { + const auto& source = inst.src[i]; if (source.kind == OperandKind::Register && source.reg.file != RegisterFile::Vector && source.reg.file != RegisterFile::Exec) { - inst->scalar_sources[i] = OperandValue(source, state); + inst.scalar_sources[i] = OperandValue(source, state); } } } @@ -729,11 +726,11 @@ private: auto& component_inst = block.instructions[index + component]; if (attach_sources) { component_inst.scalar_value = ScalarProvenance::Undefined; - AttachScalarSources(&component_inst, before); - AttachSources(&component_inst, before); + AttachScalarSources(component_inst, before); + AttachSources(component_inst, before); } auto component_state = before; - WriteDestination(component_inst, &component_state); + WriteDestination(component_inst, component_state); uint32_t dst = 0; ScalarRegister(component_inst.dst, dst); state.regs[dst] = component_state.regs[dst]; @@ -746,11 +743,11 @@ private: } if (attach_sources) { inst.scalar_value = ScalarProvenance::Undefined; - AttachScalarSources(&inst, state); - AttachSources(&inst, state); + AttachScalarSources(inst, state); + AttachSources(inst, state); } - WriteVectorDestination(inst, &state); - WriteDestination(inst, &state); + WriteVectorDestination(inst, state); + WriteDestination(inst, state); if (attach_sources) { uint32_t dst = 0; if (ScalarRegister(inst.dst, dst)) { @@ -765,7 +762,7 @@ private: ScalarState MergeEntry(size_t block_index) { ScalarState result; result.Fill(ScalarProvenance::Undefined); - const auto& block = m_program->blocks[block_index]; + const auto& block = m_program.blocks[block_index]; const auto merge = [&](uint32_t initial, auto predecessor_value, uint32_t* phi) { std::vector incoming; if (initial != ScalarProvenance::Undefined) { @@ -845,7 +842,7 @@ private: } } - Program* m_program; + Program& m_program; ScalarProvenance& m_graph; ScalarState m_user_data; std::vector m_entry; @@ -860,40 +857,34 @@ private: } // namespace -bool BuildScalarProvenance(Program* program, std::string* error) { - if (program == nullptr) { - if (error != nullptr) { - *error = "invalid scalar provenance program"; - } - return false; - } - if (program->resource_tracking_complete) { +bool BuildScalarProvenance(Program& program, std::string* error) { + if (program.resource_tracking_complete) { if (error != nullptr) { *error = "cannot rebuild scalar provenance after resource tracking"; } return false; } - if (program->user_data_count > 64) { + if (program.user_data_count > 64) { if (error != nullptr) { *error = "scalar provenance user-data count exceeds 64 SGPRs"; } return false; } - if (program->user_data_base > ScalarRegisters || - program->user_data_count > ScalarRegisters - program->user_data_base) { + if (program.user_data_base > ScalarRegisters || + program.user_data_count > ScalarRegisters - program.user_data_base) { if (error != nullptr) { *error = "scalar provenance user-data window is out of range"; } return false; } - if (program->srt_patching_complete) { + if (program.srt_patching_complete) { if (error != nullptr) { *error = "cannot rebuild scalar provenance after SRT patching"; } return false; } - program->srt = {}; - program->srt_plan_complete = false; + program.srt = {}; + program.srt_plan_complete = false; return Builder(program).Run(error); } @@ -911,7 +902,7 @@ bool DescriptorSourceResolved(const Program& program, uint32_t source) { } std::vector visited(program.provenance.values.size()); for (uint32_t i = 0; i < descriptor->dword_count; i++) { - if (!ValueResolved(program.provenance, descriptor->dwords[i], &visited)) { + if (!ValueResolved(program.provenance, descriptor->dwords[i], visited)) { return false; } } diff --git a/src/graphics/shader/recompiler/ScalarProvenance.h b/src/graphics/shader/recompiler/ScalarProvenance.h index 5657fb364..55cada635 100644 --- a/src/graphics/shader/recompiler/ScalarProvenance.h +++ b/src/graphics/shader/recompiler/ScalarProvenance.h @@ -6,7 +6,7 @@ namespace Libs::Graphics::ShaderRecompiler::IR { // Builds scalar reaching definitions and attaches descriptor sources to individual memory uses. -bool BuildScalarProvenance(Program* program, std::string* error); +bool BuildScalarProvenance(Program& program, std::string* error); uint32_t ScalarValueArgCount(ScalarValueOp op); diff --git a/src/graphics/shader/recompiler/ShaderCFG.cpp b/src/graphics/shader/recompiler/ShaderCFG.cpp index 4fe5ab4d8..176406755 100644 --- a/src/graphics/shader/recompiler/ShaderCFG.cpp +++ b/src/graphics/shader/recompiler/ShaderCFG.cpp @@ -30,14 +30,12 @@ void SetError(std::string* error, const std::string& message) { } } -void SetFailure(Graph* graph, FailureKind kind, uint32_t block_id, const std::string& message, +void SetFailure(Graph& graph, FailureKind kind, uint32_t block_id, const std::string& message, std::string* error) { - if (graph != nullptr) { - graph->unsupported = true; - graph->failure_kind = kind; - graph->failure_block = block_id; - graph->unsupported_reason = message; - } + graph.unsupported = true; + graph.failure_kind = kind; + graph.failure_block = block_id; + graph.unsupported_reason = message; SetError(error, message); } @@ -89,50 +87,41 @@ bool IsRegister(const Decoder::Operand& operand, Decoder::OperandKind kind, uint return operand.kind == kind && operand.reg == reg; } -bool ScalarOperandCode(const Decoder::Operand& operand, uint32_t* code) { - if (code == nullptr) { - return false; - } +bool ScalarOperandCode(const Decoder::Operand& operand, uint32_t& code) { switch (operand.kind) { - case Decoder::OperandKind::Sgpr: *code = operand.reg; return true; - case Decoder::OperandKind::VccLo: *code = 106u; return true; - case Decoder::OperandKind::VccHi: *code = 107u; return true; - case Decoder::OperandKind::M0: *code = 124u; return true; - case Decoder::OperandKind::ExecLo: *code = 126u; return true; - case Decoder::OperandKind::ExecHi: *code = 127u; return true; + case Decoder::OperandKind::Sgpr: code = operand.reg; return true; + case Decoder::OperandKind::VccLo: code = 106u; return true; + case Decoder::OperandKind::VccHi: code = 107u; return true; + case Decoder::OperandKind::M0: code = 124u; return true; + case Decoder::OperandKind::ExecLo: code = 126u; return true; + case Decoder::OperandKind::ExecHi: code = 127u; return true; default: return false; } } bool IsScalarCode(const Decoder::Operand& operand, uint32_t code) { uint32_t operand_code = 0; - return ScalarOperandCode(operand, &operand_code) && operand_code == code; + return ScalarOperandCode(operand, operand_code) && operand_code == code; } -bool IsImmediate(const Decoder::Operand& operand, uint32_t* value) { +bool IsImmediate(const Decoder::Operand& operand, uint32_t& value) { if (operand.kind == Decoder::OperandKind::IntegerInlineConstant || operand.kind == Decoder::OperandKind::LiteralConstant || operand.kind == Decoder::OperandKind::FloatInlineConstant) { - if (value != nullptr) { - *value = operand.value; - } + value = operand.value; return true; } return false; } -bool IsImmediateSigned(const Decoder::Operand& operand, int32_t* value) { +bool IsImmediateSigned(const Decoder::Operand& operand, int32_t& value) { if (operand.kind == Decoder::OperandKind::IntegerInlineConstant || operand.kind == Decoder::OperandKind::LiteralConstant) { - if (value != nullptr) { - *value = operand.signed_val; - } + value = operand.signed_val; return true; } if (operand.kind == Decoder::OperandKind::FloatInlineConstant) { - if (value != nullptr) { - *value = static_cast(operand.value); - } + value = static_cast(operand.value); return true; } return false; @@ -156,7 +145,7 @@ bool OtherScalarSource(const Instruction& inst, uint32_t known_code, bool InstructionWritesScalarCode(const Instruction& inst, uint32_t code) { uint32_t dst_code = 0; - if (!ScalarOperandCode(inst.dst, &dst_code)) { + if (!ScalarOperandCode(inst.dst, dst_code)) { return false; } const uint32_t count = std::max(1u, inst.data_dwords); @@ -203,8 +192,7 @@ bool ResolvePcRelativeBase(const Decoder::Program& program, uint32_t before_inde const Decoder::Operand* offset = nullptr; int32_t imm = 0; uint32_t getpc_index = 0; - if (!OtherScalarSource(candidate, base_code, &offset) || - !IsImmediateSigned(*offset, &imm) || + if (!OtherScalarSource(candidate, base_code, &offset) || !IsImmediateSigned(*offset, imm) || !FindPreviousGetpc(program, candidate_index, base_code, &getpc_index)) { return false; } @@ -242,7 +230,7 @@ bool ResolveJumpTableEntryCount(const Decoder::Program& program, uint32_t before return false; } uint32_t byte_offset_code = 0; - if (!ScalarOperandCode(byte_offset_operand, &byte_offset_code)) { + if (!ScalarOperandCode(byte_offset_operand, byte_offset_code)) { return false; } @@ -259,7 +247,7 @@ bool ResolveJumpTableEntryCount(const Decoder::Program& program, uint32_t before const Decoder::Operand* shift_amount_operand = nullptr; uint32_t shift_amount = 0; if (!OtherScalarSource(shift, byte_offset_code, &shift_amount_operand) || - !IsImmediate(*shift_amount_operand, &shift_amount) || shift_amount != 3u) { + !IsImmediate(*shift_amount_operand, shift_amount) || shift_amount != 3u) { return false; } @@ -278,7 +266,7 @@ bool ResolveJumpTableEntryCount(const Decoder::Program& program, uint32_t before const Decoder::Operand* clamp_other = nullptr; uint32_t max_index = 0; if (!OtherScalarSource(clamp, index_code, &clamp_other) || - !IsImmediate(*clamp_other, &max_index)) { + !IsImmediate(*clamp_other, max_index)) { return false; } *entry_count = max_index + 1u; @@ -289,12 +277,9 @@ bool ResolveJumpTableEntryCount(const Decoder::Program& program, uint32_t before return false; } -bool AddUniqueTargetPc(std::vector* targets, uint32_t target) { - if (targets == nullptr) { - return false; - } - if (std::find(targets->begin(), targets->end(), target) == targets->end()) { - targets->push_back(target); +bool AddUniqueTargetPc(std::vector& targets, uint32_t target) { + if (std::find(targets.begin(), targets.end(), target) == targets.end()) { + targets.push_back(target); } return true; } @@ -312,14 +297,14 @@ bool ScalarCodeWrittenInRange(const Decoder::Program& program, uint32_t begin_in } bool ResolveSetpcJumpTable(const Decoder::Program& program, uint32_t setpc_index, - SetpcTargetInfo* info) { - if (info == nullptr || setpc_index < 4u || setpc_index >= program.instructions.size()) { + SetpcTargetInfo& info) { + if (setpc_index < 4u || setpc_index >= program.instructions.size()) { return false; } const auto& setpc = program.instructions[setpc_index]; uint32_t pc_reg = 0; - if (setpc.opcode != Opcode::SSetpcB64 || !ScalarOperandCode(setpc.src0, &pc_reg) || + if (setpc.opcode != Opcode::SSetpcB64 || !ScalarOperandCode(setpc.src0, pc_reg) || setpc.src0.kind != Decoder::OperandKind::Sgpr) { return false; } @@ -339,8 +324,8 @@ bool ResolveSetpcJumpTable(const Decoder::Program& program, uint32_t setpc_index uint32_t offset_high_code = 0; if (!OtherScalarSource(add, pc_reg, &offset_low_operand) || !OtherScalarSource(addc, pc_reg + 1u, &offset_high_operand) || - !ScalarOperandCode(*offset_low_operand, &offset_low_code) || - !ScalarOperandCode(*offset_high_operand, &offset_high_code) || + !ScalarOperandCode(*offset_low_operand, offset_low_code) || + !ScalarOperandCode(*offset_high_operand, offset_high_code) || offset_high_code != offset_low_code + 1u) { return false; } @@ -351,7 +336,7 @@ bool ResolveSetpcJumpTable(const Decoder::Program& program, uint32_t setpc_index } const auto& load = program.instructions[load_index]; uint32_t table_base_code = 0; - if (!ScalarOperandCode(load.src0, &table_base_code)) { + if (!ScalarOperandCode(load.src0, table_base_code)) { return false; } @@ -365,7 +350,7 @@ bool ResolveSetpcJumpTable(const Decoder::Program& program, uint32_t setpc_index return false; } uint32_t selector_code = UINT32_MAX; - if (!ScalarOperandCode(load.src1, &selector_code) || + if (!ScalarOperandCode(load.src1, selector_code) || ScalarCodeWrittenInRange(program, load_index + 1u, setpc_index, selector_code)) { return false; } @@ -386,7 +371,7 @@ bool ResolveSetpcJumpTable(const Decoder::Program& program, uint32_t setpc_index return false; } const auto target_pc = (target_base + low) & ~3u; - AddUniqueTargetPc(&targets, target_pc); + AddUniqueTargetPc(targets, target_pc); selector_values.push_back(i * 8u); selector_target_pcs.push_back(target_pc); } @@ -394,18 +379,18 @@ bool ResolveSetpcJumpTable(const Decoder::Program& program, uint32_t setpc_index return false; } - info->indirect = true; - info->pc_sgpr = pc_reg; - info->selector_code = selector_code; - info->table_load_pc = load.pc; - info->target_pcs = std::move(targets); - info->selector_values = std::move(selector_values); - info->selector_target_pcs = std::move(selector_target_pcs); + info.indirect = true; + info.pc_sgpr = pc_reg; + info.selector_code = selector_code; + info.table_load_pc = load.pc; + info.target_pcs = std::move(targets); + info.selector_values = std::move(selector_values); + info.selector_target_pcs = std::move(selector_target_pcs); return true; } -bool ResolveSetpcTarget(const Decoder::Program& program, uint32_t setpc_index, uint32_t* target) { - if (target == nullptr || setpc_index >= program.instructions.size()) { +bool ResolveSetpcTarget(const Decoder::Program& program, uint32_t setpc_index, uint32_t& target) { + if (setpc_index >= program.instructions.size()) { return false; } @@ -427,10 +412,9 @@ bool ResolveSetpcTarget(const Decoder::Program& program, uint32_t setpc_index, u if ((adds || subs) && (IsRegister(arith.src0, Decoder::OperandKind::Sgpr, pc_reg) || IsRegister(arith.src1, Decoder::OperandKind::Sgpr, pc_reg)) && - (IsImmediate(arith.src0, &imm) || IsImmediate(arith.src1, &imm))) { + (IsImmediate(arith.src0, imm) || IsImmediate(arith.src1, imm))) { const auto base = InstructionEndPc(getpc); - *target = adds ? base + imm : base - imm; - *target &= ~3u; + target = (adds ? base + imm : base - imm) & ~3u; return true; } } @@ -440,7 +424,7 @@ bool ResolveSetpcTarget(const Decoder::Program& program, uint32_t setpc_index, u const auto& getpc = program.instructions[setpc_index - 1u]; if (getpc.opcode == Opcode::SGetpcB64 && getpc.dst.kind == Decoder::OperandKind::Sgpr && getpc.dst.reg == pc_reg) { - *target = InstructionEndPc(getpc); + target = InstructionEndPc(getpc); return true; } } @@ -449,17 +433,14 @@ bool ResolveSetpcTarget(const Decoder::Program& program, uint32_t setpc_index, u } bool ResolveSetpcTargets(const Decoder::Program& program, uint32_t setpc_index, - SetpcTargetInfo* info) { - if (info == nullptr) { - return false; - } - *info = {}; + SetpcTargetInfo& info) { + info = {}; if (ResolveSetpcJumpTable(program, setpc_index, info)) { return true; } uint32_t target = 0; - if (ResolveSetpcTarget(program, setpc_index, &target)) { - info->target = target; + if (ResolveSetpcTarget(program, setpc_index, target)) { + info.target = target; return true; } return false; @@ -470,9 +451,9 @@ bool IsValidTarget(uint32_t target, const std::set& instruction_pcs, u return target == end_pc || (target >= first_pc && instruction_pcs.contains(target)); } -void AddUnique(std::vector* values, uint32_t value) { - if (std::find(values->begin(), values->end(), value) == values->end()) { - values->push_back(value); +void AddUnique(std::vector& values, uint32_t value) { + if (std::find(values.begin(), values.end(), value) == values.end()) { + values.push_back(value); } } @@ -493,18 +474,18 @@ std::vector IntersectSorted(const std::vector& a, return ret; } -void SortUnique(std::vector* values) { - std::sort(values->begin(), values->end()); - values->erase(std::unique(values->begin(), values->end()), values->end()); +void SortUnique(std::vector& values) { + std::sort(values.begin(), values.end()); + values.erase(std::unique(values.begin(), values.end()), values.end()); } bool Contains(const std::vector& values, uint32_t value) { return std::find(values.begin(), values.end(), value) != values.end(); } -bool ReplaceValue(std::vector* values, uint32_t old_value, uint32_t new_value) { +bool ReplaceValue(std::vector& values, uint32_t old_value, uint32_t new_value) { bool changed = false; - for (auto& value: *values) { + for (auto& value: values) { if (value == old_value) { value = new_value; changed = true; @@ -516,21 +497,21 @@ bool ReplaceValue(std::vector* values, uint32_t old_value, uint32_t ne return changed; } -bool RemoveValue(std::vector* values, uint32_t value) { - const auto old_size = values->size(); - values->erase(std::remove(values->begin(), values->end(), value), values->end()); - return values->size() != old_size; +bool RemoveValue(std::vector& values, uint32_t value) { + const auto old_size = values.size(); + values.erase(std::remove(values.begin(), values.end(), value), values.end()); + return values.size() != old_size; } -bool ReplaceTerminatorTarget(Terminator* terminator, uint32_t old_value, uint32_t new_value) { +bool ReplaceTerminatorTarget(Terminator& terminator, uint32_t old_value, uint32_t new_value) { bool changed = false; - if (terminator->true_block == old_value) { - terminator->true_block = new_value; - changed = true; + if (terminator.true_block == old_value) { + terminator.true_block = new_value; + changed = true; } - if (terminator->false_block == old_value) { - terminator->false_block = new_value; - changed = true; + if (terminator.false_block == old_value) { + terminator.false_block = new_value; + changed = true; } return changed; } @@ -539,56 +520,55 @@ uint32_t RemapId(uint32_t id, const std::vector& id_map) { return id != UINT32_MAX && id < id_map.size() ? id_map[id] : id; } -void RemapIds(std::vector* values, const std::vector& id_map) { - for (auto& value: *values) { +void RemapIds(std::vector& values, const std::vector& id_map) { + for (auto& value: values) { value = RemapId(value, id_map); } SortUnique(values); } -void RebuildPredecessors(Graph* graph) { - for (auto& block: graph->blocks) { +void RebuildPredecessors(Graph& graph) { + for (auto& block: graph.blocks) { block.predecessors.clear(); - SortUnique(&block.successors); + SortUnique(block.successors); } - for (const auto& block: graph->blocks) { + for (const auto& block: graph.blocks) { for (auto succ: block.successors) { - if (succ < graph->blocks.size()) { - AddUnique(&graph->blocks[succ].predecessors, block.id); + if (succ < graph.blocks.size()) { + AddUnique(graph.blocks[succ].predecessors, block.id); } } } - for (auto& block: graph->blocks) { - SortUnique(&block.predecessors); + for (auto& block: graph.blocks) { + SortUnique(block.predecessors); } } -void ComputeDominators(Graph* graph) { - const auto count = static_cast(graph->blocks.size()); +void ComputeDominators(Graph& graph) { + const auto count = static_cast(graph.blocks.size()); const auto all = AllBlockIds(count); - for (auto& block: graph->blocks) { - block.dominators = - (block.id == graph->entry_block ? std::vector {block.id} : all); + for (auto& block: graph.blocks) { + block.dominators = (block.id == graph.entry_block ? std::vector {block.id} : all); } bool changed = true; while (changed) { changed = false; - for (auto& block: graph->blocks) { - if (block.id == graph->entry_block) { + for (auto& block: graph.blocks) { + if (block.id == graph.entry_block) { continue; } std::vector next; if (block.predecessors.empty()) { next = {block.id}; } else { - next = graph->blocks[block.predecessors.front()].dominators; + next = graph.blocks[block.predecessors.front()].dominators; for (uint32_t i = 1; i < block.predecessors.size(); i++) { - next = IntersectSorted(next, graph->blocks[block.predecessors[i]].dominators); + next = IntersectSorted(next, graph.blocks[block.predecessors[i]].dominators); } - AddUnique(&next, block.id); - SortUnique(&next); + AddUnique(next, block.id); + SortUnique(next); } if (next != block.dominators) { block.dominators = std::move(next); @@ -598,29 +578,28 @@ void ComputeDominators(Graph* graph) { } } -void ComputePostDominators(Graph* graph) { - const auto count = static_cast(graph->blocks.size()); +void ComputePostDominators(Graph& graph) { + const auto count = static_cast(graph.blocks.size()); const auto all = AllBlockIds(count); - for (auto& block: graph->blocks) { + for (auto& block: graph.blocks) { block.post_dominators = block.successors.empty() ? std::vector {block.id} : all; } bool changed = true; while (changed) { changed = false; - for (auto& block: graph->blocks) { + for (auto& block: graph.blocks) { std::vector next; if (block.successors.empty()) { next = {block.id}; } else { - next = graph->blocks[block.successors.front()].post_dominators; + next = graph.blocks[block.successors.front()].post_dominators; for (uint32_t i = 1; i < block.successors.size(); i++) { - next = - IntersectSorted(next, graph->blocks[block.successors[i]].post_dominators); + next = IntersectSorted(next, graph.blocks[block.successors[i]].post_dominators); } - AddUnique(&next, block.id); - SortUnique(&next); + AddUnique(next, block.id); + SortUnique(next); } if (next != block.post_dominators) { block.post_dominators = std::move(next); @@ -630,12 +609,12 @@ void ComputePostDominators(Graph* graph) { } } -void ComputeBackEdges(Graph* graph) { - graph->back_edges.clear(); - for (const auto& block: graph->blocks) { +void ComputeBackEdges(Graph& graph) { + graph.back_edges.clear(); + for (const auto& block: graph.blocks) { for (auto succ: block.successors) { - if (graph->Dominates(succ, block.id)) { - graph->back_edges.push_back({block.id, succ, true}); + if (graph.Dominates(succ, block.id)) { + graph.back_edges.push_back({block.id, succ, true}); } } } @@ -647,8 +626,8 @@ std::vector NaturalLoopBody(const Graph& graph, uint32_t header, uint3 std::vector stack; body.reserve(graph.blocks.size()); stack.reserve(graph.blocks.size()); - AddUnique(&body, header); - AddUnique(&body, latch); + AddUnique(body, header); + AddUnique(body, latch); if (latch != header) { stack.push_back(latch); } @@ -675,15 +654,15 @@ std::vector NaturalLoopBody(const Graph& graph, uint32_t header, uint3 } } } - SortUnique(&body); + SortUnique(body); return body; } -void ComputeNaturalLoops(Graph* graph) { - graph->natural_loops.clear(); - for (auto& edge: graph->back_edges) { +void ComputeNaturalLoops(Graph& graph) { + graph.natural_loops.clear(); + for (auto& edge: graph.back_edges) { bool natural = true; - auto body = NaturalLoopBody(*graph, edge.to, edge.from, &natural); + auto body = NaturalLoopBody(graph, edge.to, edge.from, &natural); edge.natural = natural; NaturalLoop loop; @@ -693,26 +672,26 @@ void ComputeNaturalLoops(Graph* graph) { loop.body_blocks = body; for (auto block_id: body) { - const auto* block = graph->FindBlock(block_id); + const auto* block = graph.FindBlock(block_id); if (block == nullptr) { continue; } for (auto succ: block->successors) { if (!Contains(body, succ)) { - AddUnique(&loop.exit_blocks, succ); + AddUnique(loop.exit_blocks, succ); } } } - SortUnique(&loop.exit_blocks); + SortUnique(loop.exit_blocks); if (!loop.exit_blocks.empty()) { uint32_t merge = loop.exit_blocks.front(); for (uint32_t i = 1; i < loop.exit_blocks.size(); i++) { - merge = graph->FindNearestCommonPostDominator(merge, loop.exit_blocks[i]); + merge = graph.FindNearestCommonPostDominator(merge, loop.exit_blocks[i]); } loop.merge = merge; } - graph->natural_loops.push_back(std::move(loop)); + graph.natural_loops.push_back(std::move(loop)); } } @@ -726,90 +705,90 @@ struct TarjanState { std::vector components; }; -void TarjanVisit(TarjanState* state, uint32_t block_id) { - state->index[block_id] = state->next_index; - state->lowlink[block_id] = state->next_index; - state->next_index++; - state->stack.push_back(block_id); - state->on_stack[block_id] = true; +void TarjanVisit(TarjanState& state, uint32_t block_id) { + state.index[block_id] = state.next_index; + state.lowlink[block_id] = state.next_index; + state.next_index++; + state.stack.push_back(block_id); + state.on_stack[block_id] = true; - const auto* block = state->graph->FindBlock(block_id); + const auto* block = state.graph->FindBlock(block_id); if (block != nullptr) { for (auto succ: block->successors) { - if (state->index[succ] == UINT32_MAX) { + if (state.index[succ] == UINT32_MAX) { TarjanVisit(state, succ); - state->lowlink[block_id] = std::min(state->lowlink[block_id], state->lowlink[succ]); - } else if (state->on_stack[succ]) { - state->lowlink[block_id] = std::min(state->lowlink[block_id], state->index[succ]); + state.lowlink[block_id] = std::min(state.lowlink[block_id], state.lowlink[succ]); + } else if (state.on_stack[succ]) { + state.lowlink[block_id] = std::min(state.lowlink[block_id], state.index[succ]); } } } - if (state->lowlink[block_id] != state->index[block_id]) { + if (state.lowlink[block_id] != state.index[block_id]) { return; } StronglyConnectedComponent component; for (;;) { - const auto member = state->stack.back(); - state->stack.pop_back(); - state->on_stack[member] = false; + const auto member = state.stack.back(); + state.stack.pop_back(); + state.on_stack[member] = false; component.blocks.push_back(member); if (member == block_id) { break; } } - SortUnique(&component.blocks); + SortUnique(component.blocks); bool cyclic = component.blocks.size() > 1u; for (auto member: component.blocks) { - const auto* member_block = state->graph->FindBlock(member); + const auto* member_block = state.graph->FindBlock(member); if (member_block != nullptr && Contains(member_block->successors, member)) { cyclic = true; } if (member_block != nullptr) { for (auto pred: member_block->predecessors) { if (!Contains(component.blocks, pred)) { - AddUnique(&component.entry_blocks, member); + AddUnique(component.entry_blocks, member); } } } } - SortUnique(&component.entry_blocks); + SortUnique(component.entry_blocks); component.irreducible = cyclic && component.entry_blocks.size() > 1u; - state->components.push_back(std::move(component)); + state.components.push_back(std::move(component)); } -void ComputeComponents(Graph* graph) { +void ComputeComponents(Graph& graph) { TarjanState state; - state.graph = graph; - state.index.assign(graph->blocks.size(), UINT32_MAX); - state.lowlink.assign(graph->blocks.size(), UINT32_MAX); - state.on_stack.assign(graph->blocks.size(), false); - state.stack.reserve(graph->blocks.size()); - state.components.reserve(graph->blocks.size()); + state.graph = &graph; + state.index.assign(graph.blocks.size(), UINT32_MAX); + state.lowlink.assign(graph.blocks.size(), UINT32_MAX); + state.on_stack.assign(graph.blocks.size(), false); + state.stack.reserve(graph.blocks.size()); + state.components.reserve(graph.blocks.size()); - for (const auto& block: graph->blocks) { + for (const auto& block: graph.blocks) { if (state.index[block.id] == UINT32_MAX) { - TarjanVisit(&state, block.id); + TarjanVisit(state, block.id); } } - graph->components = std::move(state.components); - graph->irreducible = false; - for (const auto& component: graph->components) { + graph.components = std::move(state.components); + graph.irreducible = false; + for (const auto& component: graph.components) { if (component.irreducible) { - graph->irreducible = true; - graph->failure_kind = FailureKind::IrreducibleControlFlow; - graph->failure_block = component.entry_blocks.empty() ? component.blocks.front() - : component.entry_blocks.front(); - graph->unsupported_reason = "irreducible CFG: cyclic component has multiple entries"; + graph.irreducible = true; + graph.failure_kind = FailureKind::IrreducibleControlFlow; + graph.failure_block = component.entry_blocks.empty() ? component.blocks.front() + : component.entry_blocks.front(); + graph.unsupported_reason = "irreducible CFG: cyclic component has multiple entries"; break; } } } -void RecomputeAnalyses(Graph* graph) { +void RecomputeAnalyses(Graph& graph) { ComputeDominators(graph); ComputePostDominators(graph); ComputeBackEdges(graph); @@ -817,15 +796,15 @@ void RecomputeAnalyses(Graph* graph) { ComputeComponents(graph); } -uint32_t MoveBlockBefore(Graph* graph, uint32_t block_id, uint32_t before_id) { - if (block_id == before_id || block_id >= graph->blocks.size() || - before_id >= graph->blocks.size()) { +uint32_t MoveBlockBefore(Graph& graph, uint32_t block_id, uint32_t before_id) { + if (block_id == before_id || block_id >= graph.blocks.size() || + before_id >= graph.blocks.size()) { return block_id; } const auto block_pos = block_id; const auto before_pos = before_id; - std::vector old_blocks = std::move(graph->blocks); + std::vector old_blocks = std::move(graph.blocks); std::vector new_blocks; new_blocks.reserve(old_blocks.size()); @@ -843,14 +822,14 @@ uint32_t MoveBlockBefore(Graph* graph, uint32_t block_id, uint32_t before_id) { id_map[new_blocks[i].id] = i; } - graph->blocks = std::move(new_blocks); - graph->entry_block = RemapId(graph->entry_block, id_map); - for (auto& block: graph->blocks) { + graph.blocks = std::move(new_blocks); + graph.entry_block = RemapId(graph.entry_block, id_map); + for (auto& block: graph.blocks) { block.id = RemapId(block.id, id_map); - RemapIds(&block.predecessors, id_map); - RemapIds(&block.successors, id_map); - RemapIds(&block.dominators, id_map); - RemapIds(&block.post_dominators, id_map); + RemapIds(block.predecessors, id_map); + RemapIds(block.successors, id_map); + RemapIds(block.dominators, id_map); + RemapIds(block.post_dominators, id_map); block.terminator.true_block = RemapId(block.terminator.true_block, id_map); block.terminator.false_block = RemapId(block.terminator.false_block, id_map); block.terminator.merge_block = RemapId(block.terminator.merge_block, id_map); @@ -880,7 +859,7 @@ std::vector DominatedBlocks(const Graph& graph, uint32_t header, continue; } - AddUnique(&blocks, block_id); + AddUnique(blocks, block_id); for (auto succ: block->successors) { if (succ != stop_block && graph.Dominates(header, succ)) { stack.push_back(succ); @@ -888,15 +867,15 @@ std::vector DominatedBlocks(const Graph& graph, uint32_t header, } } - SortUnique(&blocks); + SortUnique(blocks); return blocks; } -uint32_t AppendSyntheticMergeBlock(Graph* graph, uint32_t old_merge) { - const auto* merge = graph->FindBlock(old_merge); +uint32_t AppendSyntheticMergeBlock(Graph& graph, uint32_t old_merge) { + const auto* merge = graph.FindBlock(old_merge); BasicBlock block; - block.id = static_cast(graph->blocks.size()); + block.id = static_cast(graph.blocks.size()); block.start_pc = merge != nullptr ? merge->start_pc : 0u; block.end_pc = block.start_pc; block.inst_begin = merge != nullptr ? merge->inst_begin : 0u; @@ -905,8 +884,8 @@ uint32_t AppendSyntheticMergeBlock(Graph* graph, uint32_t old_merge) { block.terminator.kind = TerminatorKind::Branch; block.terminator.condition = BranchCondition::Always; block.terminator.true_block = old_merge; - graph->blocks.push_back(std::move(block)); - return graph->blocks.back().id; + graph.blocks.push_back(std::move(block)); + return graph.blocks.back().id; } bool IsSyntheticMergeForwarder(const Graph& graph, uint32_t block_id, uint32_t merge) { @@ -934,15 +913,14 @@ bool SelectionMergeLeavesContainingLoop(const Graph& graph, uint32_t header, uin return false; } -bool SplitSharedMergeBlock(Graph* graph, uint32_t merge, +bool SplitSharedMergeBlock(Graph& graph, uint32_t merge, const std::vector& construct_blocks, bool force_split = false) { - if (graph == nullptr || merge == UINT32_MAX || merge >= graph->blocks.size() || - Contains(construct_blocks, merge)) { + if (merge == UINT32_MAX || merge >= graph.blocks.size() || Contains(construct_blocks, merge)) { return false; } - const auto* merge_block = graph->FindBlock(merge); + const auto* merge_block = graph.FindBlock(merge); if (merge_block == nullptr) { return false; } @@ -951,9 +929,9 @@ bool SplitSharedMergeBlock(Graph* graph, uint32_t merge, std::vector external_predecessors; for (auto pred: merge_block->predecessors) { if (Contains(construct_blocks, pred)) { - AddUnique(&construct_predecessors, pred); + AddUnique(construct_predecessors, pred); } else { - AddUnique(&external_predecessors, pred); + AddUnique(external_predecessors, pred); } } @@ -962,8 +940,8 @@ bool SplitSharedMergeBlock(Graph* graph, uint32_t merge, } std::vector predecessors_to_split; for (auto pred: construct_predecessors) { - if (!IsSyntheticMergeForwarder(*graph, pred, merge)) { - AddUnique(&predecessors_to_split, pred); + if (!IsSyntheticMergeForwarder(graph, pred, merge)) { + AddUnique(predecessors_to_split, pred); } } if (predecessors_to_split.empty()) { @@ -971,36 +949,36 @@ bool SplitSharedMergeBlock(Graph* graph, uint32_t merge, } const auto synthetic_merge = AppendSyntheticMergeBlock(graph, merge); - auto* synthetic_block = graph->FindBlock(synthetic_merge); + auto* synthetic_block = graph.FindBlock(synthetic_merge); if (synthetic_block != nullptr) { synthetic_block->predecessors = predecessors_to_split; - SortUnique(&synthetic_block->predecessors); + SortUnique(synthetic_block->predecessors); } for (auto pred: predecessors_to_split) { - auto* block = graph->FindBlock(pred); + auto* block = graph.FindBlock(pred); if (block == nullptr) { continue; } - ReplaceValue(&block->successors, merge, synthetic_merge); - ReplaceTerminatorTarget(&block->terminator, merge, synthetic_merge); + ReplaceValue(block->successors, merge, synthetic_merge); + ReplaceTerminatorTarget(block->terminator, merge, synthetic_merge); } - auto* old_merge = graph->FindBlock(merge); + auto* old_merge = graph.FindBlock(merge); if (old_merge != nullptr) { for (auto pred: predecessors_to_split) { - RemoveValue(&old_merge->predecessors, pred); + RemoveValue(old_merge->predecessors, pred); } - AddUnique(&old_merge->predecessors, synthetic_merge); - SortUnique(&old_merge->predecessors); + AddUnique(old_merge->predecessors, synthetic_merge); + SortUnique(old_merge->predecessors); } MoveBlockBefore(graph, synthetic_merge, merge); return true; } -bool SplitOneLoopMerge(Graph* graph) { - const auto& loops = graph->natural_loops; +bool SplitOneLoopMerge(Graph& graph) { + const auto& loops = graph.natural_loops; for (const auto& loop: loops) { if (SplitSharedMergeBlock(graph, loop.merge, loop.body_blocks)) { return true; @@ -1009,25 +987,25 @@ bool SplitOneLoopMerge(Graph* graph) { return false; } -bool SplitOneSelectionMerge(Graph* graph) { +bool SplitOneSelectionMerge(Graph& graph) { std::vector loop_headers; - loop_headers.reserve(graph->natural_loops.size()); - for (const auto& loop: graph->natural_loops) { - AddUnique(&loop_headers, loop.header); + loop_headers.reserve(graph.natural_loops.size()); + for (const auto& loop: graph.natural_loops) { + AddUnique(loop_headers, loop.header); } - const auto original_block_count = static_cast(graph->blocks.size()); + const auto original_block_count = static_cast(graph.blocks.size()); for (uint32_t block_id = 0; block_id < original_block_count; block_id++) { - const auto* block = graph->FindBlock(block_id); + const auto* block = graph.FindBlock(block_id); if (block == nullptr || block->terminator.kind != TerminatorKind::ConditionalBranch || Contains(loop_headers, block_id)) { continue; } - const auto merge = graph->FindNearestCommonPostDominator(block->terminator.true_block, - block->terminator.false_block); - const auto construct_blocks = DominatedBlocks(*graph, block_id, merge); - const auto force_split = SelectionMergeLeavesContainingLoop(*graph, block_id, merge); + const auto merge = graph.FindNearestCommonPostDominator(block->terminator.true_block, + block->terminator.false_block); + const auto construct_blocks = DominatedBlocks(graph, block_id, merge); + const auto force_split = SelectionMergeLeavesContainingLoop(graph, block_id, merge); if (SplitSharedMergeBlock(graph, merge, construct_blocks, force_split)) { return true; } @@ -1035,8 +1013,8 @@ bool SplitOneSelectionMerge(Graph* graph) { return false; } -bool SplitSharedMergeBlocks(Graph* graph, std::string* error) { - const auto original_block_count = static_cast(graph->blocks.size()); +bool SplitSharedMergeBlocks(Graph& graph, std::string* error) { + const auto original_block_count = static_cast(graph.blocks.size()); const auto split_budget = std::max(16u, std::min(128u, original_block_count)); for (uint32_t splits = 0; splits < split_budget; splits++) { @@ -1046,17 +1024,17 @@ bool SplitSharedMergeBlocks(Graph* graph, std::string* error) { RebuildPredecessors(graph); RecomputeAnalyses(graph); } - SetFailure(graph, FailureKind::StructuredControlFlow, graph->entry_block, + SetFailure(graph, FailureKind::StructuredControlFlow, graph.entry_block, fmt::format("CFG shared merge splitting exceeded budget: original_blocks={} " "current_blocks={} split_budget={}", - original_block_count, static_cast(graph->blocks.size()), + original_block_count, static_cast(graph.blocks.size()), split_budget), error); return false; } -void ClearStructuredTerminators(Graph* graph) { - for (auto& block: graph->blocks) { +void ClearStructuredTerminators(Graph& graph) { + for (auto& block: graph.blocks) { block.terminator.merge_block = UINT32_MAX; block.terminator.continue_block = UINT32_MAX; block.terminator.loop_header = false; @@ -1138,12 +1116,8 @@ uint32_t Graph::FindNearestCommonPostDominator(uint32_t block_a, uint32_t block_ return common.empty() ? UINT32_MAX : common.front(); } -bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* error) { - if (graph == nullptr) { - SetError(error, "invalid CFG output"); - return false; - } - *graph = {}; +bool BuildGraph(const Decoder::Program& program, Graph& graph, std::string* error) { + graph = {}; if (program.instructions.empty()) { SetError(error, "cannot build CFG for empty shader"); @@ -1188,7 +1162,7 @@ bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* erro } } else if (inst.opcode == Opcode::SSetpcB64) { SetpcTargetInfo target_info; - if (!ResolveSetpcTargets(program, i, &target_info)) { + if (!ResolveSetpcTargets(program, i, target_info)) { SetFailure(graph, FailureKind::InvalidBranchTarget, UINT32_MAX, fmt::format("unsupported dynamic S_SETPC_B64 at pc 0x{:08x}", inst.pc), error); @@ -1232,7 +1206,7 @@ bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* erro } BasicBlock block; - block.id = static_cast(graph->blocks.size()); + block.id = static_cast(graph.blocks.size()); block.start_pc = start; block.end_pc = i + 1u < sorted_labels.size() ? sorted_labels[i + 1u] : end_pc; block.inst_begin = static_cast( @@ -1243,17 +1217,17 @@ bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* erro std::lower_bound(program.instructions.begin(), program.instructions.end(), block.end_pc, [](const Instruction& inst, uint32_t pc) { return inst.pc < pc; }) - program.instructions.begin()); - graph->blocks.push_back(std::move(block)); + graph.blocks.push_back(std::move(block)); } - graph->entry_block = 0; + graph.entry_block = 0; std::map pc_to_block; - for (const auto& block: graph->blocks) { + for (const auto& block: graph.blocks) { pc_to_block.emplace(block.start_pc, block.id); } - for (auto& block: graph->blocks) { + for (auto& block: graph.blocks) { block.terminator = {}; if (block.inst_begin == block.inst_end) { block.terminator.kind = TerminatorKind::Return; @@ -1286,7 +1260,7 @@ bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* erro pc_to_block.at(target_info.selector_target_pcs[i])); } if (target_info.table_load_pc != UINT32_MAX) { - AddUnique(&graph->code_table_load_pcs, target_info.table_load_pc); + AddUnique(graph.code_table_load_pcs, target_info.table_load_pc); } } else { block.terminator.kind = TerminatorKind::Branch; @@ -1323,15 +1297,15 @@ bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* erro switch (block.terminator.kind) { case TerminatorKind::Branch: - AddUnique(&block.successors, block.terminator.true_block); + AddUnique(block.successors, block.terminator.true_block); break; case TerminatorKind::ConditionalBranch: - AddUnique(&block.successors, block.terminator.true_block); - AddUnique(&block.successors, block.terminator.false_block); + AddUnique(block.successors, block.terminator.true_block); + AddUnique(block.successors, block.terminator.false_block); break; case TerminatorKind::IndirectBranch: for (const auto target: block.terminator.indirect_targets) { - AddUnique(&block.successors, target); + AddUnique(block.successors, target); } break; case TerminatorKind::Return: @@ -1339,16 +1313,16 @@ bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* erro } } - for (auto& block: graph->blocks) { - SortUnique(&block.successors); + for (auto& block: graph.blocks) { + SortUnique(block.successors); for (auto succ: block.successors) { - AddUnique(&graph->blocks[succ].predecessors, block.id); + AddUnique(graph.blocks[succ].predecessors, block.id); } } - for (auto& block: graph->blocks) { - SortUnique(&block.predecessors); + for (auto& block: graph.blocks) { + SortUnique(block.predecessors); } - SortUnique(&graph->code_table_load_pcs); + SortUnique(graph.code_table_load_pcs); ComputeDominators(graph); ComputePostDominators(graph); @@ -1357,29 +1331,25 @@ bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* erro ComputeComponents(graph); if (indirect_setpc) { - graph->irreducible = true; - graph->unsupported = false; - graph->failure_kind = FailureKind::IrreducibleControlFlow; - graph->unsupported_reason = "indirect S_SETPC_B64 jump table requires dispatcher fallback"; + graph.irreducible = true; + graph.unsupported = false; + graph.failure_kind = FailureKind::IrreducibleControlFlow; + graph.unsupported_reason = "indirect S_SETPC_B64 jump table requires dispatcher fallback"; } - if (graph->irreducible) { - graph->unsupported = false; + if (graph.irreducible) { + graph.unsupported = false; } return true; } -bool Structurize(Graph* graph, std::string* error) { - if (graph == nullptr) { - SetError(error, "invalid CFG input"); - return false; - } - if (graph->unsupported || graph->irreducible) { - if (graph->unsupported_reason.empty()) { - graph->unsupported_reason = "unsupported CFG"; +bool Structurize(Graph& graph, std::string* error) { + if (graph.unsupported || graph.irreducible) { + if (graph.unsupported_reason.empty()) { + graph.unsupported_reason = "unsupported CFG"; } - SetError(error, graph->unsupported_reason); + SetError(error, graph.unsupported_reason); return false; } @@ -1403,8 +1373,8 @@ bool Structurize(Graph* graph, std::string* error) { return true; }; - for (const auto& loop: graph->natural_loops) { - auto* header = graph->FindBlock(loop.header); + for (const auto& loop: graph.natural_loops) { + auto* header = graph.FindBlock(loop.header); if (header == nullptr || loop.merge == UINT32_MAX || loop.continue_block == UINT32_MAX) { SetFailure( graph, FailureKind::StructuredControlFlow, loop.header, @@ -1420,14 +1390,14 @@ bool Structurize(Graph* graph, std::string* error) { header->terminator.continue_block = loop.continue_block; } - for (auto& block: graph->blocks) { + for (auto& block: graph.blocks) { if (block.terminator.kind != TerminatorKind::ConditionalBranch || block.terminator.loop_header) { continue; } - const auto merge = graph->FindNearestCommonPostDominator(block.terminator.true_block, - block.terminator.false_block); + const auto merge = graph.FindNearestCommonPostDominator(block.terminator.true_block, + block.terminator.false_block); if (merge == UINT32_MAX) { SetFailure(graph, FailureKind::StructuredControlFlow, block.id, fmt::format("conditional block {} has no structured merge", block.id), diff --git a/src/graphics/shader/recompiler/ShaderCFG.h b/src/graphics/shader/recompiler/ShaderCFG.h index 43659297d..52a02cc07 100644 --- a/src/graphics/shader/recompiler/ShaderCFG.h +++ b/src/graphics/shader/recompiler/ShaderCFG.h @@ -105,8 +105,8 @@ struct Graph { uint32_t FindNearestCommonPostDominator(uint32_t block_a, uint32_t block_b) const; }; -bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* error); -bool Structurize(Graph* graph, std::string* error); +bool BuildGraph(const Decoder::Program& program, Graph& graph, std::string* error); +bool Structurize(Graph& graph, std::string* error); std::string BranchConditionToString(BranchCondition condition); std::string FailureKindToString(FailureKind kind); std::string FormatBlockDiagnostic(const Graph& graph, uint32_t block_id, const char* stage, diff --git a/src/graphics/shader/recompiler/ShaderDecoder.cpp b/src/graphics/shader/recompiler/ShaderDecoder.cpp index 4b1e4003d..76b302ce0 100644 --- a/src/graphics/shader/recompiler/ShaderDecoder.cpp +++ b/src/graphics/shader/recompiler/ShaderDecoder.cpp @@ -44,10 +44,10 @@ bool IsControlFlowBranch(Opcode opcode) { } } -void ApplyLiteral(Operand* operand, uint32_t literal) { - if (operand->kind == OperandKind::LiteralConstant) { - operand->value = literal; - operand->signed_val = static_cast(literal); +void ApplyLiteral(Operand& operand, uint32_t literal) { + if (operand.kind == OperandKind::LiteralConstant) { + operand.value = literal; + operand.signed_val = static_cast(literal); } } @@ -196,36 +196,31 @@ std::string FormatExp(const Instruction& inst) { } // namespace -bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::string* error) { - if (operand == nullptr) { - SetError(error, "internal decoder error: null source operand"); - return false; - } - - *operand = {}; +bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error) { + operand = {}; if (code <= 105u) { - operand->kind = OperandKind::Sgpr; - operand->reg = code; + operand.kind = OperandKind::Sgpr; + operand.reg = code; return true; } if (code >= 128u && code <= 192u) { - operand->kind = OperandKind::IntegerInlineConstant; - operand->signed_val = static_cast(code - 128u); - operand->value = static_cast(operand->signed_val); + operand.kind = OperandKind::IntegerInlineConstant; + operand.signed_val = static_cast(code - 128u); + operand.value = static_cast(operand.signed_val); return true; } if (code >= 193u && code <= 208u) { - operand->kind = OperandKind::IntegerInlineConstant; - operand->signed_val = 192 - static_cast(code); - operand->value = static_cast(operand->signed_val); + operand.kind = OperandKind::IntegerInlineConstant; + operand.signed_val = 192 - static_cast(code); + operand.value = static_cast(operand.signed_val); return true; } if (code >= 240u && code <= 247u) { constexpr float values[] = {0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f, 4.0f, -4.0f}; - operand->kind = OperandKind::FloatInlineConstant; - operand->float_val = values[code - 240u]; - operand->value = FloatBits(operand->float_val); + operand.kind = OperandKind::FloatInlineConstant; + operand.float_val = values[code - 240u]; + operand.value = FloatBits(operand.float_val); return true; } if (code >= 256u && code <= 511u) { @@ -233,22 +228,22 @@ bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::strin } switch (code) { - case 106u: operand->kind = OperandKind::VccLo; return true; - case 107u: operand->kind = OperandKind::VccHi; return true; - case 124u: operand->kind = OperandKind::M0; return true; - case 125u: operand->kind = OperandKind::Null; return true; - case 126u: operand->kind = OperandKind::ExecLo; return true; - case 127u: operand->kind = OperandKind::ExecHi; return true; - case 239u: operand->kind = OperandKind::PopsExitingWaveId; return true; + case 106u: operand.kind = OperandKind::VccLo; return true; + case 107u: operand.kind = OperandKind::VccHi; return true; + case 124u: operand.kind = OperandKind::M0; return true; + case 125u: operand.kind = OperandKind::Null; return true; + case 126u: operand.kind = OperandKind::ExecLo; return true; + case 127u: operand.kind = OperandKind::ExecHi; return true; + case 239u: operand.kind = OperandKind::PopsExitingWaveId; return true; case 248u: - operand->kind = OperandKind::FloatInlineConstant; - operand->float_val = 0.15915494309189535f; - operand->value = FloatBits(operand->float_val); + operand.kind = OperandKind::FloatInlineConstant; + operand.float_val = 0.15915494309189535f; + operand.value = FloatBits(operand.float_val); return true; - case 251u: operand->kind = OperandKind::VccZ; return true; - case 252u: operand->kind = OperandKind::ExecZ; return true; - case 253u: operand->kind = OperandKind::Scc; return true; - case 255u: operand->kind = OperandKind::LiteralConstant; return true; + case 251u: operand.kind = OperandKind::VccZ; return true; + case 252u: operand.kind = OperandKind::ExecZ; return true; + case 253u: operand.kind = OperandKind::Scc; return true; + case 255u: operand.kind = OperandKind::LiteralConstant; return true; default: if (error != nullptr) { *error = fmt::format("unsupported scalar source operand 0x{:08x} at pc 0x{:08x}", @@ -258,27 +253,22 @@ bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::strin } } -bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand* operand, std::string* error) { - if (operand == nullptr) { - SetError(error, "internal decoder error: null destination operand"); - return false; - } - - *operand = {}; +bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error) { + operand = {}; if (code <= 105u) { - operand->kind = OperandKind::Sgpr; - operand->reg = code; + operand.kind = OperandKind::Sgpr; + operand.reg = code; return true; } switch (code) { - case 106u: operand->kind = OperandKind::VccLo; return true; - case 107u: operand->kind = OperandKind::VccHi; return true; - case 124u: operand->kind = OperandKind::M0; return true; - case 125u: operand->kind = OperandKind::Null; return true; - case 126u: operand->kind = OperandKind::ExecLo; return true; - case 127u: operand->kind = OperandKind::ExecHi; return true; + case 106u: operand.kind = OperandKind::VccLo; return true; + case 107u: operand.kind = OperandKind::VccHi; return true; + case 124u: operand.kind = OperandKind::M0; return true; + case 125u: operand.kind = OperandKind::Null; return true; + case 126u: operand.kind = OperandKind::ExecLo; return true; + case 127u: operand.kind = OperandKind::ExecHi; return true; default: if (error != nullptr) { *error = fmt::format( @@ -288,67 +278,63 @@ bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand* operand, std:: } } -bool DecodeVectorGpr(uint32_t reg, Operand* operand, std::string* error) { - if (operand == nullptr) { - SetError(error, "internal decoder error: null VGPR operand"); - return false; - } +bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error) { if (reg > 255u) { SetError(error, "VGPR index is out of range"); return false; } - *operand = {}; - operand->kind = OperandKind::Vgpr; - operand->reg = reg; + operand = {}; + operand.kind = OperandKind::Vgpr; + operand.reg = reg; return true; } -bool ReadLiteralOperands(std::span code, uint32_t word_index, Instruction* inst, +bool ReadLiteralOperands(std::span code, uint32_t word_index, Instruction& inst, std::string* error) { - if (!HasLiteral(*inst)) { + if (!HasLiteral(inst)) { return true; } - if (word_index + inst->word_count >= code.size()) { + if (word_index + inst.word_count >= code.size()) { if (error != nullptr) { - *error = fmt::format("missing literal constant at pc 0x{:08x}", inst->pc); + *error = fmt::format("missing literal constant at pc 0x{:08x}", inst.pc); } return false; } - const auto literal = code[word_index + inst->word_count]; - ApplyLiteral(&inst->src0, literal); - ApplyLiteral(&inst->src1, literal); - ApplyLiteral(&inst->src2, literal); - ApplyLiteral(&inst->src3, literal); - inst->word_count++; - SetRawWords(inst, code, word_index, inst->word_count); + const auto literal = code[word_index + inst.word_count]; + ApplyLiteral(inst.src0, literal); + ApplyLiteral(inst.src1, literal); + ApplyLiteral(inst.src2, literal); + ApplyLiteral(inst.src3, literal); + inst.word_count++; + SetRawWords(inst, code, word_index, inst.word_count); return true; } -void SetRawWords(Instruction* inst, std::span code, uint32_t word_index, +void SetRawWords(Instruction& inst, std::span code, uint32_t word_index, uint32_t word_count) { - inst->word_count = word_count; - inst->raw_count = std::min(word_count, MaxInstructionRawWords); - for (uint32_t i = 0; i < inst->raw_count; i++) { - inst->raw[i] = code[word_index + i]; + inst.word_count = word_count; + inst.raw_count = std::min(word_count, MaxInstructionRawWords); + for (uint32_t i = 0; i < inst.raw_count; i++) { + inst.raw[i] = code[word_index + i]; } } -void SetUnsupported(Instruction* inst, Family family, uint32_t opcode_id, const char* reason) { - inst->opcode = Opcode::Unsupported; - inst->family = family; - inst->opcode_id = opcode_id; - inst->unsupported_reason = reason; +void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const char* reason) { + inst.opcode = Opcode::Unsupported; + inst.family = family; + inst.opcode_id = opcode_id; + inst.unsupported_reason = reason; } -bool DecodeProgram(std::span code, Program* program, std::string* error) { - if (code.empty() || code.size() > UINT32_MAX / sizeof(uint32_t) || program == nullptr) { +bool DecodeProgram(std::span code, Program& program, std::string* error) { + if (code.empty() || code.size() > UINT32_MAX / sizeof(uint32_t)) { SetError(error, "invalid shader decoder input"); return false; } - program->instructions.clear(); - program->code = code; + program.instructions.clear(); + program.code = code; std::set branch_targets; for (uint32_t word_index = 0; word_index < code.size();) { @@ -358,30 +344,30 @@ bool DecodeProgram(std::span code, Program* program, std::string Instruction inst; bool ok = false; if ((word & 0x80000000u) == 0u) { - ok = DecodeVop2(pc, code, word_index, &inst, error); + ok = DecodeVop2(pc, code, word_index, inst, error); } else if ((word & 0xc0000000u) == 0x80000000u) { const auto opcode = (word >> 23u) & 0x7fu; switch (opcode) { - case 0x7du: ok = DecodeSop1(pc, code, word_index, &inst, error); break; - case 0x7eu: ok = DecodeSopc(pc, code, word_index, &inst, error); break; - case 0x7fu: ok = DecodeSopp(pc, code, word_index, &inst, error); break; + case 0x7du: ok = DecodeSop1(pc, code, word_index, inst, error); break; + case 0x7eu: ok = DecodeSopc(pc, code, word_index, inst, error); break; + case 0x7fu: ok = DecodeSopp(pc, code, word_index, inst, error); break; default: - ok = opcode >= 0x60u ? DecodeSopk(pc, code, word_index, &inst, error) - : DecodeSop2(pc, code, word_index, &inst, error); + ok = opcode >= 0x60u ? DecodeSopk(pc, code, word_index, inst, error) + : DecodeSop2(pc, code, word_index, inst, error); break; } } else { switch (word >> 26u) { - case 0x32u: ok = DecodeVintrp(pc, code, word_index, &inst, error); break; - case 0x33u: ok = DecodeVop3p(pc, code, word_index, &inst, error); break; - case 0x35u: ok = DecodeVop3(pc, code, word_index, &inst, error); break; - case 0x36u: ok = DecodeDs(pc, code, word_index, &inst, error); break; - case 0x37u: ok = DecodeFlat(pc, code, word_index, &inst, error); break; - case 0x38u: ok = DecodeMubuf(pc, code, word_index, &inst, error); break; - case 0x3au: ok = DecodeMtbuf(pc, code, word_index, &inst, error); break; - case 0x3cu: ok = DecodeMimg(pc, code, word_index, &inst, error); break; - case 0x3du: ok = DecodeSmem(pc, code, word_index, &inst, error); break; - case 0x3eu: ok = DecodeExp(pc, code, word_index, &inst, error); break; + case 0x32u: ok = DecodeVintrp(pc, code, word_index, inst, error); break; + case 0x33u: ok = DecodeVop3p(pc, code, word_index, inst, error); break; + case 0x35u: ok = DecodeVop3(pc, code, word_index, inst, error); break; + case 0x36u: ok = DecodeDs(pc, code, word_index, inst, error); break; + case 0x37u: ok = DecodeFlat(pc, code, word_index, inst, error); break; + case 0x38u: ok = DecodeMubuf(pc, code, word_index, inst, error); break; + case 0x3au: ok = DecodeMtbuf(pc, code, word_index, inst, error); break; + case 0x3cu: ok = DecodeMimg(pc, code, word_index, inst, error); break; + case 0x3du: ok = DecodeSmem(pc, code, word_index, inst, error); break; + case 0x3eu: ok = DecodeExp(pc, code, word_index, inst, error); break; default: if (error != nullptr) { *error = fmt::format( @@ -396,7 +382,7 @@ bool DecodeProgram(std::span code, Program* program, std::string return false; } - program->instructions.push_back(inst); + program.instructions.push_back(inst); word_index += inst.word_count; if (IsControlFlowBranch(inst.opcode)) { diff --git a/src/graphics/shader/recompiler/ShaderDecoder.h b/src/graphics/shader/recompiler/ShaderDecoder.h index a726aeeba..c4a144f32 100644 --- a/src/graphics/shader/recompiler/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/ShaderDecoder.h @@ -656,16 +656,16 @@ struct Program { std::vector instructions; }; -bool DecodeProgram(std::span code, Program* program, std::string* error); +bool DecodeProgram(std::span code, Program& program, std::string* error); -bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::string* error); -bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand* operand, std::string* error); -bool DecodeVectorGpr(uint32_t reg, Operand* operand, std::string* error); -bool ReadLiteralOperands(std::span code, uint32_t word_index, Instruction* inst, +bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error); +bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error); +bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error); +bool ReadLiteralOperands(std::span code, uint32_t word_index, Instruction& inst, std::string* error); -void SetRawWords(Instruction* inst, std::span code, uint32_t word_index, +void SetRawWords(Instruction& inst, std::span code, uint32_t word_index, uint32_t word_count); -void SetUnsupported(Instruction* inst, Family family, uint32_t opcode_id, const char* reason); +void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const char* reason); std::string FamilyToString(Family family); std::string OpcodeToString(Opcode opcode); std::string OperandToString(const Operand& operand); diff --git a/src/graphics/shader/recompiler/ShaderIR.h b/src/graphics/shader/recompiler/ShaderIR.h index 49b0007da..417abf494 100644 --- a/src/graphics/shader/recompiler/ShaderIR.h +++ b/src/graphics/shader/recompiler/ShaderIR.h @@ -753,7 +753,7 @@ struct Program { }; bool LowerProgram(const Decoder::Program& decoded, const CFG::Graph& cfg, ShaderType stage, - uint32_t wave_size, Program* program, std::string* error); + uint32_t wave_size, Program& program, std::string* error); std::string RegisterToString(Register reg); std::string OperandToString(const Operand& operand); diff --git a/src/graphics/shader/recompiler/ShaderInfoCollection.cpp b/src/graphics/shader/recompiler/ShaderInfoCollection.cpp index 50aaaa7ba..6e89075ab 100644 --- a/src/graphics/shader/recompiler/ShaderInfoCollection.cpp +++ b/src/graphics/shader/recompiler/ShaderInfoCollection.cpp @@ -12,10 +12,10 @@ bool HasInput(const ShaderInfo& info, StageInputKind kind, uint32_t location) { }); } -void AddInput(ShaderInfo* info, StageInputKind kind, uint32_t location, uint32_t components, +void AddInput(ShaderInfo& info, StageInputKind kind, uint32_t location, uint32_t components, std::string name) { - if (!HasInput(*info, kind, location)) { - info->inputs.push_back({kind, location, components, std::move(name)}); + if (!HasInput(info, kind, location)) { + info.inputs.push_back({kind, location, components, std::move(name)}); } } @@ -25,10 +25,10 @@ bool HasOutput(const ShaderInfo& info, StageOutputKind kind, uint32_t index) { }); } -void AddOutput(ShaderInfo* info, StageOutputKind kind, uint32_t index, uint32_t location, +void AddOutput(ShaderInfo& info, StageOutputKind kind, uint32_t index, uint32_t location, std::string name) { - if (!HasOutput(*info, kind, index)) { - info->outputs.push_back({kind, index, location, std::move(name)}); + if (!HasOutput(info, kind, index)) { + info.outputs.push_back({kind, index, location, std::move(name)}); } } @@ -87,7 +87,7 @@ bool ValidateOptions(const Program& program, const ShaderInfoOptions& options, s } void CollectVertexInputs(const Program& program, const ShaderVertexInputInfo* vertex, - ShaderInfo* info) { + ShaderInfo& info) { AddInput(info, StageInputKind::VertexIndex, 0, 1, "gl_VertexIndex"); AddInput(info, StageInputKind::InstanceIndex, 0, 1, "gl_InstanceIndex"); if (vertex == nullptr) { @@ -114,7 +114,7 @@ void CollectVertexInputs(const Program& program, const ShaderVertexInputInfo* ve } } -void CollectPixelInputs(const ShaderPixelInputInfo* pixel, ShaderInfo* info) { +void CollectPixelInputs(const ShaderPixelInputInfo* pixel, ShaderInfo& info) { if (pixel == nullptr) { return; } @@ -130,7 +130,7 @@ void CollectPixelInputs(const ShaderPixelInputInfo* pixel, ShaderInfo* info) { } void CollectComputeInputs(const Program& program, const ShaderComputeInputInfo* compute, - ShaderInfo* info) { + ShaderInfo& info) { if (compute != nullptr) { if (compute->group_id[0] || compute->group_id[1] || compute->group_id[2]) { AddInput(info, StageInputKind::WorkgroupId, 0, 3, "gl_WorkGroupID"); @@ -150,7 +150,7 @@ void CollectComputeInputs(const Program& program, const ShaderComputeInputInfo* } } -void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, ShaderInfo* info) { +void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, ShaderInfo& info) { for (const auto& block: program.blocks) { for (const auto& inst: block.instructions) { if (inst.op != Opcode::Export) { @@ -193,32 +193,30 @@ void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, S } // namespace -bool CollectShaderInfo(Program* program, const ShaderInfoOptions& options, std::string* error) { - if (program == nullptr || !program->resource_tracking_complete || - program->shader_info_complete) { +bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::string* error) { + if (!program.resource_tracking_complete || program.shader_info_complete) { if (error != nullptr) { - *error = program == nullptr ? "invalid shader info program" - : !program->resource_tracking_complete ? "shader resources were not tracked" - : "shader info already collected"; + *error = !program.resource_tracking_complete ? "shader resources were not tracked" + : "shader info already collected"; } return false; } - if (!ValidateOptions(*program, options, error)) { + if (!ValidateOptions(program, options, error)) { return false; } - auto next = program->info; + auto next = program.info; next.inputs.clear(); next.outputs.clear(); - switch (program->stage) { - case ShaderType::Vertex: CollectVertexInputs(*program, options.vertex, &next); break; - case ShaderType::Pixel: CollectPixelInputs(options.pixel, &next); break; - case ShaderType::Compute: CollectComputeInputs(*program, options.compute, &next); break; + switch (program.stage) { + case ShaderType::Vertex: CollectVertexInputs(program, options.vertex, next); break; + case ShaderType::Pixel: CollectPixelInputs(options.pixel, next); break; + case ShaderType::Compute: CollectComputeInputs(program, options.compute, next); break; default: return false; } - CollectOutputs(*program, options.pixel, &next); - program->info = std::move(next); - program->shader_info_complete = true; + CollectOutputs(program, options.pixel, next); + program.info = std::move(next); + program.shader_info_complete = true; return true; } diff --git a/src/graphics/shader/recompiler/ShaderInfoCollection.h b/src/graphics/shader/recompiler/ShaderInfoCollection.h index 3694f135c..5bd03cfc0 100644 --- a/src/graphics/shader/recompiler/ShaderInfoCollection.h +++ b/src/graphics/shader/recompiler/ShaderInfoCollection.h @@ -13,7 +13,7 @@ struct ShaderInfoOptions { // Completes the immutable shader interface after resource tracking. On failure Program::info and // all completion state remain unchanged. -bool CollectShaderInfo(Program* program, const ShaderInfoOptions& options, std::string* error); +bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::IR diff --git a/src/graphics/shader/recompiler/ShaderRecompiler.cpp b/src/graphics/shader/recompiler/ShaderRecompiler.cpp index f73056936..5d0bd73c4 100644 --- a/src/graphics/shader/recompiler/ShaderRecompiler.cpp +++ b/src/graphics/shader/recompiler/ShaderRecompiler.cpp @@ -289,12 +289,11 @@ int BufferTableAttribFromOffset(uint32_t raw_offset, int dword) { return static_cast((raw_offset + static_cast(dword) * 4u) / 16u); } -void AppendUniquePcs(std::vector* dst, const std::vector& src) { - EXIT_IF(dst == nullptr); - dst->reserve(dst->size() + src.size()); +void AppendUniquePcs(std::vector& dst, const std::vector& src) { + dst.reserve(dst.size() + src.size()); for (auto pc: src) { - if (std::find(dst->begin(), dst->end(), pc) == dst->end()) { - dst->push_back(pc); + if (std::find(dst.begin(), dst.end(), pc) == dst.end()) { + dst.push_back(pc); } } } @@ -578,21 +577,21 @@ int ResolveEmbeddedFetchResource(const ShaderVertexInputInfo* input_info, return -1; } -uint32_t RewriteEmbeddedVertexFetches(IR::Program* ir, const ShaderVertexInputInfo* input_info, +uint32_t RewriteEmbeddedVertexFetches(IR::Program& ir, const ShaderVertexInputInfo* input_info, const std::vector& loads) { - if (ir == nullptr || input_info == nullptr || loads.empty()) { + if (input_info == nullptr || loads.empty()) { return 0; } std::vector prolog_pcs; prolog_pcs.reserve(loads.size()); for (const auto& load: loads) { - AppendUniquePcs(&prolog_pcs, load.prolog_loads); + AppendUniquePcs(prolog_pcs, load.prolog_loads); } auto* mutable_input_info = const_cast(input_info); uint32_t rewritten = 0; - for (auto& block: ir->blocks) { + for (auto& block: ir.blocks) { for (auto& inst: block.instructions) { if (IsIrFetchPrologLoad(inst) && EmbeddedFetchPcInList(prolog_pcs, inst.pc)) { auto pc = inst.pc; @@ -637,8 +636,8 @@ uint32_t RewriteEmbeddedVertexFetches(IR::Program* ir, const ShaderVertexInputIn } // namespace bool TryRecompile(std::span code, const CompileOptions& options, - CompileResult* result, std::string* error) { - if (code.empty() || result == nullptr) { + CompileResult& result, std::string* error) { + if (code.empty()) { if (error != nullptr) { *error = "invalid shader recompiler input"; } @@ -664,7 +663,7 @@ bool TryRecompile(std::span code, const CompileOptions& options, static_cast(code.size())); Decoder::Program decoded; - if (!Decoder::DecodeProgram(code, &decoded, error)) { + if (!Decoder::DecodeProgram(code, decoded, error)) { return false; } LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " decode instructions=%" PRIu64 @@ -683,7 +682,7 @@ bool TryRecompile(std::span code, const CompileOptions& options, CFG::Graph cfg; LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG BuildGraph\n", GetDumpLabel(options), StageName(options.stage), options.shader_hash); - if (!CFG::BuildGraph(decoded, &cfg, error)) { + if (!CFG::BuildGraph(decoded, cfg, error)) { return false; } LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " CFG BuildGraph blocks=%" PRIu64 @@ -703,7 +702,7 @@ bool TryRecompile(std::span code, const CompileOptions& options, const auto unstructured_cfg = cfg; LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG Structurize\n", GetDumpLabel(options), StageName(options.stage), options.shader_hash); - if (!CFG::Structurize(&cfg, &structure_error)) { + if (!CFG::Structurize(cfg, &structure_error)) { const auto diagnostic = FormatCfgFailure(cfg, options, structure_error); LOGF("%s structured CFG bug/failure: %s\n", GetDumpLabel(options), diagnostic.c_str()); dispatcher_fallback = true; @@ -729,7 +728,7 @@ bool TryRecompile(std::span code, const CompileOptions& options, IR::Program ir; LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " IR LowerProgram\n", GetDumpLabel(options), StageName(options.stage), options.shader_hash); - if (!IR::LowerProgram(decoded, cfg, options.stage, options.wave_size, &ir, error)) { + if (!IR::LowerProgram(decoded, cfg, options.stage, options.wave_size, ir, error)) { return false; } ir.lane_mask_mode = options.lane_mask_mode; @@ -747,18 +746,18 @@ bool TryRecompile(std::span code, const CompileOptions& options, DetectEmbeddedVertexFetch(decoded, options.vertex_input_info, ir.user_data_base, ir.user_data_count, options.wave_size); auto rewritten = - RewriteEmbeddedVertexFetches(&ir, options.vertex_input_info, embedded_fetch.loads); + RewriteEmbeddedVertexFetches(ir, options.vertex_input_info, embedded_fetch.loads); if (rewritten > 0 || !embedded_fetch.loads.empty()) { LOGF("%s embedded vertex fetch rewrite: detected=%" PRIu64 " rewritten=%" PRIu32 "\n", GetDumpLabel(options), static_cast(embedded_fetch.loads.size()), rewritten); } } - if (!IR::BuildScalarProvenance(&ir, error)) { + if (!IR::BuildScalarProvenance(ir, error)) { return false; } std::string srt_error; - if (!IR::BuildSrtPlan(&ir, &srt_error)) { + if (!IR::BuildSrtPlan(ir, &srt_error)) { LOGF("%s SRT planning failed: %s\n", GetDumpLabel(options), srt_error.c_str()); if (error != nullptr) { *error = std::move(srt_error); @@ -770,7 +769,7 @@ bool TryRecompile(std::span code, const CompileOptions& options, ir.fallback_reason = dispatcher_reason; } - if (!IR::PatchSrtReads(&ir, error) || !IR::TrackResources(&ir, error)) { + if (!IR::PatchSrtReads(ir, error) || !IR::TrackResources(ir, error)) { return false; } if (options.stage == ShaderType::Vertex) { @@ -810,11 +809,11 @@ bool TryRecompile(std::span code, const CompileOptions& options, : nullptr; runtime.userdata = options.read_memory_data; runtime.flat_memory_base = options.flat_memory_base; - if (!IR::MaterializeResources(ir, runtime, &resources, error)) { + if (!IR::MaterializeResources(ir, runtime, resources, error)) { return false; } } - if (!IR::SpecializeResources(&ir, resources, error)) { + if (!IR::SpecializeResources(ir, resources, error)) { return false; } @@ -828,13 +827,13 @@ bool TryRecompile(std::span code, const CompileOptions& options, options.pixel_input_info != nullptr ? options.pixel_input_info : &default_pixel; info_options.compute = options.compute_input_info != nullptr ? options.compute_input_info : &default_compute; - if (!IR::CollectShaderInfo(&ir, info_options, error)) { + if (!IR::CollectShaderInfo(ir, info_options, error)) { return false; } IR::BindingLayoutOptions layout_options; layout_options.descriptor_set = options.descriptor_set; layout_options.push_constant_offset = options.push_constant_offset; - if (!IR::AllocateBindings(&ir, layout_options, error)) { + if (!IR::AllocateBindings(ir, layout_options, error)) { return false; } std::string ir_dump; @@ -850,7 +849,7 @@ bool TryRecompile(std::span code, const CompileOptions& options, LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " SPIR-V EmitProgram\n", GetDumpLabel(options), StageName(options.stage), options.shader_hash); if (!Spirv::EmitProgram(ir, resources, options.vertex_input_info, options.pixel_input_info, - options.compute_input_info, &spirv, &emit_error)) { + options.compute_input_info, spirv, &emit_error)) { if (dispatcher_fallback && error != nullptr) { *error = fmt::format("dispatcher fallback failed after {}: {}", dispatcher_reason.c_str(), emit_error.c_str()); @@ -868,15 +867,15 @@ bool TryRecompile(std::span code, const CompileOptions& options, LOGF("%s dispatcher fallback used: %s\n", GetDumpLabel(options), dispatcher_reason.c_str()); } - result->spirv = std::move(spirv); - result->program = std::move(ir); - result->resources = std::move(resources); + result.spirv = std::move(spirv); + result.program = std::move(ir); + result.resources = std::move(resources); if (options.dump_ir) { - result->decoded_dump = std::move(decoded_dump); - result->ir_dump = std::move(ir_dump); + result.decoded_dump = std::move(decoded_dump); + result.ir_dump = std::move(ir_dump); } else { - result->decoded_dump.clear(); - result->ir_dump.clear(); + result.decoded_dump.clear(); + result.ir_dump.clear(); } return true; } diff --git a/src/graphics/shader/recompiler/ShaderRecompiler.h b/src/graphics/shader/recompiler/ShaderRecompiler.h index 9819de561..d06c391fa 100644 --- a/src/graphics/shader/recompiler/ShaderRecompiler.h +++ b/src/graphics/shader/recompiler/ShaderRecompiler.h @@ -44,7 +44,7 @@ struct CompileResult { }; bool TryRecompile(std::span code, const CompileOptions& options, - CompileResult* result, std::string* error); + CompileResult& result, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler diff --git a/src/graphics/shader/recompiler/SpirvBuilder.cpp b/src/graphics/shader/recompiler/SpirvBuilder.cpp index 4261842c7..031b52c48 100644 --- a/src/graphics/shader/recompiler/SpirvBuilder.cpp +++ b/src/graphics/shader/recompiler/SpirvBuilder.cpp @@ -8,15 +8,15 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv { static constexpr size_t InitialSpirvSectionReserve = 4096; static constexpr size_t InitialSpirvFunctionSectionReserve = 450000; -static void AppendInstructionWords(std::vector* section, const uint32_t* words, +static void AppendInstructionWords(std::vector& section, const uint32_t* words, size_t words_num) { if (words_num == 0) { return; } const auto opcode = words[0]; const auto word_count = static_cast(words_num); - section->push_back((word_count << 16u) | opcode); - section->insert(section->end(), words + 1, words + words_num); + section.push_back((word_count << 16u) | opcode); + section.insert(section.end(), words + 1, words + words_num); } Builder::Builder() { @@ -30,7 +30,7 @@ uint32_t Builder::AllocateId() { return m_next_id++; } -void Builder::AppendString(std::vector* words, const char* text) { +void Builder::AppendString(std::vector& words, const char* text) { const auto len = text != nullptr ? std::strlen(text) : 0; const auto word_count = (len + 1u + 3u) / 4u; for (size_t i = 0; i < word_count; i++) { @@ -42,76 +42,76 @@ void Builder::AppendString(std::vector* words, const char* text) { << (byte * 8u); } } - words->push_back(word); + words.push_back(word); } } -void Builder::AppendInstruction(std::vector* section, uint32_t opcode, +void Builder::AppendInstruction(std::vector& section, uint32_t opcode, const std::vector& operands) { const uint32_t word_count = static_cast(operands.size() + 1u); - section->push_back((word_count << 16u) | opcode); - section->insert(section->end(), operands.begin(), operands.end()); + section.push_back((word_count << 16u) | opcode); + section.insert(section.end(), operands.begin(), operands.end()); } -void Builder::AppendInstruction(std::vector* section, uint32_t opcode, +void Builder::AppendInstruction(std::vector& section, uint32_t opcode, std::initializer_list operands) { const uint32_t word_count = static_cast(operands.size() + 1u); - section->push_back((word_count << 16u) | opcode); - section->insert(section->end(), operands.begin(), operands.end()); + section.push_back((word_count << 16u) | opcode); + section.insert(section.end(), operands.begin(), operands.end()); } void Builder::AddCapability(std::initializer_list operands) { - AppendInstruction(&m_capabilities, 17u, operands); + AppendInstruction(m_capabilities, 17u, operands); } void Builder::AddExtension(const char* name) { std::vector operands; - AppendString(&operands, name); - AppendInstruction(&m_extensions, 10u, operands); + AppendString(operands, name); + AppendInstruction(m_extensions, 10u, operands); } void Builder::AddExtInstImport(uint32_t id, const char* name) { std::vector operands = {id}; - AppendString(&operands, name); - AppendInstruction(&m_ext_inst_imports, 11u, operands); + AppendString(operands, name); + AppendInstruction(m_ext_inst_imports, 11u, operands); } void Builder::AddMemoryModel(std::initializer_list operands) { - AppendInstruction(&m_memory_model, 14u, operands); + AppendInstruction(m_memory_model, 14u, operands); } void Builder::AddEntryPoint(uint32_t execution_model, uint32_t entry_point, const char* name, const std::vector& interfaces) { std::vector operands = {execution_model, entry_point}; - AppendString(&operands, name); + AppendString(operands, name); operands.insert(operands.end(), interfaces.begin(), interfaces.end()); - AppendInstruction(&m_entry_points, 15u, operands); + AppendInstruction(m_entry_points, 15u, operands); } void Builder::AddExecutionMode(std::initializer_list operands) { - AppendInstruction(&m_execution_modes, 16u, operands); + AppendInstruction(m_execution_modes, 16u, operands); } void Builder::AddName(uint32_t target, const char* name) { std::vector operands = {target}; - AppendString(&operands, name); - AppendInstruction(&m_debug, 5u, operands); + AppendString(operands, name); + AppendInstruction(m_debug, 5u, operands); } void Builder::AddAnnotation(std::initializer_list words) { - AppendInstructionWords(&m_annotations, words.begin(), words.size()); + AppendInstructionWords(m_annotations, words.begin(), words.size()); } void Builder::AddType(std::initializer_list words) { - AppendInstructionWords(&m_types, words.begin(), words.size()); + AppendInstructionWords(m_types, words.begin(), words.size()); } void Builder::AddFunction(std::initializer_list words) { - AppendInstructionWords(&m_functions, words.begin(), words.size()); + AppendInstructionWords(m_functions, words.begin(), words.size()); } void Builder::AddFunction(const std::vector& words) { - AppendInstructionWords(&m_functions, words.data(), words.size()); + AppendInstructionWords(m_functions, words.data(), words.size()); } std::vector Builder::Build() const { diff --git a/src/graphics/shader/recompiler/SpirvBuilder.h b/src/graphics/shader/recompiler/SpirvBuilder.h index ccd184b0a..5cd1fd44e 100644 --- a/src/graphics/shader/recompiler/SpirvBuilder.h +++ b/src/graphics/shader/recompiler/SpirvBuilder.h @@ -32,11 +32,11 @@ public: [[nodiscard]] std::vector Build() const; private: - static void AppendInstruction(std::vector* section, uint32_t opcode, + static void AppendInstruction(std::vector& section, uint32_t opcode, const std::vector& operands); - static void AppendInstruction(std::vector* section, uint32_t opcode, + static void AppendInstruction(std::vector& section, uint32_t opcode, std::initializer_list operands); - static void AppendString(std::vector* words, const char* text); + static void AppendString(std::vector& words, const char* text); uint32_t m_next_id = 1; std::vector m_capabilities; diff --git a/src/graphics/shader/recompiler/SpirvEmitter.cpp b/src/graphics/shader/recompiler/SpirvEmitter.cpp index aac056f7a..f482dbb41 100644 --- a/src/graphics/shader/recompiler/SpirvEmitter.cpp +++ b/src/graphics/shader/recompiler/SpirvEmitter.cpp @@ -339,7 +339,7 @@ static bool IsUniformZeroExecWrite(const IR::Program& program, const IR::Instruc return false; } uint32_t count = 0; - return IR::FoldScalarConstant(program.provenance, inst.scalar_sources[0], &count) && + return IR::FoldScalarConstant(program.provenance, inst.scalar_sources[0], count) && (count & 63u) == 0u; } @@ -408,16 +408,12 @@ bool ProgramRequiresExactSubgroupSize(const IR::Program& program) { } bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resources, - const ShaderVertexInputInfo* vertex_input_info, - const ShaderPixelInputInfo* pixel_input_info, - const ShaderComputeInputInfo* compute_input_info, std::vector* spirv, - std::string* error) { + const ShaderVertexInputInfo* vertex_input_info, + const ShaderPixelInputInfo* pixel_input_info, + const ShaderComputeInputInfo* compute_input_info, std::vector& spirv, + std::string* error) { using namespace Emitter; - if (spirv == nullptr) { - SetError(error, "invalid SPIR-V output"); - return false; - } if (program.stage != ShaderType::Compute && program.stage != ShaderType::Vertex && program.stage != ShaderType::Pixel) { SetError(error, "binary SPIR-V emitter supports compute, vertex, and pixel shaders"); @@ -438,9 +434,7 @@ bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resourc return false; } - EmitterState state; - state.program = &program; - state.resources = &resources; + EmitterState state(program, resources); state.vertex_input_info = vertex_input_info; state.pixel_input_info = pixel_input_info; state.compute_input_info = compute_input_info; @@ -454,8 +448,8 @@ bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resourc state.outputs.reserve(InitialEmitterVectorReserve); state.interface_variables.reserve(InitialEmitterVectorReserve); state.reachable_blocks.reserve(InitialEmitterVectorReserve); - CollectRegisters(program, &state.registers); - CopyProgramInputsAndOutputs(&state, program); + CollectRegisters(program, state.registers); + CopyProgramInputsAndOutputs(state, program); state.needs_subgroup_ballot = ProgramNeedsSubgroupBallot(program); state.needs_subgroup_shuffle = ProgramNeedsSubgroupShuffle(program); state.needs_subgroup_local_invocation_id = ProgramNeedsSubgroupLocalInvocationId(program); @@ -463,15 +457,15 @@ bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resourc state.needs_image_gather_extended = ProgramNeedsImageGatherExtended(program); state.needs_function_lds = ProgramNeedsFunctionLds(program); state.needs_pixel_valid_mask = ProgramNeedsPixelValidMask(program); - ComputeReachableBlocks(&state, program); - AllocateInputVariables(&state); - AllocateOutputVariables(&state); - AllocateDescriptorVariables(&state); - EmitHeaderAndTypes(&state); - AllocateRegisterVariables(&state); - AllocateBlockLabels(&state, program); - AllocateDispatcherState(&state, program); - EmitFunction(&state, program); + ComputeReachableBlocks(state, program); + AllocateInputVariables(state); + AllocateOutputVariables(state); + AllocateDescriptorVariables(state); + EmitHeaderAndTypes(state); + AllocateRegisterVariables(state); + AllocateBlockLabels(state, program); + AllocateDispatcherState(state, program); + EmitFunction(state, program); ReportReserveExceeded(program, "registers", state.registers.size()); ReportReserveExceeded(program, "inputs", state.inputs.size()); @@ -484,7 +478,7 @@ bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resourc SetError(error, "SPIR-V builder returned an empty module"); return false; } - *spirv = std::move(binary); + spirv = std::move(binary); return true; } diff --git a/src/graphics/shader/recompiler/SpirvEmitter.h b/src/graphics/shader/recompiler/SpirvEmitter.h index ddc798ae4..424cd0eaa 100644 --- a/src/graphics/shader/recompiler/SpirvEmitter.h +++ b/src/graphics/shader/recompiler/SpirvEmitter.h @@ -12,9 +12,9 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv { bool ProgramRequiresExactSubgroupSize(const IR::Program& program); bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resources, - const ShaderVertexInputInfo* vertex_input_info, - const ShaderPixelInputInfo* pixel_input_info, - const ShaderComputeInputInfo* compute_input_info, std::vector* spirv, + const ShaderVertexInputInfo* vertex_input_info, + const ShaderPixelInputInfo* pixel_input_info, + const ShaderComputeInputInfo* compute_input_info, std::vector& spirv, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::Spirv diff --git a/src/graphics/shader/recompiler/SrtPatcher.cpp b/src/graphics/shader/recompiler/SrtPatcher.cpp index 734c8e51d..02ec7b971 100644 --- a/src/graphics/shader/recompiler/SrtPatcher.cpp +++ b/src/graphics/shader/recompiler/SrtPatcher.cpp @@ -1,19 +1,19 @@ #include "graphics/shader/recompiler/SrtPatcher.h" #include +#include #include #include #include namespace Libs::Graphics::ShaderRecompiler::IR { -bool PatchSrtReads(Program* program, std::string* error) { - if (program == nullptr || !program->srt_plan_complete || program->srt_patching_complete || - program->resource_tracking_complete) { +bool PatchSrtReads(Program& program, std::string* error) { + if (!program.srt_plan_complete || program.srt_patching_complete || + program.resource_tracking_complete) { if (error != nullptr) { - *error = program == nullptr ? "invalid SRT patch program" - : !program->srt_plan_complete ? "SRT plan is not ready" - : program->srt_patching_complete ? "SRT reads already patched" + *error = !program.srt_plan_complete ? "SRT plan is not ready" + : program.srt_patching_complete ? "SRT reads already patched" : "resources already tracked"; } return false; @@ -21,11 +21,11 @@ bool PatchSrtReads(Program* program, std::string* error) { std::map offsets; std::map values; - for (const auto& read: program->srt.reads) { - if (read.value >= program->provenance.values.size() || - read.flat_offset >= program->srt.reads.size() || - (program->provenance.values[read.value].op != ScalarValueOp::ReadConst && - program->provenance.values[read.value].op != ScalarValueOp::ReadConstBuffer)) { + for (const auto& read: program.srt.reads) { + if (read.value >= program.provenance.values.size() || + read.flat_offset >= program.srt.reads.size() || + (program.provenance.values[read.value].op != ScalarValueOp::ReadConst && + program.provenance.values[read.value].op != ScalarValueOp::ReadConstBuffer)) { if (error != nullptr) { *error = fmt::format("invalid SRT read value={} flat_offset={}", read.value, read.flat_offset); @@ -47,7 +47,7 @@ bool PatchSrtReads(Program* program, std::string* error) { return false; } } - if (offsets.size() != program->srt.reads.size() || values.size() != program->srt.reads.size()) { + if (offsets.size() != program.srt.reads.size() || values.size() != program.srt.reads.size()) { if (error != nullptr) { *error = "SRT reads do not form a dense value-to-offset bijection"; } @@ -55,10 +55,10 @@ bool PatchSrtReads(Program* program, std::string* error) { } std::set dynamic_reads; - for (const auto value: program->srt.dynamic_reads) { - if (value >= program->provenance.values.size() || offsets.contains(value) || - (program->provenance.values[value].op != ScalarValueOp::ReadConst && - program->provenance.values[value].op != ScalarValueOp::ReadConstBuffer) || + for (const auto value: program.srt.dynamic_reads) { + if (value >= program.provenance.values.size() || offsets.contains(value) || + (program.provenance.values[value].op != ScalarValueOp::ReadConst && + program.provenance.values[value].op != ScalarValueOp::ReadConstBuffer) || !dynamic_reads.insert(value).second) { if (error != nullptr) { *error = fmt::format("invalid dynamic SRT read value={}", value); @@ -67,10 +67,10 @@ bool PatchSrtReads(Program* program, std::string* error) { } } std::set dynamic_sources; - for (const auto source: program->srt.dynamic_sources) { + for (const auto source: program.srt.dynamic_sources) { if (source == ScalarProvenance::Undefined || (source > ScalarProvenance::Unknown && - source - 2u >= program->provenance.descriptors.size()) || + source - 2u >= program.provenance.descriptors.size()) || !dynamic_sources.insert(source).second) { if (error != nullptr) { *error = fmt::format("invalid dynamic descriptor source={}", source); @@ -80,21 +80,21 @@ bool PatchSrtReads(Program* program, std::string* error) { } struct Patch { - Instruction* inst = nullptr; - uint32_t flat_offset = 0; + std::reference_wrapper inst; + uint32_t flat_offset = 0; }; std::vector patches; std::map matched; for (const auto& [value, offset]: offsets) { matched.emplace(value, false); } - for (auto& block: program->blocks) { + for (auto& block: program.blocks) { for (auto& inst: block.instructions) { if (inst.op != Opcode::SLoadDword && inst.op != Opcode::SBufferLoadDword) { continue; } if (const auto found = offsets.find(inst.scalar_value); found != offsets.end()) { - const auto value_op = program->provenance.values[found->first].op; + const auto value_op = program.provenance.values[found->first].op; if ((inst.op == Opcode::SLoadDword) != (value_op == ScalarValueOp::ReadConst)) { if (error != nullptr) { *error = fmt::format("SRT read value {} has the wrong scalar-load producer", @@ -102,7 +102,7 @@ bool PatchSrtReads(Program* program, std::string* error) { } return false; } - patches.push_back({&inst, found->second}); + patches.push_back({std::ref(inst), found->second}); matched[found->first] = true; } } @@ -117,16 +117,17 @@ bool PatchSrtReads(Program* program, std::string* error) { } for (const auto& patch: patches) { - patch.inst->op = Opcode::LoadSrtDword; - patch.inst->src_count = 1; - for (auto& src: patch.inst->src) { + auto& inst = patch.inst.get(); + inst.op = Opcode::LoadSrtDword; + inst.src_count = 1; + for (auto& src: inst.src) { src = {}; } - patch.inst->src[0].kind = OperandKind::ImmediateU32; - patch.inst->src[0].imm = patch.flat_offset; - patch.inst->memory = {}; + inst.src[0].kind = OperandKind::ImmediateU32; + inst.src[0].imm = patch.flat_offset; + inst.memory = {}; } - program->srt_patching_complete = true; + program.srt_patching_complete = true; return true; } diff --git a/src/graphics/shader/recompiler/SrtPatcher.h b/src/graphics/shader/recompiler/SrtPatcher.h index b6c16c5b6..90dedc5f0 100644 --- a/src/graphics/shader/recompiler/SrtPatcher.h +++ b/src/graphics/shader/recompiler/SrtPatcher.h @@ -7,7 +7,7 @@ namespace Libs::Graphics::ShaderRecompiler::IR { // Replaces each immediate ReadConst producer selected by the SRT plan with a dense flat-buffer // dword load. Dynamic-offset reads remain explicit. On failure no instruction is changed. -bool PatchSrtReads(Program* program, std::string* error); +bool PatchSrtReads(Program& program, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::IR diff --git a/src/graphics/shader/recompiler/SrtWalker.cpp b/src/graphics/shader/recompiler/SrtWalker.cpp index 8cf663574..0297101a6 100644 --- a/src/graphics/shader/recompiler/SrtWalker.cpp +++ b/src/graphics/shader/recompiler/SrtWalker.cpp @@ -3,6 +3,7 @@ #include "graphics/shader/recompiler/ScalarProvenance.h" #include +#include #include #include @@ -26,8 +27,8 @@ std::string Diagnostic(const Program& program, uint32_t pc, const std::string& m StageName(program.stage), pc, message); } -bool AddSignedAddress(uint64_t base, int64_t offset, uint64_t* result) { - if (result == nullptr || base > AddressMask) { +bool AddSignedAddress(uint64_t base, int64_t offset, uint64_t& result) { + if (base > AddressMask) { return false; } if (offset < 0) { @@ -35,69 +36,66 @@ bool AddSignedAddress(uint64_t base, int64_t offset, uint64_t* result) { if (magnitude > base) { return false; } - *result = base - magnitude; + result = base - magnitude; return true; } const auto magnitude = static_cast(offset); if (magnitude > AddressMask - base) { return false; } - *result = base + magnitude; + result = base + magnitude; return true; } -bool ApplyOperation(ScalarValueOp op, const uint32_t args[3], uint32_t* result) { - if (result == nullptr) { - return false; - } +bool ApplyOperation(ScalarValueOp op, const std::array& args, uint32_t& result) { const auto shift = args[1] & 31u; switch (op) { - case ScalarValueOp::Add: *result = args[0] + args[1]; break; - case ScalarValueOp::AddCarry: *result = args[0] + args[1] + (args[2] & 1u); break; + case ScalarValueOp::Add: result = args[0] + args[1]; break; + case ScalarValueOp::AddCarry: result = args[0] + args[1] + (args[2] & 1u); break; case ScalarValueOp::Carry: - *result = static_cast( + result = static_cast( (static_cast(args[0]) + args[1] + (args[2] & 1u)) >> 32u); break; - case ScalarValueOp::Sub: *result = args[0] - args[1]; break; - case ScalarValueOp::SubBorrow: *result = args[0] - args[1] - (args[2] & 1u); break; + case ScalarValueOp::Sub: result = args[0] - args[1]; break; + case ScalarValueOp::SubBorrow: result = args[0] - args[1] - (args[2] & 1u); break; case ScalarValueOp::Borrow: - *result = static_cast(args[1]) + (args[2] & 1u) > args[0] ? 1u : 0u; + result = static_cast(args[1]) + (args[2] & 1u) > args[0] ? 1u : 0u; break; - case ScalarValueOp::Mul: *result = args[0] * args[1]; break; - case ScalarValueOp::And: *result = args[0] & args[1]; break; - case ScalarValueOp::AndNot: *result = args[0] & ~args[1]; break; - case ScalarValueOp::Or: *result = args[0] | args[1]; break; - case ScalarValueOp::OrNot: *result = args[0] | ~args[1]; break; - case ScalarValueOp::Xor: *result = args[0] ^ args[1]; break; - case ScalarValueOp::Not: *result = ~args[0]; break; - case ScalarValueOp::ShiftLeft: *result = args[0] << shift; break; - case ScalarValueOp::ShiftRight: *result = args[0] >> shift; break; + case ScalarValueOp::Mul: result = args[0] * args[1]; break; + case ScalarValueOp::And: result = args[0] & args[1]; break; + case ScalarValueOp::AndNot: result = args[0] & ~args[1]; break; + case ScalarValueOp::Or: result = args[0] | args[1]; break; + case ScalarValueOp::OrNot: result = args[0] | ~args[1]; break; + case ScalarValueOp::Xor: result = args[0] ^ args[1]; break; + case ScalarValueOp::Not: result = ~args[0]; break; + case ScalarValueOp::ShiftLeft: result = args[0] << shift; break; + case ScalarValueOp::ShiftRight: result = args[0] >> shift; break; case ScalarValueOp::ShiftRightArithmetic: - *result = static_cast(static_cast(args[0]) >> shift); + result = static_cast(static_cast(args[0]) >> shift); break; case ScalarValueOp::BitFieldMaskU32: { const auto count = args[0] & 31u; const auto offset = args[1] & 31u; - *result = ((uint32_t {1} << count) - 1u) << offset; + result = ((uint32_t {1} << count) - 1u) << offset; break; } case ScalarValueOp::BitFieldMaskU64Low: case ScalarValueOp::BitFieldMaskU64High: { const auto count = args[0] & 63u; const auto value = ((uint64_t {1} << count) - 1u) << (args[1] & 63u); - *result = op == ScalarValueOp::BitFieldMaskU64Low ? static_cast(value) - : static_cast(value >> 32u); + result = op == ScalarValueOp::BitFieldMaskU64Low ? static_cast(value) + : static_cast(value >> 32u); break; } - case ScalarValueOp::Add3: *result = args[0] + args[1] + args[2]; break; - case ScalarValueOp::ShiftLeftAdd: *result = (args[0] << shift) + args[2]; break; + case ScalarValueOp::Add3: result = args[0] + args[1] + args[2]; break; + case ScalarValueOp::ShiftLeftAdd: result = (args[0] << shift) + args[2]; break; case ScalarValueOp::ShiftLeftAddCarry: - *result = + result = static_cast(((static_cast(args[0]) << shift) + args[2]) >> 32u); break; - case ScalarValueOp::AddShiftLeft: *result = (args[0] + args[1]) << (args[2] & 31u); break; - case ScalarValueOp::XorAdd: *result = (args[0] ^ args[1]) + args[2]; break; - case ScalarValueOp::ShiftLeftOr: *result = (args[0] << shift) | args[2]; break; + case ScalarValueOp::AddShiftLeft: result = (args[0] + args[1]) << (args[2] & 31u); break; + case ScalarValueOp::XorAdd: result = (args[0] ^ args[1]) + args[2]; break; + case ScalarValueOp::ShiftLeftOr: result = (args[0] << shift) | args[2]; break; default: return false; } return true; @@ -138,13 +136,13 @@ public: if (count == 0 || count > 3 || value.op == ScalarValueOp::ReadConst) { return Dynamic(id); } - uint32_t args[3] = {}; + std::array args {}; for (uint32_t i = 0; i < count; i++) { if (!Fold(value.args[i], args[i])) { return Dynamic(id); } } - if (!ApplyOperation(value.op, args, &out)) { + if (!ApplyOperation(value.op, args, out)) { return Dynamic(id); } break; @@ -169,13 +167,13 @@ private: class PlanBuilder { public: - explicit PlanBuilder(Program* program): m_program(program), m_folder(program->provenance) { - m_state.resize(program->provenance.values.size()); + explicit PlanBuilder(Program& program): m_program(program), m_folder(program.provenance) { + m_state.resize(program.provenance.values.size()); } bool Run(std::string* error) { - m_program->srt = {}; - for (const auto& block: m_program->blocks) { + m_program.srt = {}; + for (const auto& block: m_program.blocks) { for (const auto& inst: block.instructions) { if (!CollectDescriptor(inst.memory.resource_source, inst.pc, error) || !CollectDescriptor(inst.memory.sampler_source, inst.pc, error)) { @@ -183,11 +181,11 @@ public: } } } - for (const auto& block: m_program->blocks) { + for (const auto& block: m_program.blocks) { for (const auto& inst: block.instructions) { if (inst.op == Opcode::SLoadDword && inst.scalar_value < m_state.size() && m_state[inst.scalar_value] == 0) { - const auto& value = m_program->provenance.values[inst.scalar_value]; + const auto& value = m_program.provenance.values[inst.scalar_value]; uint32_t ignored = 0; if (value.op == ScalarValueOp::ReadConst && m_folder.Fold(value.args[2], ignored) && @@ -203,20 +201,20 @@ public: private: bool Fail(uint32_t pc, std::string* error, const std::string& message) const { if (error != nullptr) { - *error = Diagnostic(*m_program, pc, message); + *error = Diagnostic(m_program, pc, message); } return false; } bool CollectDescriptor(uint32_t source, uint32_t use_pc, std::string* error) { - const auto* descriptor = GetDescriptorSource(*m_program, source); + const auto* descriptor = GetDescriptorSource(m_program, source); if (descriptor == nullptr) { if (source <= ScalarProvenance::Unknown) { return source == ScalarProvenance::Undefined || AddDynamicSource(source); } return Fail(use_pc, error, fmt::format("invalid descriptor source {}", source)); } - if (!DescriptorSourceResolved(*m_program, source) || + if (!DescriptorSourceResolved(m_program, source) || DescriptorNeedsControlFlow(*descriptor)) { MarkDescriptor(*descriptor); return AddDynamicSource(source); @@ -240,7 +238,7 @@ private: return; } m_state[id] = 2; - const auto& value = m_program->provenance.values[id]; + const auto& value = m_program.provenance.values[id]; if (value.op == ScalarValueOp::Phi) { for (const auto arg: value.phi_args) { MarkValue(arg); @@ -253,21 +251,21 @@ private: } bool DescriptorNeedsControlFlow(const DescriptorValue& descriptor) { - std::vector visited(m_program->provenance.values.size()); + std::vector visited(m_program.provenance.values.size()); for (uint32_t i = 0; i < descriptor.dword_count; i++) { - if (ValueNeedsControlFlow(descriptor.dwords[i], &visited)) { + if (ValueNeedsControlFlow(descriptor.dwords[i], visited)) { return true; } } return false; } - bool ValueNeedsControlFlow(uint32_t id, std::vector* visited) { - if (id >= m_program->provenance.values.size() || (*visited)[id] != 0) { + bool ValueNeedsControlFlow(uint32_t id, std::vector& visited) { + if (id >= m_program.provenance.values.size() || visited[id] != 0) { return false; } - (*visited)[id] = 1; - const auto& value = m_program->provenance.values[id]; + visited[id] = 1; + const auto& value = m_program.provenance.values[id]; if (value.op == ScalarValueOp::Phi) { uint32_t ignored = 0; return !m_folder.Fold(id, ignored); @@ -281,15 +279,15 @@ private: } bool AddDynamicSource(uint32_t source) { - if (std::find(m_program->srt.dynamic_sources.begin(), m_program->srt.dynamic_sources.end(), - source) == m_program->srt.dynamic_sources.end()) { - m_program->srt.dynamic_sources.push_back(source); + if (std::find(m_program.srt.dynamic_sources.begin(), m_program.srt.dynamic_sources.end(), + source) == m_program.srt.dynamic_sources.end()) { + m_program.srt.dynamic_sources.push_back(source); } return true; } bool CollectValue(uint32_t id, uint32_t use_pc, std::string* error) { - if (id >= m_program->provenance.values.size()) { + if (id >= m_program.provenance.values.size()) { return Fail(use_pc, error, fmt::format("invalid scalar value {}", id)); } if (m_state[id] == 2) { @@ -299,7 +297,7 @@ private: return Fail(use_pc, error, fmt::format("cyclic scalar value {}", id)); } m_state[id] = 1; - const auto& value = m_program->provenance.values[id]; + const auto& value = m_program.provenance.values[id]; if (value.op == ScalarValueOp::Phi) { for (const auto arg: value.phi_args) { if (!CollectValue(arg, use_pc, error)) { @@ -317,17 +315,17 @@ private: const auto offset_arg = value.op == ScalarValueOp::ReadConst ? 2u : 4u; uint32_t ignored = 0; if (m_folder.Fold(value.args[offset_arg], ignored)) { - m_program->srt.reads.push_back( - {id, static_cast(m_program->srt.reads.size()), use_pc}); + m_program.srt.reads.push_back( + {id, static_cast(m_program.srt.reads.size()), use_pc}); } else { - m_program->srt.dynamic_reads.push_back(id); + m_program.srt.dynamic_reads.push_back(id); } } m_state[id] = 2; return true; } - Program* m_program; + Program& m_program; ConstantFolder m_folder; std::vector m_state; }; @@ -395,7 +393,7 @@ public: } case ScalarValueOp::ReadConst: case ScalarValueOp::ReadConstBuffer: - if (!Read(value, &out, error)) { + if (!Read(value, out, error)) { return false; } break; @@ -403,7 +401,7 @@ public: case ScalarValueOp::Unknown: return Fail(error, fmt::format("scalar value {} is unresolved", id)); default: - if (!EvaluateOperation(value, &out, error)) { + if (!EvaluateOperation(value, out, error)) { return false; } break; @@ -422,13 +420,13 @@ private: return false; } - bool EvaluateOperation(const ScalarValue& value, uint32_t* result, std::string* error) { + bool EvaluateOperation(const ScalarValue& value, uint32_t& result, std::string* error) { const auto count = ScalarValueArgCount(value.op); if (count == 0 || count > 3) { return Fail(error, fmt::format("unsupported scalar operation {}", static_cast(value.op))); } - uint32_t args[3] = {}; + std::array args {}; for (uint32_t i = 0; i < count; i++) { if (!Evaluate(value.args[i], args[i], error)) { return false; @@ -439,7 +437,7 @@ private: static_cast(value.op))); } - bool Read(const ScalarValue& value, uint32_t* result, std::string* error) { + bool Read(const ScalarValue& value, uint32_t& result, std::string* error) { const bool buffer = value.op == ScalarValueOp::ReadConstBuffer; uint32_t lo = 0; uint32_t hi = 0; @@ -478,7 +476,7 @@ private: const auto base_aligned = base & ~uint64_t {3}; const auto immediate_aligned = immediate & ~int64_t {3}; const auto relative = immediate_aligned + static_cast(offset & ~uint32_t {3}); - if (!AddSignedAddress(base_aligned, relative, &address)) { + if (!AddSignedAddress(base_aligned, relative, address)) { return Fail(error, fmt::format("ReadConst pc=0x{:08x} address base=0x{:016x} offset={} " "is outside the 48-bit address space", @@ -486,12 +484,12 @@ private: } } if (m_runtime.read_memory != nullptr && - !m_runtime.read_memory(m_runtime.userdata, address, result)) { + !m_runtime.read_memory(m_runtime.userdata, address, &result)) { return Fail( error, fmt::format("ReadConst pc=0x{:08x} failed at 0x{:016x}", value.pc, address)); } if (m_runtime.read_memory == nullptr) { - std::memcpy(result, reinterpret_cast(address), sizeof(*result)); + std::memcpy(&result, reinterpret_cast(address), sizeof(result)); } return true; } @@ -505,71 +503,53 @@ private: } // namespace -bool FoldScalarConstant(const ScalarProvenance& provenance, uint32_t value, uint32_t* result) { - if (result == nullptr) { - return false; - } +bool FoldScalarConstant(const ScalarProvenance& provenance, uint32_t value, uint32_t& result) { ConstantFolder folder(provenance); - return folder.Fold(value, *result); + return folder.Fold(value, result); } -bool BuildSrtPlan(Program* program, std::string* error) { - if (program == nullptr) { - if (error != nullptr) { - *error = "invalid SRT program"; - } - return false; - } - if (program->resource_tracking_complete) { +bool BuildSrtPlan(Program& program, std::string* error) { + if (program.resource_tracking_complete) { if (error != nullptr) { *error = "cannot rebuild SRT plan after resource tracking"; } return false; } - if (program->srt_patching_complete) { + if (program.srt_patching_complete) { if (error != nullptr) { *error = "cannot rebuild SRT plan after SRT patching"; } return false; } - program->srt_plan_complete = false; + program.srt_plan_complete = false; if (!PlanBuilder(program).Run(error)) { return false; } - program->srt_plan_complete = true; + program.srt_plan_complete = true; return true; } bool EvaluateDescriptorSource(const Program& program, uint32_t source, uint32_t use_pc, - const SrtRuntime& runtime, DescriptorValue* result, - std::string* error) { - if (result == nullptr) { - if (error != nullptr) { - *error = Diagnostic(program, use_pc, "invalid descriptor result"); - } - return false; - } + const SrtRuntime& runtime, DescriptorValue& result, + std::string* error) { const DescriptorSourceRequest request {source, use_pc}; std::vector results; - if (!EvaluateDescriptorSources(program, std::span {&request, 1}, runtime, &results, error)) { + if (!EvaluateDescriptorSources(program, std::span {&request, 1}, runtime, results, error)) { return false; } - *result = results[0]; + result = results[0]; return true; } static bool EvaluateRuntimeSourcesImpl(const Program& program, - std::span requests, - const SrtRuntime& runtime, - std::vector* results, - std::vector* flat, bool evaluate_flat, - std::string* error) { - if (results == nullptr || flat == nullptr || !program.srt_plan_complete) { + std::span requests, + const SrtRuntime& runtime, + std::vector& results, + std::vector& flat, bool evaluate_flat, + std::string* error) { + if (!program.srt_plan_complete) { if (error != nullptr) { - *error = Diagnostic(program, 0, - results == nullptr || flat == nullptr - ? "invalid runtime evaluation output" - : "SRT plan is not ready"); + *error = Diagnostic(program, 0, "SRT plan is not ready"); } return false; } @@ -614,44 +594,32 @@ static bool EvaluateRuntimeSourcesImpl(const Program& } } } - *results = std::move(evaluated); + results = std::move(evaluated); if (evaluate_flat) { - *flat = std::move(flattened); + flat = std::move(flattened); } return true; } bool EvaluateDescriptorSources(const Program& program, - std::span requests, - const SrtRuntime& runtime, std::vector* results, - std::string* error) { - if (results == nullptr) { - if (error != nullptr) { - *error = Diagnostic(program, 0, "invalid descriptor results"); - } - return false; - } + std::span requests, + const SrtRuntime& runtime, std::vector& results, + std::string* error) { std::vector ignored; - return EvaluateRuntimeSourcesImpl(program, requests, runtime, results, &ignored, false, error); + return EvaluateRuntimeSourcesImpl(program, requests, runtime, results, ignored, false, error); } bool EvaluateRuntimeSources(const Program& program, - std::span requests, - const SrtRuntime& runtime, std::vector* results, - std::vector* flat, std::string* error) { + std::span requests, + const SrtRuntime& runtime, std::vector& results, + std::vector& flat, std::string* error) { return EvaluateRuntimeSourcesImpl(program, requests, runtime, results, flat, true, error); } -bool WalkSrt(const Program& program, const SrtRuntime& runtime, std::vector* flat, - std::string* error) { - if (flat == nullptr) { - if (error != nullptr) { - *error = Diagnostic(program, 0, "invalid SRT walker output"); - } - return false; - } +bool WalkSrt(const Program& program, const SrtRuntime& runtime, std::vector& flat, + std::string* error) { std::vector ignored; - return EvaluateRuntimeSources(program, {}, runtime, &ignored, flat, error); + return EvaluateRuntimeSources(program, {}, runtime, ignored, flat, error); } } // namespace Libs::Graphics::ShaderRecompiler::IR diff --git a/src/graphics/shader/recompiler/SrtWalker.h b/src/graphics/shader/recompiler/SrtWalker.h index 1bf0fe2c8..4a36befe1 100644 --- a/src/graphics/shader/recompiler/SrtWalker.h +++ b/src/graphics/shader/recompiler/SrtWalker.h @@ -23,31 +23,31 @@ struct DescriptorSourceRequest { uint32_t use_pc = 0; }; -bool FoldScalarConstant(const ScalarProvenance& provenance, uint32_t value, uint32_t* result); +bool FoldScalarConstant(const ScalarProvenance& provenance, uint32_t value, uint32_t& result); // Collects reachable ReadConst values. Immediate offsets receive compact flat-buffer slots; // dynamic offsets remain explicit and are never assigned a fake slot. -bool BuildSrtPlan(Program* program, std::string* error); +bool BuildSrtPlan(Program& program, std::string* error); bool EvaluateDescriptorSource(const Program& program, uint32_t source, uint32_t use_pc, - const SrtRuntime& runtime, DescriptorValue* result, + const SrtRuntime& runtime, DescriptorValue& result, std::string* error); // Evaluates one runtime snapshot transactionally. Scalar values and ReadConst results shared by // several descriptors are memoized once across the batch. bool EvaluateDescriptorSources(const Program& program, - std::span requests, - const SrtRuntime& runtime, std::vector* results, + std::span requests, + const SrtRuntime& runtime, std::vector& results, std::string* error); // Evaluates descriptor sources and the flattened immediate SRT with one memoized scalar walk. // On failure neither destination is changed. bool EvaluateRuntimeSources(const Program& program, - std::span requests, - const SrtRuntime& runtime, std::vector* results, - std::vector* flat, std::string* error); + std::span requests, + const SrtRuntime& runtime, std::vector& results, + std::vector& flat, std::string* error); -bool WalkSrt(const Program& program, const SrtRuntime& runtime, std::vector* flat, +bool WalkSrt(const Program& program, const SrtRuntime& runtime, std::vector& flat, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::IR diff --git a/src/graphics/shader/recompiler/VectorAluOps.cpp b/src/graphics/shader/recompiler/VectorAluOps.cpp index f11165661..225df8821 100644 --- a/src/graphics/shader/recompiler/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/VectorAluOps.cpp @@ -319,9 +319,9 @@ bool IsNativeVop3B16BinaryOpcode(Opcode opcode) { } } -void ApplyDefaultVop2F16Destination(Instruction* inst) { - if (inst != nullptr && IsVop2LowHalfF16Opcode(inst->opcode)) { - inst->dst.sdwa_sel = 4; +void ApplyDefaultVop2F16Destination(Instruction& inst) { + if (IsVop2LowHalfF16Opcode(inst.opcode)) { + inst.dst.sdwa_sel = 4; } } @@ -476,7 +476,7 @@ bool HasUnsupportedVop1SdwaSourceModifiers(Opcode opcode, bool src_neg, bool src } } -bool ValidateVop1Sdwa(Instruction* inst, uint32_t opcode, uint32_t modifier) { +bool ValidateVop1Sdwa(Instruction& inst, uint32_t opcode, uint32_t modifier) { const auto dst_sel = (modifier >> 8u) & 0x7u; const auto dst_u = (modifier >> 11u) & 0x3u; const auto clamp = (modifier >> 13u) & 0x1u; @@ -489,20 +489,20 @@ bool ValidateVop1Sdwa(Instruction* inst, uint32_t opcode, uint32_t modifier) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 SDWA selector is invalid"); return false; } - if ((clamp != 0u || omod != 0u) && !IsVop1FloatResultOpcode(inst->opcode)) { + if ((clamp != 0u || omod != 0u) && !IsVop1FloatResultOpcode(inst.opcode)) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 SDWA output modifiers are not supported"); return false; } - if (!IsVop1SdwaDestinationSupported(inst->opcode, dst_sel, dst_u, src0_sel)) { + if (!IsVop1SdwaDestinationSupported(inst.opcode, dst_sel, dst_u, src0_sel)) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 SDWA destination selector is not supported"); return false; } - if (HasUnsupportedVop1SdwaSourceModifiers(inst->opcode, src0_neg != 0u, src0_abs != 0u)) { + if (HasUnsupportedVop1SdwaSourceModifiers(inst.opcode, src0_neg != 0u, src0_abs != 0u)) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 SDWA source modifiers are not supported"); return false; } - if (!IsVop1SdwaSourceSupported(inst->opcode, src0_sel, src0_neg != 0u, src0_abs != 0u)) { + if (!IsVop1SdwaSourceSupported(inst.opcode, src0_sel, src0_neg != 0u, src0_abs != 0u)) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 SDWA source selector is not supported"); return false; } @@ -510,7 +510,7 @@ bool ValidateVop1Sdwa(Instruction* inst, uint32_t opcode, uint32_t modifier) { } bool DecodeVop1Sdwa(uint32_t pc, std::span code, uint32_t word_index, - uint32_t opcode, uint32_t vdst, Instruction* inst, std::string* error) { + uint32_t opcode, uint32_t vdst, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { *error = fmt::format("truncated VOP1 SDWA instruction at pc 0x{:08x}", pc); @@ -535,26 +535,26 @@ bool DecodeVop1Sdwa(uint32_t pc, std::span code, uint32_t word_i return true; } - const bool scalar_dst = UsesScalarDestination(inst->opcode); - if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, &inst->dst, error) - : DecodeVectorGpr(vdst, &inst->dst, error)) || - !DecodeScalarSource(src0 + (s0 == 0u ? 256u : 0u), pc, &inst->src0, error)) { + const bool scalar_dst = UsesScalarDestination(inst.opcode); + if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, inst.dst, error) + : DecodeVectorGpr(vdst, inst.dst, error)) || + !DecodeScalarSource(src0 + (s0 == 0u ? 256u : 0u), pc, inst.src0, error)) { return false; } - inst->dst.sdwa_sel = dst_sel; - inst->dst.sdwa_dst_unused = dst_u; - inst->dst.clamp = clamp != 0u; - inst->dst.omod = omod; - inst->src0.sdwa_sel = src0_sel; - inst->src0.sdwa_sext = src0_sext != 0u; - inst->src0.negate = src0_neg != 0u; - inst->src0.absolute = src0_abs != 0u; - inst->src_count = 1; + inst.dst.sdwa_sel = dst_sel; + inst.dst.sdwa_dst_unused = dst_u; + inst.dst.clamp = clamp != 0u; + inst.dst.omod = omod; + inst.src0.sdwa_sel = src0_sel; + inst.src0.sdwa_sext = src0_sext != 0u; + inst.src0.negate = src0_neg != 0u; + inst.src0.absolute = src0_abs != 0u; + inst.src_count = 1; return ReadLiteralOperands(code, word_index, inst, error); } bool DecodeVop1Dpp(uint32_t pc, std::span code, uint32_t word_index, - uint32_t opcode, uint32_t vdst, Instruction* inst, std::string* error) { + uint32_t opcode, uint32_t vdst, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { *error = fmt::format("truncated VOP1 DPP instruction at pc 0x{:08x}", pc); @@ -566,23 +566,23 @@ bool DecodeVop1Dpp(uint32_t pc, std::span code, uint32_t word_in const auto src0 = modifier & 0xffu; SetRawWords(inst, code, word_index, 2); - const bool scalar_dst = UsesScalarDestination(inst->opcode); - if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, &inst->dst, error) - : DecodeVectorGpr(vdst, &inst->dst, error)) || - !DecodeScalarSource(src0 + 256u, pc, &inst->src0, error)) { + const bool scalar_dst = UsesScalarDestination(inst.opcode); + if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, inst.dst, error) + : DecodeVectorGpr(vdst, inst.dst, error)) || + !DecodeScalarSource(src0 + 256u, pc, inst.src0, error)) { return false; } - inst->src0.negate = ((modifier >> 20u) & 0x1u) != 0u; - inst->src0.absolute = ((modifier >> 21u) & 0x1u) != 0u; - inst->src0.dpp = true; - inst->src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu; - inst->src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u; - inst->src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u; - inst->src0.dpp_bank_mask = (modifier >> 24u) & 0xfu; - inst->src0.dpp_row_mask = (modifier >> 28u) & 0xfu; - inst->src_count = 1; + inst.src0.negate = ((modifier >> 20u) & 0x1u) != 0u; + inst.src0.absolute = ((modifier >> 21u) & 0x1u) != 0u; + inst.src0.dpp = true; + inst.src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu; + inst.src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u; + inst.src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u; + inst.src0.dpp_bank_mask = (modifier >> 24u) & 0xfu; + inst.src0.dpp_row_mask = (modifier >> 28u) & 0xfu; + inst.src_count = 1; - if (!IsVop1FloatSourceOpcode(inst->opcode) && (inst->src0.negate || inst->src0.absolute)) { + if (!IsVop1FloatSourceOpcode(inst.opcode) && (inst.src0.negate || inst.src0.absolute)) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 DPP integer source modifiers are not supported"); return true; @@ -592,7 +592,7 @@ bool DecodeVop1Dpp(uint32_t pc, std::span code, uint32_t word_in using Vop1ModifierDecodeFn = bool (*)(uint32_t pc, std::span code, uint32_t word_index, uint32_t opcode, uint32_t vdst, - Instruction* inst, std::string* error); + Instruction& inst, std::string* error); struct Vop1ModifierDecoder { uint32_t escape = 0; @@ -605,7 +605,7 @@ constexpr Vop1ModifierDecoder VOP1_MODIFIER_DECODERS[] = { }; bool TryDecodeVop1Modifier(uint32_t pc, std::span code, uint32_t word_index, - uint32_t src0, uint32_t opcode, uint32_t vdst, Instruction* inst, + uint32_t src0, uint32_t opcode, uint32_t vdst, Instruction& inst, std::string* error, bool* handled) { if (handled != nullptr) { *handled = false; @@ -857,17 +857,17 @@ bool IsFullWidthVop2Sdwa(const Vop2SdwaFields& fields) { fields.src1_sel == 6u; } -bool ValidateVop2Sdwa(Instruction* inst, uint32_t opcode, const Vop2SdwaFields& fields) { +bool ValidateVop2Sdwa(Instruction& inst, uint32_t opcode, const Vop2SdwaFields& fields) { if (fields.src0_sel > 6u || fields.src1_sel > 6u || fields.dst_sel > 6u) { SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA selector is invalid"); return false; } - if ((fields.clamp != 0u || fields.omod != 0u) && !IsVop2FloatResultOpcode(inst->opcode)) { + if ((fields.clamp != 0u || fields.omod != 0u) && !IsVop2FloatResultOpcode(inst.opcode)) { SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA output modifiers are not supported"); return false; } if (IsFullWidthVop2Sdwa(fields)) { - if (!IsVop2FloatSourceOpcode(inst->opcode) && inst->opcode != Opcode::VCndmaskB32 && + if (!IsVop2FloatSourceOpcode(inst.opcode) && inst.opcode != Opcode::VCndmaskB32 && (fields.src0_neg != 0u || fields.src0_abs != 0u || fields.src1_neg != 0u || fields.src1_abs != 0u)) { SetUnsupported(inst, Family::VOP2, opcode, @@ -877,7 +877,7 @@ bool ValidateVop2Sdwa(Instruction* inst, uint32_t opcode, const Vop2SdwaFields& return true; } - const auto* rule = FindVop2SdwaRule(inst->opcode); + const auto* rule = FindVop2SdwaRule(inst.opcode); if (rule == nullptr) { SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA modifier is not supported for opcode"); @@ -896,7 +896,7 @@ bool ValidateVop2Sdwa(Instruction* inst, uint32_t opcode, const Vop2SdwaFields& const bool has_source_modifiers = (fields.src0_neg != 0u || fields.src0_abs != 0u || fields.src1_neg != 0u || fields.src1_abs != 0u); const bool cndmask_float_modifiers = - inst->opcode == Opcode::VCndmaskB32 && fields.src0_sel == 6u && fields.src1_sel == 6u; + inst.opcode == Opcode::VCndmaskB32 && fields.src0_sel == 6u && fields.src1_sel == 6u; if (!rule->source_modifiers && has_source_modifiers && !cndmask_float_modifiers) { SetUnsupported(inst, Family::VOP2, opcode, "VOP2 SDWA source modifiers are not supported"); return false; @@ -905,34 +905,34 @@ bool ValidateVop2Sdwa(Instruction* inst, uint32_t opcode, const Vop2SdwaFields& } bool FinalizeVop2Instruction(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error) { + Instruction& inst, std::string* error) { (void)pc; - switch (inst->opcode) { + switch (inst.opcode) { case Opcode::VMadmkF32: case Opcode::VFmamkF16: - inst->src2 = inst->src1; - inst->src1 = {}; - inst->src1.kind = OperandKind::LiteralConstant; - inst->src_count = 3; + inst.src2 = inst.src1; + inst.src1 = {}; + inst.src1.kind = OperandKind::LiteralConstant; + inst.src_count = 3; break; case Opcode::VMadakF32: case Opcode::VFmaakF16: - inst->src2 = {}; - inst->src2.kind = OperandKind::LiteralConstant; - inst->src_count = 3; + inst.src2 = {}; + inst.src2.kind = OperandKind::LiteralConstant; + inst.src_count = 3; break; case Opcode::VAddcU32: - inst->dst2.kind = OperandKind::VccLo; - inst->src2.kind = OperandKind::VccLo; - inst->src_count = 3; + inst.dst2.kind = OperandKind::VccLo; + inst.src2.kind = OperandKind::VccLo; + inst.src_count = 3; break; - default: inst->src_count = 2; break; + default: inst.src_count = 2; break; } return ReadLiteralOperands(code, word_index, inst, error); } bool DecodeVop2Sdwa(uint32_t pc, std::span code, uint32_t word_index, - uint32_t opcode, uint32_t vdst, uint32_t vsrc1, Instruction* inst, + uint32_t opcode, uint32_t vdst, uint32_t vsrc1, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { @@ -948,28 +948,28 @@ bool DecodeVop2Sdwa(uint32_t pc, std::span code, uint32_t word_i return true; } - if (!DecodeVectorGpr(vdst, &inst->dst, error) || - !DecodeScalarSource(fields.src0 + (fields.s0 == 0u ? 256u : 0u), pc, &inst->src0, error) || - !DecodeScalarSource(vsrc1 + (fields.s1 == 0u ? 256u : 0u), pc, &inst->src1, error)) { + if (!DecodeVectorGpr(vdst, inst.dst, error) || + !DecodeScalarSource(fields.src0 + (fields.s0 == 0u ? 256u : 0u), pc, inst.src0, error) || + !DecodeScalarSource(vsrc1 + (fields.s1 == 0u ? 256u : 0u), pc, inst.src1, error)) { return false; } - inst->dst.sdwa_sel = fields.dst_sel; - inst->dst.sdwa_dst_unused = fields.dst_u; - inst->dst.clamp = fields.clamp != 0u; - inst->dst.omod = fields.omod; - inst->src0.sdwa_sel = fields.src0_sel; - inst->src0.sdwa_sext = fields.src0_sext != 0u; - inst->src0.negate = fields.src0_neg != 0u; - inst->src0.absolute = fields.src0_abs != 0u; - inst->src1.sdwa_sel = fields.src1_sel; - inst->src1.sdwa_sext = fields.src1_sext != 0u; - inst->src1.negate = fields.src1_neg != 0u; - inst->src1.absolute = fields.src1_abs != 0u; + inst.dst.sdwa_sel = fields.dst_sel; + inst.dst.sdwa_dst_unused = fields.dst_u; + inst.dst.clamp = fields.clamp != 0u; + inst.dst.omod = fields.omod; + inst.src0.sdwa_sel = fields.src0_sel; + inst.src0.sdwa_sext = fields.src0_sext != 0u; + inst.src0.negate = fields.src0_neg != 0u; + inst.src0.absolute = fields.src0_abs != 0u; + inst.src1.sdwa_sel = fields.src1_sel; + inst.src1.sdwa_sext = fields.src1_sext != 0u; + inst.src1.negate = fields.src1_neg != 0u; + inst.src1.absolute = fields.src1_abs != 0u; return FinalizeVop2Instruction(pc, code, word_index, inst, error); } bool DecodeVop2Dpp(uint32_t pc, std::span code, uint32_t word_index, - uint32_t opcode, uint32_t vdst, uint32_t vsrc1, Instruction* inst, + uint32_t opcode, uint32_t vdst, uint32_t vsrc1, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { @@ -982,25 +982,25 @@ bool DecodeVop2Dpp(uint32_t pc, std::span code, uint32_t word_in const auto src0 = modifier & 0xffu; SetRawWords(inst, code, word_index, 2); - if (!DecodeVectorGpr(vdst, &inst->dst, error) || - !DecodeScalarSource(src0 + 256u, pc, &inst->src0, error) || - !DecodeVectorGpr(vsrc1, &inst->src1, error)) { + if (!DecodeVectorGpr(vdst, inst.dst, error) || + !DecodeScalarSource(src0 + 256u, pc, inst.src0, error) || + !DecodeVectorGpr(vsrc1, inst.src1, error)) { return false; } ApplyDefaultVop2F16Destination(inst); - inst->src0.negate = ((modifier >> 20u) & 0x1u) != 0u; - inst->src0.absolute = ((modifier >> 21u) & 0x1u) != 0u; - inst->src0.dpp = true; - inst->src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu; - inst->src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u; - inst->src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u; - inst->src0.dpp_bank_mask = (modifier >> 24u) & 0xfu; - inst->src0.dpp_row_mask = (modifier >> 28u) & 0xfu; - inst->src1.negate = ((modifier >> 22u) & 0x1u) != 0u; - inst->src1.absolute = ((modifier >> 23u) & 0x1u) != 0u; + inst.src0.negate = ((modifier >> 20u) & 0x1u) != 0u; + inst.src0.absolute = ((modifier >> 21u) & 0x1u) != 0u; + inst.src0.dpp = true; + inst.src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu; + inst.src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u; + inst.src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u; + inst.src0.dpp_bank_mask = (modifier >> 24u) & 0xfu; + inst.src0.dpp_row_mask = (modifier >> 28u) & 0xfu; + inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u; + inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u; - if (!IsVop2FloatSourceOpcode(inst->opcode) && - (inst->src0.negate || inst->src0.absolute || inst->src1.negate || inst->src1.absolute)) { + if (!IsVop2FloatSourceOpcode(inst.opcode) && + (inst.src0.negate || inst.src0.absolute || inst.src1.negate || inst.src1.absolute)) { SetUnsupported(inst, Family::VOP2, opcode, "VOP2 DPP integer source modifiers are not supported"); return true; @@ -1010,7 +1010,7 @@ bool DecodeVop2Dpp(uint32_t pc, std::span code, uint32_t word_in using Vop2ModifierDecodeFn = bool (*)(uint32_t pc, std::span code, uint32_t word_index, uint32_t opcode, uint32_t vdst, - uint32_t vsrc1, Instruction* inst, std::string* error); + uint32_t vsrc1, Instruction& inst, std::string* error); struct Vop2ModifierDecoder { uint32_t escape = 0; @@ -1024,7 +1024,7 @@ constexpr Vop2ModifierDecoder VOP2_MODIFIER_DECODERS[] = { bool TryDecodeVop2Modifier(uint32_t pc, std::span code, uint32_t word_index, uint32_t src0, uint32_t opcode, uint32_t vdst, uint32_t vsrc1, - Instruction* inst, std::string* error, bool* handled) { + Instruction& inst, std::string* error, bool* handled) { if (handled != nullptr) { *handled = false; } @@ -1078,7 +1078,7 @@ bool SupportsVopcSdwa(Opcode opcode) { } bool DecodeVopcSdwa(uint32_t pc, std::span code, uint32_t word_index, - uint32_t opcode, uint32_t vsrc1, Instruction* inst, std::string* error) { + uint32_t opcode, uint32_t vsrc1, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { *error = fmt::format("truncated VOPC SDWA instruction at pc 0x{:08x}", pc); @@ -1093,37 +1093,37 @@ bool DecodeVopcSdwa(uint32_t pc, std::span code, uint32_t word_i SetUnsupported(inst, Family::VOPC, opcode, "VOPC SDWA selector is invalid"); return true; } - if (!SupportsVopcSdwa(inst->opcode)) { + if (!SupportsVopcSdwa(inst.opcode)) { SetUnsupported(inst, Family::VOPC, opcode, "VOPC SDWA modifier is not supported for opcode"); return true; } - if (!DecodeScalarSource(fields.src0 + (fields.s0 == 0u ? 256u : 0u), pc, &inst->src0, error) || - !DecodeScalarSource(vsrc1 + (fields.s1 == 0u ? 256u : 0u), pc, &inst->src1, error)) { + if (!DecodeScalarSource(fields.src0 + (fields.s0 == 0u ? 256u : 0u), pc, inst.src0, error) || + !DecodeScalarSource(vsrc1 + (fields.s1 == 0u ? 256u : 0u), pc, inst.src1, error)) { return false; } - if (IsVopcCompareExec(inst->opcode)) { - inst->dst.kind = OperandKind::ExecLo; + if (IsVopcCompareExec(inst.opcode)) { + inst.dst.kind = OperandKind::ExecLo; } else if (fields.sd == 0u) { - inst->dst.kind = OperandKind::VccLo; - } else if (!DecodeScalarDestination(fields.sdst, pc, &inst->dst, error)) { + inst.dst.kind = OperandKind::VccLo; + } else if (!DecodeScalarDestination(fields.sdst, pc, inst.dst, error)) { return false; } - inst->src0.sdwa_sel = fields.src0_sel; - inst->src0.sdwa_sext = fields.src0_sext != 0u; - inst->src0.negate = fields.src0_neg != 0u; - inst->src0.absolute = fields.src0_abs != 0u; - inst->src1.sdwa_sel = fields.src1_sel; - inst->src1.sdwa_sext = fields.src1_sext != 0u; - inst->src1.negate = fields.src1_neg != 0u; - inst->src1.absolute = fields.src1_abs != 0u; - inst->src_count = 2; + inst.src0.sdwa_sel = fields.src0_sel; + inst.src0.sdwa_sext = fields.src0_sext != 0u; + inst.src0.negate = fields.src0_neg != 0u; + inst.src0.absolute = fields.src0_abs != 0u; + inst.src1.sdwa_sel = fields.src1_sel; + inst.src1.sdwa_sext = fields.src1_sext != 0u; + inst.src1.negate = fields.src1_neg != 0u; + inst.src1.absolute = fields.src1_abs != 0u; + inst.src_count = 2; return ReadLiteralOperands(code, word_index, inst, error); } bool DecodeVopcDpp(uint32_t pc, std::span code, uint32_t word_index, - uint32_t opcode, uint32_t vsrc1, Instruction* inst, std::string* error) { + uint32_t opcode, uint32_t vsrc1, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { *error = fmt::format("truncated VOPC DPP instruction at pc 0x{:08x}", pc); @@ -1134,26 +1134,26 @@ bool DecodeVopcDpp(uint32_t pc, std::span code, uint32_t word_in const auto modifier = code[word_index + 1u]; const auto src0 = modifier & 0xffu; SetRawWords(inst, code, word_index, 2); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::VOPC, opcode, "VOPC opcode is not implemented"); return true; } - if (!DecodeScalarSource(src0 + 256u, pc, &inst->src0, error) || - !DecodeVectorGpr(vsrc1, &inst->src1, error)) { + if (!DecodeScalarSource(src0 + 256u, pc, inst.src0, error) || + !DecodeVectorGpr(vsrc1, inst.src1, error)) { return false; } - inst->dst.kind = IsVopcCompareExec(inst->opcode) ? OperandKind::ExecLo : OperandKind::VccLo; - inst->src0.negate = ((modifier >> 20u) & 0x1u) != 0u; - inst->src0.absolute = ((modifier >> 21u) & 0x1u) != 0u; - inst->src0.dpp = true; - inst->src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu; - inst->src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u; - inst->src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u; - inst->src0.dpp_bank_mask = (modifier >> 24u) & 0xfu; - inst->src0.dpp_row_mask = (modifier >> 28u) & 0xfu; - inst->src1.negate = ((modifier >> 22u) & 0x1u) != 0u; - inst->src1.absolute = ((modifier >> 23u) & 0x1u) != 0u; - inst->src_count = 2; + inst.dst.kind = IsVopcCompareExec(inst.opcode) ? OperandKind::ExecLo : OperandKind::VccLo; + inst.src0.negate = ((modifier >> 20u) & 0x1u) != 0u; + inst.src0.absolute = ((modifier >> 21u) & 0x1u) != 0u; + inst.src0.dpp = true; + inst.src0.dpp_ctrl = (modifier >> 8u) & 0x1ffu; + inst.src0.dpp_fetch_inactive = ((modifier >> 18u) & 0x1u) != 0u; + inst.src0.dpp_bound_ctrl = ((modifier >> 19u) & 0x1u) != 0u; + inst.src0.dpp_bank_mask = (modifier >> 24u) & 0xfu; + inst.src0.dpp_row_mask = (modifier >> 28u) & 0xfu; + inst.src1.negate = ((modifier >> 22u) & 0x1u) != 0u; + inst.src1.absolute = ((modifier >> 23u) & 0x1u) != 0u; + inst.src_count = 2; return ReadLiteralOperands(code, word_index, inst, error); } @@ -1229,9 +1229,9 @@ bool IsMadMixF16(Opcode opcode) { return opcode == Opcode::VMadMixloF16 || opcode == Opcode::VMadMixhiF16; } -void ApplyVop3pSourceModifiers(Instruction* inst, uint32_t op_sel, uint32_t op_sel_hi, uint32_t neg, +void ApplyVop3pSourceModifiers(Instruction& inst, uint32_t op_sel, uint32_t op_sel_hi, uint32_t neg, uint32_t neg_hi) { - Operand* sources[] = {&inst->src0, &inst->src1, &inst->src2}; + Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2}; for (uint32_t i = 0; i < 3u; i++) { sources[i]->op_sel = ((op_sel >> i) & 1u) != 0; sources[i]->op_sel_hi = ((op_sel_hi >> i) & 1u) != 0; @@ -1240,8 +1240,8 @@ void ApplyVop3pSourceModifiers(Instruction* inst, uint32_t op_sel, uint32_t op_s } } -void ApplyVop3pMixAbsModifiers(Instruction* inst) { - Operand* sources[] = {&inst->src0, &inst->src1, &inst->src2}; +void ApplyVop3pMixAbsModifiers(Instruction& inst) { + Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2}; for (auto* source: sources) { // RDNA2 MIX opcodes reuse the VOP3P NEG_HI bits as source absolute modifiers. source->absolute = source->negate_hi; @@ -1249,44 +1249,44 @@ void ApplyVop3pMixAbsModifiers(Instruction* inst) { } } -void ApplyNativeVop3MadMixModifiers(Instruction* inst, uint32_t op_sel, uint32_t abs, +void ApplyNativeVop3MadMixModifiers(Instruction& inst, uint32_t op_sel, uint32_t abs, uint32_t neg) { - Operand* sources[] = {&inst->src0, &inst->src1, &inst->src2}; + Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2}; for (uint32_t i = 0; i < 3u; i++) { sources[i]->op_sel = ((op_sel >> i) & 1u) != 0; sources[i]->op_sel_hi = true; sources[i]->negate = ((neg >> i) & 1u) != 0; sources[i]->absolute = ((abs >> i) & 1u) != 0; } - inst->dst.sdwa_sel = ((op_sel & 0x8u) != 0) ? 5u : 4u; + inst.dst.sdwa_sel = ((op_sel & 0x8u) != 0) ? 5u : 4u; } -void ApplyNativeVop3F16TernaryModifiers(Instruction* inst, uint32_t op_sel, uint32_t abs, +void ApplyNativeVop3F16TernaryModifiers(Instruction& inst, uint32_t op_sel, uint32_t abs, uint32_t neg) { - Operand* sources[] = {&inst->src0, &inst->src1, &inst->src2}; + Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2}; for (uint32_t i = 0; i < 3u; i++) { sources[i]->op_sel = ((op_sel >> i) & 1u) != 0; sources[i]->op_sel_hi = true; sources[i]->negate = ((neg >> i) & 1u) != 0; sources[i]->absolute = ((abs >> i) & 1u) != 0; } - inst->dst.sdwa_sel = ((op_sel & 0x8u) != 0) ? 5u : 4u; + inst.dst.sdwa_sel = ((op_sel & 0x8u) != 0) ? 5u : 4u; } -void ApplyNativeVop3B16BinaryModifiers(Instruction* inst, uint32_t op_sel) { - inst->src0.op_sel = (op_sel & 0x1u) != 0; - inst->src1.op_sel = (op_sel & 0x2u) != 0; - inst->dst.sdwa_sel = (op_sel & 0x8u) != 0 ? 5u : 4u; +void ApplyNativeVop3B16BinaryModifiers(Instruction& inst, uint32_t op_sel) { + inst.src0.op_sel = (op_sel & 0x1u) != 0; + inst.src1.op_sel = (op_sel & 0x2u) != 0; + inst.dst.sdwa_sel = (op_sel & 0x8u) != 0 ? 5u : 4u; } -void ApplyNativeVop3PackB32F16Modifiers(Instruction* inst, uint32_t op_sel, uint32_t abs, +void ApplyNativeVop3PackB32F16Modifiers(Instruction& inst, uint32_t op_sel, uint32_t abs, uint32_t neg) { - inst->src0.op_sel = (op_sel & 0x1u) != 0; - inst->src1.op_sel = (op_sel & 0x2u) != 0; - inst->src0.negate = (neg & 0x1u) != 0; - inst->src1.negate = (neg & 0x2u) != 0; - inst->src0.absolute = (abs & 0x1u) != 0; - inst->src1.absolute = (abs & 0x2u) != 0; + inst.src0.op_sel = (op_sel & 0x1u) != 0; + inst.src1.op_sel = (op_sel & 0x2u) != 0; + inst.src0.negate = (neg & 0x1u) != 0; + inst.src1.negate = (neg & 0x2u) != 0; + inst.src0.absolute = (abs & 0x1u) != 0; + inst.src1.absolute = (abs & 0x2u) != 0; } bool SupportsNativeVop3SourceModifiers(Opcode opcode) { @@ -1390,9 +1390,9 @@ bool HasUnsupportedNativeVop3Modifiers(Opcode opcode, bool permlane, bool mad_mi return abs != 0u || op_sel != 0u || clamp != 0u || omod != 0u || neg != 0u; } -void ApplyNativeVop3SourceModifiers(Instruction* inst, uint32_t abs, uint32_t neg) { - Operand* sources[] = {&inst->src0, &inst->src1, &inst->src2}; - for (uint32_t i = 0; i < inst->src_count && i < 3u; i++) { +void ApplyNativeVop3SourceModifiers(Instruction& inst, uint32_t abs, uint32_t neg) { + Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2}; + for (uint32_t i = 0; i < inst.src_count && i < 3u; i++) { sources[i]->absolute = ((abs >> i) & 1u) != 0; sources[i]->negate = ((neg >> i) & 1u) != 0; } @@ -1437,7 +1437,7 @@ bool IsVopcCompareExec(Opcode opcode) { } // namespace -bool DecodeVop2(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeVop2(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { const uint32_t word = code[word_index]; const uint32_t opcode = (word >> 25u) & 0x3fu; @@ -1445,11 +1445,11 @@ bool DecodeVop2(uint32_t pc, std::span code, uint32_t word_index const uint32_t src0 = word & 0x1ffu; const uint32_t vsrc1 = (word >> 9u) & 0xffu; - inst->pc = pc; - inst->word = word; - inst->family = Family::VOP2; - inst->opcode_id = opcode; - inst->opcode = Lookup(VOP2_OPS, static_cast(std::size(VOP2_OPS)), opcode); + inst.pc = pc; + inst.word = word; + inst.family = Family::VOP2; + inst.opcode_id = opcode; + inst.opcode = Lookup(VOP2_OPS, static_cast(std::size(VOP2_OPS)), opcode); SetRawWords(inst, code, word_index, 1); switch (opcode) { @@ -1457,7 +1457,7 @@ bool DecodeVop2(uint32_t pc, std::span code, uint32_t word_index case 0x3fu: return DecodeVop1(pc, code, word_index, inst, error); default: break; } - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::VOP2, opcode, "VOP2 opcode is not implemented"); return true; } @@ -1470,36 +1470,36 @@ bool DecodeVop2(uint32_t pc, std::span code, uint32_t word_index return true; } - if (!DecodeVectorGpr(vdst, &inst->dst, error) || - !DecodeScalarSource(src0, pc, &inst->src0, error) || - !DecodeVectorGpr(vsrc1, &inst->src1, error)) { + if (!DecodeVectorGpr(vdst, inst.dst, error) || + !DecodeScalarSource(src0, pc, inst.src0, error) || + !DecodeVectorGpr(vsrc1, inst.src1, error)) { return false; } ApplyDefaultVop2F16Destination(inst); return FinalizeVop2Instruction(pc, code, word_index, inst, error); } -bool DecodeVop1(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeVop1(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { const uint32_t word = code[word_index]; const uint32_t opcode = (word >> 9u) & 0xffu; const uint32_t src0 = word & 0x1ffu; const uint32_t vdst = (word >> 17u) & 0xffu; - inst->pc = pc; - inst->word = word; - inst->family = Family::VOP1; - inst->opcode_id = opcode; - inst->opcode = Lookup(VOP1_OPS, static_cast(std::size(VOP1_OPS)), opcode); + inst.pc = pc; + inst.word = word; + inst.family = Family::VOP1; + inst.opcode_id = opcode; + inst.opcode = Lookup(VOP1_OPS, static_cast(std::size(VOP1_OPS)), opcode); SetRawWords(inst, code, word_index, 1); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::VOP1, opcode, "VOP1 opcode is not implemented"); return true; } - if (inst->opcode == Opcode::VNop) { - inst->dst.kind = OperandKind::Null; - inst->src_count = 0; + if (inst.opcode == Opcode::VNop) { + inst.dst.kind = OperandKind::Null; + inst.src_count = 0; return true; } bool modifier_handled = false; @@ -1510,29 +1510,29 @@ bool DecodeVop1(uint32_t pc, std::span code, uint32_t word_index if (modifier_handled) { return true; } - const bool scalar_dst = UsesScalarDestination(inst->opcode); - if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, &inst->dst, error) - : DecodeVectorGpr(vdst, &inst->dst, error)) || - !DecodeScalarSource(src0, pc, &inst->src0, error)) { + const bool scalar_dst = UsesScalarDestination(inst.opcode); + if (!(scalar_dst ? DecodeScalarDestination(vdst, pc, inst.dst, error) + : DecodeVectorGpr(vdst, inst.dst, error)) || + !DecodeScalarSource(src0, pc, inst.src0, error)) { return false; } - inst->src_count = 1; + inst.src_count = 1; return ReadLiteralOperands(code, word_index, inst, error); } -bool DecodeVopc(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeVopc(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { const uint32_t word = code[word_index]; const uint32_t opcode = (word >> 17u) & 0xffu; const uint32_t src0 = word & 0x1ffu; const uint32_t vsrc1 = (word >> 9u) & 0xffu; - inst->pc = pc; - inst->word = word; - inst->family = Family::VOPC; - inst->opcode_id = opcode; - inst->opcode = Lookup(VOPC_OPS, static_cast(std::size(VOPC_OPS)), opcode); - inst->dst.kind = IsVopcCompareExec(inst->opcode) ? OperandKind::ExecLo : OperandKind::VccLo; + inst.pc = pc; + inst.word = word; + inst.family = Family::VOPC; + inst.opcode_id = opcode; + inst.opcode = Lookup(VOPC_OPS, static_cast(std::size(VOPC_OPS)), opcode); + inst.dst.kind = IsVopcCompareExec(inst.opcode) ? OperandKind::ExecLo : OperandKind::VccLo; SetRawWords(inst, code, word_index, 1); switch (src0) { @@ -1540,19 +1540,19 @@ bool DecodeVopc(uint32_t pc, std::span code, uint32_t word_index case 250u: return DecodeVopcDpp(pc, code, word_index, opcode, vsrc1, inst, error); default: break; } - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::VOPC, opcode, "VOPC opcode is not implemented"); return true; } - if (!DecodeScalarSource(src0, pc, &inst->src0, error) || - !DecodeVectorGpr(vsrc1, &inst->src1, error)) { + if (!DecodeScalarSource(src0, pc, inst.src0, error) || + !DecodeVectorGpr(vsrc1, inst.src1, error)) { return false; } - inst->src_count = 2; + inst.src_count = 2; return ReadLiteralOperands(code, word_index, inst, error); } -bool DecodeVop3(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeVop3(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { @@ -1575,30 +1575,30 @@ bool DecodeVop3(uint32_t pc, std::span code, uint32_t word_index const uint32_t omod = (word1 >> 27u) & 0x3u; const uint32_t neg = (word1 >> 29u) & 0x7u; - inst->pc = pc; - inst->word = word0; - inst->family = Family::VOP3; - inst->opcode_id = opcode; - inst->opcode = LookupVop3Opcode(opcode); + inst.pc = pc; + inst.word = word0; + inst.family = Family::VOP3; + inst.opcode_id = opcode; + inst.opcode = LookupVop3Opcode(opcode); SetRawWords(inst, code, word_index, 2); - const bool addc = inst->opcode == Opcode::VAddcU32 && opcode == 0x128u; - const bool vop3b_carry_out = IsVop3BCarryOutOpcode(inst->opcode); - const bool vop3b_mad_u64 = IsVop3BMadU64Opcode(inst->opcode); + const bool addc = inst.opcode == Opcode::VAddcU32 && opcode == 0x128u; + const bool vop3b_carry_out = IsVop3BCarryOutOpcode(inst.opcode); + const bool vop3b_mad_u64 = IsVop3BMadU64Opcode(inst.opcode); const bool vop3b_uses_sdst = addc || vop3b_carry_out || vop3b_mad_u64; const bool mad_mix = false; - const bool f16_ternary = IsNativeVop3F16TernaryOpcode(inst->opcode); - const bool b16_binary = IsNativeVop3B16BinaryOpcode(inst->opcode); - const bool pack_b32_f16 = inst->opcode == Opcode::VPackB32F16; - const bool permlane = IsPermlaneOpcode(inst->opcode); + const bool f16_ternary = IsNativeVop3F16TernaryOpcode(inst.opcode); + const bool b16_binary = IsNativeVop3B16BinaryOpcode(inst.opcode); + const bool pack_b32_f16 = inst.opcode == Opcode::VPackB32F16; + const bool permlane = IsPermlaneOpcode(inst.opcode); const bool vop3_vopc = IsVop3EncodedVopc(opcode); - const bool compare_exec = vop3_vopc && IsVopcCompareExec(inst->opcode); - const bool scalar_dst = vop3_vopc || UsesScalarDestination(inst->opcode); - const bool scalar_modifier_limits = UsesScalarDestination(inst->opcode); - const bool native_source_modifiers = SupportsNativeVop3SourceModifiers(inst->opcode); - const bool native_result_modifiers = SupportsNativeVop3ResultModifiers(inst->opcode); + const bool compare_exec = vop3_vopc && IsVopcCompareExec(inst.opcode); + const bool scalar_dst = vop3_vopc || UsesScalarDestination(inst.opcode); + const bool scalar_modifier_limits = UsesScalarDestination(inst.opcode); + const bool native_source_modifiers = SupportsNativeVop3SourceModifiers(inst.opcode); + const bool native_result_modifiers = SupportsNativeVop3ResultModifiers(inst.opcode); const bool modifiers = - HasUnsupportedNativeVop3Modifiers(inst->opcode, permlane, mad_mix, vop3b_uses_sdst, + HasUnsupportedNativeVop3Modifiers(inst.opcode, permlane, mad_mix, vop3b_uses_sdst, scalar_modifier_limits, abs, op_sel, clamp, omod, neg); if (modifiers) { SetUnsupported(inst, Family::VOP3, opcode, @@ -1608,98 +1608,98 @@ bool DecodeVop3(uint32_t pc, std::span code, uint32_t word_index : "VOP3 source modifiers are not implemented"); return true; } - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::VOP3, opcode, "VOP3 opcode is not implemented"); return true; } - if (inst->opcode == Opcode::VNop) { - inst->dst.kind = OperandKind::Null; - inst->src_count = 0; + if (inst.opcode == Opcode::VNop) { + inst.dst.kind = OperandKind::Null; + inst.src_count = 0; return true; } bool dst_ok = true; if (compare_exec) { - inst->dst.kind = OperandKind::ExecLo; + inst.dst.kind = OperandKind::ExecLo; } else if (scalar_dst) { // VOP3A uses VDST for VOPC and the scalar-destination lane-read opcodes. - dst_ok = DecodeScalarDestination(vdst, pc, &inst->dst, error); + dst_ok = DecodeScalarDestination(vdst, pc, inst.dst, error); } else { - dst_ok = DecodeVectorGpr(vdst, &inst->dst, error); + dst_ok = DecodeVectorGpr(vdst, inst.dst, error); } - if (!dst_ok || !DecodeScalarSource(src0, pc, &inst->src0, error)) { + if (!dst_ok || !DecodeScalarSource(src0, pc, inst.src0, error)) { return false; } - inst->dst.clamp = native_result_modifiers && clamp != 0u; - inst->dst.omod = native_result_modifiers ? omod : 0u; + inst.dst.clamp = native_result_modifiers && clamp != 0u; + inst.dst.omod = native_result_modifiers ? omod : 0u; if (permlane) { - inst->dst.op_sel = (op_sel & 0x1u) != 0u; - inst->dst.op_sel_hi = (op_sel & 0x2u) != 0u; + inst.dst.op_sel = (op_sel & 0x1u) != 0u; + inst.dst.op_sel_hi = (op_sel & 0x2u) != 0u; } if (vop3_vopc) { - if (!DecodeScalarSource(src1, pc, &inst->src1, error)) { + if (!DecodeScalarSource(src1, pc, inst.src1, error)) { return false; } - inst->src_count = 2; + inst.src_count = 2; if (native_source_modifiers) { ApplyNativeVop3SourceModifiers(inst, abs, neg); } return ReadLiteralOperands(code, word_index, inst, error); } if (IsVop3EncodedVop1(opcode)) { - inst->src_count = 1; + inst.src_count = 1; if (native_source_modifiers) { ApplyNativeVop3SourceModifiers(inst, abs, neg); } return ReadLiteralOperands(code, word_index, inst, error); } if (addc) { - if (!DecodeScalarDestination(sdst, pc, &inst->dst2, error) || - !DecodeScalarSource(src1, pc, &inst->src1, error) || - !DecodeScalarSource(src2, pc, &inst->src2, error)) { + if (!DecodeScalarDestination(sdst, pc, inst.dst2, error) || + !DecodeScalarSource(src1, pc, inst.src1, error) || + !DecodeScalarSource(src2, pc, inst.src2, error)) { return false; } - inst->src_count = 3; + inst.src_count = 3; return ReadLiteralOperands(code, word_index, inst, error); } if (vop3b_carry_out) { - if (!DecodeScalarDestination(sdst, pc, &inst->dst2, error) || - !DecodeScalarSource(src1, pc, &inst->src1, error)) { + if (!DecodeScalarDestination(sdst, pc, inst.dst2, error) || + !DecodeScalarSource(src1, pc, inst.src1, error)) { return false; } - inst->src_count = 2; + inst.src_count = 2; return ReadLiteralOperands(code, word_index, inst, error); } if (vop3b_mad_u64) { - if (!DecodeScalarDestination(sdst, pc, &inst->dst2, error) || - !DecodeScalarSource(src1, pc, &inst->src1, error) || - !DecodeScalarSource(src2, pc, &inst->src2, error)) { + if (!DecodeScalarDestination(sdst, pc, inst.dst2, error) || + !DecodeScalarSource(src1, pc, inst.src1, error) || + !DecodeScalarSource(src2, pc, inst.src2, error)) { return false; } - inst->src_count = 3; + inst.src_count = 3; return ReadLiteralOperands(code, word_index, inst, error); } if (IsVop3EncodedVop2(opcode)) { - if (!DecodeScalarSource(src1, pc, &inst->src1, error)) { + if (!DecodeScalarSource(src1, pc, inst.src1, error)) { return false; } - if (inst->opcode == Opcode::VCndmaskB32) { - if (!DecodeScalarSource(src2, pc, &inst->src2, error)) { + if (inst.opcode == Opcode::VCndmaskB32) { + if (!DecodeScalarSource(src2, pc, inst.src2, error)) { return false; } - inst->src_count = 3; + inst.src_count = 3; } else { - inst->src_count = 2; + inst.src_count = 2; } if (native_source_modifiers) { ApplyNativeVop3SourceModifiers(inst, abs, neg); } return ReadLiteralOperands(code, word_index, inst, error); } - if (!DecodeScalarSource(src1, pc, &inst->src1, error)) { + if (!DecodeScalarSource(src1, pc, inst.src1, error)) { return false; } - inst->src_count = NativeVop3SourceCount(inst->opcode); - if (inst->src_count > 2u && !DecodeScalarSource(src2, pc, &inst->src2, error)) { + inst.src_count = NativeVop3SourceCount(inst.opcode); + if (inst.src_count > 2u && !DecodeScalarSource(src2, pc, inst.src2, error)) { return false; } if (mad_mix) { @@ -1717,7 +1717,7 @@ bool DecodeVop3(uint32_t pc, std::span code, uint32_t word_index } bool DecodeVop3p(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error) { + Instruction& inst, std::string* error) { if (word_index + 1u >= code.size()) { if (error != nullptr) { *error = fmt::format("truncated VOP3P instruction at pc 0x{:08x}", pc); @@ -1739,51 +1739,51 @@ bool DecodeVop3p(uint32_t pc, std::span code, uint32_t word_inde const uint32_t op_sel_hi = ((word1 >> 27u) & 0x3u) | (op_sel_hi_2 << 2u); const uint32_t neg = (word1 >> 29u) & 0x7u; - inst->pc = pc; - inst->word = word0; - inst->family = Family::VOP3P; - inst->opcode_id = opcode; - inst->opcode = Lookup(VOP3P_OPS, static_cast(std::size(VOP3P_OPS)), opcode); + inst.pc = pc; + inst.word = word0; + inst.family = Family::VOP3P; + inst.opcode_id = opcode; + inst.opcode = Lookup(VOP3P_OPS, static_cast(std::size(VOP3P_OPS)), opcode); SetRawWords(inst, code, word_index, 2); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::VOP3P, opcode, "VOP3P opcode is not implemented"); return true; } - inst->src_count = Vop3pSourceCount(inst->opcode); - if (!DecodeVectorGpr(vdst, &inst->dst, error) || - !DecodeScalarSource(src0, pc, &inst->src0, error) || - !DecodeScalarSource(src1, pc, &inst->src1, error)) { + inst.src_count = Vop3pSourceCount(inst.opcode); + if (!DecodeVectorGpr(vdst, inst.dst, error) || + !DecodeScalarSource(src0, pc, inst.src0, error) || + !DecodeScalarSource(src1, pc, inst.src1, error)) { return false; } - if (inst->src_count > 2u && !DecodeScalarSource(src2, pc, &inst->src2, error)) { + if (inst.src_count > 2u && !DecodeScalarSource(src2, pc, inst.src2, error)) { return false; } - if (inst->opcode == Opcode::VFmaF32) { - inst->dst.clamp = clamp != 0u; - } else if (IsMadMixF16(inst->opcode)) { - inst->dst.clamp = clamp != 0u; - } else if (IsPackedVop3p(inst->opcode)) { - inst->dst.clamp = clamp != 0u; + if (inst.opcode == Opcode::VFmaF32) { + inst.dst.clamp = clamp != 0u; + } else if (IsMadMixF16(inst.opcode)) { + inst.dst.clamp = clamp != 0u; + } else if (IsPackedVop3p(inst.opcode)) { + inst.dst.clamp = clamp != 0u; } else if (clamp != 0u) { SetUnsupported(inst, Family::VOP3P, opcode, "VOP3P integer clamp is not implemented"); return true; } ApplyVop3pSourceModifiers(inst, op_sel, op_sel_hi, neg, neg_hi); - if (inst->opcode == Opcode::VMadMixloF16) { + if (inst.opcode == Opcode::VMadMixloF16) { ApplyVop3pMixAbsModifiers(inst); - inst->dst.sdwa_sel = 4; - } else if (inst->opcode == Opcode::VMadMixhiF16) { + inst.dst.sdwa_sel = 4; + } else if (inst.opcode == Opcode::VMadMixhiF16) { ApplyVop3pMixAbsModifiers(inst); - inst->dst.sdwa_sel = 5; - } else if (inst->opcode == Opcode::VFmaF32) { + inst.dst.sdwa_sel = 5; + } else if (inst.opcode == Opcode::VFmaF32) { ApplyVop3pMixAbsModifiers(inst); } return ReadLiteralOperands(code, word_index, inst, error); } bool DecodeVintrp(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error) { + Instruction& inst, std::string* error) { if (word_index >= code.size()) { if (error != nullptr) { *error = fmt::format("truncated VINTRP instruction at pc 0x{:08x}", pc); @@ -1798,35 +1798,35 @@ bool DecodeVintrp(uint32_t pc, std::span code, uint32_t word_ind const uint32_t chan = (word >> 8u) & 0x3u; const uint32_t vsrc = word & 0xffu; - inst->pc = pc; - inst->word = word; - inst->word_count = 1; - inst->family = Family::VINTRP; - inst->opcode_id = opcode; - inst->opcode = LookupVintrpOpcode(opcode); + inst.pc = pc; + inst.word = word; + inst.word_count = 1; + inst.family = Family::VINTRP; + inst.opcode_id = opcode; + inst.opcode = LookupVintrpOpcode(opcode); SetRawWords(inst, code, word_index, 1); - if (inst->opcode == Opcode::Unsupported) { + if (inst.opcode == Opcode::Unsupported) { SetUnsupported(inst, Family::VINTRP, opcode, "VINTRP opcode is not implemented"); return true; } - if (!DecodeVectorGpr(vdst, &inst->dst, error)) { + if (!DecodeVectorGpr(vdst, inst.dst, error)) { return false; } - if (inst->opcode == Opcode::VInterpMovF32) { - inst->src0.kind = OperandKind::IntegerInlineConstant; - inst->src0.value = vsrc & 0x3u; - inst->src0.signed_val = static_cast(inst->src0.value); - } else if (!DecodeVectorGpr(vsrc, &inst->src0, error)) { + if (inst.opcode == Opcode::VInterpMovF32) { + inst.src0.kind = OperandKind::IntegerInlineConstant; + inst.src0.value = vsrc & 0x3u; + inst.src0.signed_val = static_cast(inst.src0.value); + } else if (!DecodeVectorGpr(vsrc, inst.src0, error)) { return false; } - inst->src1.kind = OperandKind::IntegerInlineConstant; - inst->src1.value = attr; - inst->src1.signed_val = static_cast(attr); - inst->src2.kind = OperandKind::IntegerInlineConstant; - inst->src2.value = chan; - inst->src2.signed_val = static_cast(chan); - inst->src_count = 3; + inst.src1.kind = OperandKind::IntegerInlineConstant; + inst.src1.value = attr; + inst.src1.signed_val = static_cast(attr); + inst.src2.kind = OperandKind::IntegerInlineConstant; + inst.src2.value = chan; + inst.src2.signed_val = static_cast(chan); + inst.src_count = 3; return true; } diff --git a/src/graphics/shader/recompiler/VectorAluOps.h b/src/graphics/shader/recompiler/VectorAluOps.h index c7009fa23..dabb465d8 100644 --- a/src/graphics/shader/recompiler/VectorAluOps.h +++ b/src/graphics/shader/recompiler/VectorAluOps.h @@ -5,18 +5,18 @@ namespace Libs::Graphics::ShaderRecompiler::Decoder { -bool DecodeVop2(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeVop2(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); -bool DecodeVop1(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeVop1(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); -bool DecodeVopc(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeVopc(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); -bool DecodeVop3(uint32_t pc, std::span code, uint32_t word_index, Instruction* inst, +bool DecodeVop3(uint32_t pc, std::span code, uint32_t word_index, Instruction& inst, std::string* error); bool DecodeVop3p(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error); + Instruction& inst, std::string* error); bool DecodeVintrp(uint32_t pc, std::span code, uint32_t word_index, - Instruction* inst, std::string* error); + Instruction& inst, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::Decoder diff --git a/src/graphics/shader/recompiler/shaderIR/ShaderIR.cpp b/src/graphics/shader/recompiler/shaderIR/ShaderIR.cpp index 42874addd..73c55dccc 100644 --- a/src/graphics/shader/recompiler/shaderIR/ShaderIR.cpp +++ b/src/graphics/shader/recompiler/shaderIR/ShaderIR.cpp @@ -32,17 +32,17 @@ Operand MakePcRelativeU32(uint32_t value) { return operand; } -bool AppendScalarResultSccNonZero(const Decoder::Instruction& decoded, BasicBlock* block, +bool AppendScalarResultSccNonZero(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { if (!ScalarResultWritesSccNonZero(decoded.opcode)) { return true; } - if (block == nullptr || block->instructions.empty()) { + if (block.instructions.empty()) { SetError(error, "internal IR error: missing scalar result for SCC update"); return false; } - const auto result = block->instructions.back().dst; + const auto result = block.instructions.back().dst; if (result.kind != OperandKind::Register) { SetError(error, "internal IR error: scalar SCC update without register result"); return false; @@ -58,7 +58,7 @@ bool AppendScalarResultSccNonZero(const Decoder::Instruction& decoded, BasicBloc scc_update.src[0] = result; scc_update.src[1] = MakeImmediateU32(0); scc_update.src_count = 2; - block->instructions.push_back(scc_update); + block.instructions.push_back(scc_update); return true; } @@ -90,81 +90,76 @@ void CopyOperandModifiers(const Decoder::Operand& decoded, Operand& operand) { operand.dpp = decoded.dpp; } -bool LowerRegisterOperand(const Decoder::Operand& decoded, Operand* operand, std::string* error) { - if (operand == nullptr) { - SetError(error, "internal IR error: null operand"); - return false; - } - - *operand = {}; - CopyOperandModifiers(decoded, *operand); +bool LowerRegisterOperand(const Decoder::Operand& decoded, Operand& operand, std::string* error) { + operand = {}; + CopyOperandModifiers(decoded, operand); switch (decoded.kind) { case Decoder::OperandKind::Sgpr: - operand->kind = OperandKind::Register; - operand->reg.file = RegisterFile::Scalar; - operand->reg.index = decoded.reg; + operand.kind = OperandKind::Register; + operand.reg.file = RegisterFile::Scalar; + operand.reg.index = decoded.reg; return true; case Decoder::OperandKind::Vgpr: - operand->kind = OperandKind::Register; - operand->reg.file = RegisterFile::Vector; - operand->reg.index = decoded.reg; + operand.kind = OperandKind::Register; + operand.reg.file = RegisterFile::Vector; + operand.reg.index = decoded.reg; return true; case Decoder::OperandKind::VccLo: - operand->kind = OperandKind::Register; - operand->reg.file = RegisterFile::Vcc; - operand->reg.index = 0; + operand.kind = OperandKind::Register; + operand.reg.file = RegisterFile::Vcc; + operand.reg.index = 0; return true; case Decoder::OperandKind::VccHi: - operand->kind = OperandKind::Register; - operand->reg.file = RegisterFile::Vcc; - operand->reg.index = 1; + operand.kind = OperandKind::Register; + operand.reg.file = RegisterFile::Vcc; + operand.reg.index = 1; return true; case Decoder::OperandKind::ExecLo: - operand->kind = OperandKind::Register; - operand->reg.file = RegisterFile::Exec; - operand->reg.index = 0; + operand.kind = OperandKind::Register; + operand.reg.file = RegisterFile::Exec; + operand.reg.index = 0; return true; case Decoder::OperandKind::ExecHi: - operand->kind = OperandKind::Register; - operand->reg.file = RegisterFile::Exec; - operand->reg.index = 1; + operand.kind = OperandKind::Register; + operand.reg.file = RegisterFile::Exec; + operand.reg.index = 1; return true; case Decoder::OperandKind::Scc: case Decoder::OperandKind::VccZ: case Decoder::OperandKind::ExecZ: - operand->kind = OperandKind::Register; - operand->reg.file = RegisterFile::Scc; - operand->reg.index = static_cast(decoded.kind); + operand.kind = OperandKind::Register; + operand.reg.file = RegisterFile::Scc; + operand.reg.index = static_cast(decoded.kind); return true; case Decoder::OperandKind::M0: - operand->kind = OperandKind::Register; - operand->reg.file = RegisterFile::M0; - operand->reg.index = 0; + operand.kind = OperandKind::Register; + operand.reg.file = RegisterFile::M0; + operand.reg.index = 0; return true; - case Decoder::OperandKind::Null: operand->kind = OperandKind::Null; return true; + case Decoder::OperandKind::Null: operand.kind = OperandKind::Null; return true; default: SetError(error, "decoded operand cannot be used as an IR register"); return false; } } -bool LowerSourceOperand(const Decoder::Operand& decoded, Operand* operand, std::string* error) { +bool LowerSourceOperand(const Decoder::Operand& decoded, Operand& operand, std::string* error) { switch (decoded.kind) { case Decoder::OperandKind::LiteralConstant: case Decoder::OperandKind::IntegerInlineConstant: case Decoder::OperandKind::FloatInlineConstant: - *operand = {}; - CopyOperandModifiers(decoded, *operand); - operand->kind = OperandKind::ImmediateU32; - operand->imm = decoded.value; - operand->sext_64 = decoded.kind == Decoder::OperandKind::IntegerInlineConstant && - decoded.signed_val < 0; + operand = {}; + CopyOperandModifiers(decoded, operand); + operand.kind = OperandKind::ImmediateU32; + operand.imm = decoded.value; + operand.sext_64 = decoded.kind == Decoder::OperandKind::IntegerInlineConstant && + decoded.signed_val < 0; return true; case Decoder::OperandKind::Null: case Decoder::OperandKind::PopsExitingWaveId: - *operand = {}; - CopyOperandModifiers(decoded, *operand); - operand->kind = OperandKind::ImmediateU32; - operand->imm = 0; + operand = {}; + CopyOperandModifiers(decoded, operand); + operand.kind = OperandKind::ImmediateU32; + operand.imm = 0; return true; default: return LowerRegisterOperand(decoded, operand, error); } @@ -284,7 +279,7 @@ bool TryOffsetScalarDestination(const Decoder::Operand& operand, uint32_t index, // dword index so s_buffer_load_dwordx2 vcc_lo writes vcc_lo, then vcc_hi. uint32_t code = 0; return TryGetScalarDestinationCode(operand, code) && - Decoder::DecodeScalarDestination(code + index, 0, &decoded, nullptr); + Decoder::DecodeScalarDestination(code + index, 0, decoded, nullptr); } Decoder::Operand OffsetDecodedRegister(const Decoder::Operand& operand, uint32_t index) { @@ -347,16 +342,16 @@ uint32_t TypedBufferFormatComponentCount(const Decoder::Instruction& decoded) { } bool LowerMoveImmediateU32(uint32_t pc, const Decoder::Operand& dst, uint32_t value, - BasicBlock* block, std::string* error) { + BasicBlock& block, std::string* error) { Instruction inst; inst.pc = pc; inst.op = Opcode::MoveU32; inst.src[0] = MakeImmediateU32(value); inst.src_count = 1; - if (!LowerRegisterOperand(dst, &inst.dst, error)) { + if (!LowerRegisterOperand(dst, inst.dst, error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } @@ -405,7 +400,7 @@ Decoder::Operand M0Operand() { namespace { -bool LowerScalarSelect(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerScalarSelect(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Decoder::Operand scc; scc.kind = Decoder::OperandKind::Scc; @@ -413,17 +408,17 @@ bool LowerScalarSelect(const Decoder::Instruction& decoded, BasicBlock* block, s inst.pc = decoded.pc; inst.op = Opcode::SelectU32; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerRegisterOperand(scc, &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error) || - !LowerSourceOperand(decoded.src1, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerRegisterOperand(scc, inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error) || + !LowerSourceOperand(decoded.src1, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerScalarSelect64(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerScalarSelect64(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Decoder::Operand scc; scc.kind = Decoder::OperandKind::Scc; @@ -432,13 +427,13 @@ bool LowerScalarSelect64(const Decoder::Instruction& decoded, BasicBlock* block, inst.pc = decoded.pc; inst.op = Opcode::SelectU64; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerRegisterOperand(scc, &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error) || - !LowerSourceOperand(decoded.src1, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerRegisterOperand(scc, inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error) || + !LowerSourceOperand(decoded.src1, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } @@ -452,7 +447,7 @@ uint32_t ScalarShiftLeftAddAmount(Decoder::Opcode opcode) { } } -bool LowerScalarShiftLeftAdd(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerScalarShiftLeftAdd(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { const auto shift = ScalarShiftLeftAddAmount(decoded.opcode); if (shift == 0) { @@ -466,12 +461,12 @@ bool LowerScalarShiftLeftAdd(const Decoder::Instruction& decoded, BasicBlock* bl inst.src_count = 3; inst.src[1].kind = OperandKind::ImmediateU32; inst.src[1].imm = shift; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } @@ -495,33 +490,33 @@ bool IsScalarMinMaxOpcode(Decoder::Opcode opcode) { } } -bool LowerScalarMinMaxWithScc(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerScalarMinMaxWithScc(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction result; result.pc = decoded.pc; result.op = LookupIrOpcode(decoded.opcode); result.src_count = 2; - if (!LowerRegisterOperand(decoded.dst, &result.dst, error) || - !LowerSourceOperand(decoded.src0, &result.src[0], error) || - !LowerSourceOperand(decoded.src1, &result.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, result.dst, error) || + !LowerSourceOperand(decoded.src0, result.src[0], error) || + !LowerSourceOperand(decoded.src1, result.src[1], error)) { return false; } - block->instructions.push_back(result); + block.instructions.push_back(result); Instruction scc; scc.pc = decoded.pc; scc.op = ScalarMinMaxSccCompareOpcode(decoded.opcode); scc.dst = MakeSccOperand(); scc.src_count = 2; - if (!LowerSourceOperand(decoded.src0, &scc.src[0], error) || - !LowerSourceOperand(decoded.src1, &scc.src[1], error)) { + if (!LowerSourceOperand(decoded.src0, scc.src[0], error) || + !LowerSourceOperand(decoded.src1, scc.src[1], error)) { return false; } - block->instructions.push_back(scc); + block.instructions.push_back(scc); return true; } -bool LowerScalarAddCarry(const Decoder::Instruction& decoded, BasicBlock* block, bool carry_in, +bool LowerScalarAddCarry(const Decoder::Instruction& decoded, BasicBlock& block, bool carry_in, std::string* error) { Decoder::Operand scc; scc.kind = Decoder::OperandKind::Scc; @@ -530,24 +525,24 @@ bool LowerScalarAddCarry(const Decoder::Instruction& decoded, BasicBlock* block, inst.pc = decoded.pc; inst.op = Opcode::ScalarAddCarryU32; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error)) { return false; } if (carry_in) { - if (!LowerRegisterOperand(scc, &inst.src[2], error)) { + if (!LowerRegisterOperand(scc, inst.src[2], error)) { return false; } } else { inst.src[2].kind = OperandKind::ImmediateU32; inst.src[2].imm = 0; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerScalarSubBorrowCarry(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerScalarSubBorrowCarry(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Decoder::Operand scc; scc.kind = Decoder::OperandKind::Scc; @@ -556,62 +551,62 @@ bool LowerScalarSubBorrowCarry(const Decoder::Instruction& decoded, BasicBlock* inst.pc = decoded.pc; inst.op = Opcode::ScalarSubBorrowCarryU32; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error) || - !LowerRegisterOperand(scc, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error) || + !LowerRegisterOperand(scc, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerScalarBinaryScc(const Decoder::Instruction& decoded, BasicBlock* block, Opcode op, +bool LowerScalarBinaryScc(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = op; inst.src_count = 2; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerScalarBitset0B32(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerScalarBitset0B32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::BitClearU32; inst.src_count = 2; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.dst, &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.dst, inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerScalarBitset1B32(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerScalarBitset1B32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::BitSetU32; inst.src_count = 2; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.dst, &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.dst, inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorCndmask(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorCndmask(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Decoder::Operand vcc; vcc.kind = Decoder::OperandKind::VccLo; @@ -624,32 +619,32 @@ bool LowerVectorCndmask(const Decoder::Instruction& decoded, BasicBlock* block, ? Opcode::SelectMaskF32Bits : Opcode::SelectMaskU32; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(mask, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error) || - !LowerSourceOperand(decoded.src0, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(mask, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error) || + !LowerSourceOperand(decoded.src0, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorMoveB32(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorMoveB32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = decoded.src0.negate || decoded.src0.absolute ? Opcode::MoveF32Bits : Opcode::MoveU32; inst.src_count = 1; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error)) { return false; } ApplyDppDestinationMask(decoded, inst.dst); - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorMoveRelSource(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorMoveRelSource(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { if (decoded.dst.kind != Decoder::OperandKind::Vgpr || decoded.src0.kind != Decoder::OperandKind::Vgpr) { @@ -668,16 +663,16 @@ bool LowerVectorMoveRelSource(const Decoder::Instruction& decoded, BasicBlock* b inst.op = Opcode::MoveRelSourceU32; inst.src_count = 2; const auto m0 = M0Operand(); - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(m0, &inst.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(m0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorMoveRelDestination(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorMoveRelDestination(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { if (decoded.dst.kind != Decoder::OperandKind::Vgpr) { SetError(error, "V_MOVRELD_B32 requires VGPR destination"); @@ -695,33 +690,33 @@ bool LowerVectorMoveRelDestination(const Decoder::Instruction& decoded, BasicBlo inst.op = Opcode::MoveRelDestU32; inst.src_count = 2; const auto m0 = M0Operand(); - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(m0, &inst.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(m0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorAddCarry(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorAddCarry(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::IAddCarryU32; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerRegisterOperand(decoded.dst2, &inst.dst2, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error) || - !LowerSourceOperand(decoded.src2, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerRegisterOperand(decoded.dst2, inst.dst2, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error) || + !LowerSourceOperand(decoded.src2, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorCarryOut(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorCarryOut(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -730,100 +725,100 @@ bool LowerVectorCarryOut(const Decoder::Instruction& decoded, BasicBlock* block, inst.src_count = decoded.opcode == Decoder::Opcode::VAddI32 ? 3u : 2u; const auto& src0 = decoded.opcode == Decoder::Opcode::VSubrevI32 ? decoded.src1 : decoded.src0; const auto& src1 = decoded.opcode == Decoder::Opcode::VSubrevI32 ? decoded.src0 : decoded.src1; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerRegisterOperand(decoded.dst2, &inst.dst2, error) || - !LowerSourceOperand(src0, &inst.src[0], error) || - !LowerSourceOperand(src1, &inst.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerRegisterOperand(decoded.dst2, inst.dst2, error) || + !LowerSourceOperand(src0, inst.src[0], error) || + !LowerSourceOperand(src1, inst.src[1], error)) { return false; } if (decoded.opcode == Decoder::Opcode::VAddI32) { inst.src[2] = MakeImmediateU32(0); } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorMadU64U32(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorMadU64U32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::UMadU64U32; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerRegisterOperand(decoded.dst2, &inst.dst2, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error) || - !LowerSourceOperand(decoded.src2, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerRegisterOperand(decoded.dst2, inst.dst2, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error) || + !LowerSourceOperand(decoded.src2, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorMacF32(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerVectorMacF32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::FMadF32; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error) || - !LowerSourceOperand(decoded.dst, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error) || + !LowerSourceOperand(decoded.dst, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorPkFmacF16(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorPkFmacF16(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::PackedFmaF16; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error) || - !LowerSourceOperand(decoded.dst, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error) || + !LowerSourceOperand(decoded.dst, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorFmacF16(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorFmacF16(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::FmaF16; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error) || - !LowerSourceOperand(decoded.dst, &inst.src[2], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error) || + !LowerSourceOperand(decoded.dst, inst.src[2], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorDot2cF32F16(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorDot2cF32F16(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::Dot2AccF32F16; inst.src_count = 3; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error) || - !LowerSourceOperand(decoded.src1, &inst.src[1], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error) || + !LowerSourceOperand(decoded.src1, inst.src[1], error)) { return false; } inst.src[2] = inst.dst; - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVectorByteConvert(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVectorByteConvert(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { const auto byte_index = VectorByteConvertIndex(decoded.opcode); if (byte_index > 3u) { @@ -837,23 +832,23 @@ bool LowerVectorByteConvert(const Decoder::Instruction& decoded, BasicBlock* blo inst.src_count = 2; inst.src[1].kind = OperandKind::ImmediateU32; inst.src[1].imm = byte_index; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVInterpP1F32(const Decoder::Instruction& decoded, BasicBlock* block) { +bool LowerVInterpP1F32(const Decoder::Instruction& decoded, BasicBlock& block) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::ControlNop; - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerVInterpLoadF32(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerVInterpLoadF32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { if (decoded.opcode == Decoder::Opcode::VInterpMovF32 && decoded.src0.value != 2u) { if (error != nullptr) { @@ -868,17 +863,15 @@ bool LowerVInterpLoadF32(const Decoder::Instruction& decoded, BasicBlock* block, inst.op = Opcode::LoadInputF32; inst.input_info.attr = decoded.src1.value; inst.input_info.chan = decoded.src2.value; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -ExportTargetKind ExportTargetKindFromTarget(uint32_t target, uint32_t* index) { - if (index != nullptr) { - *index = 0; - } +ExportTargetKind ExportTargetKindFromTarget(uint32_t target, uint32_t& index) { + index = 0; switch (target) { case 0x08u: return ExportTargetKind::MrtZ; case 0x09u: return ExportTargetKind::Null; @@ -886,30 +879,24 @@ ExportTargetKind ExportTargetKindFromTarget(uint32_t target, uint32_t* index) { default: break; } if (target <= 0x07u) { - if (index != nullptr) { - *index = target; - } + index = target; return ExportTargetKind::Mrt; } if (target >= 0x0cu && target <= 0x0fu) { - if (index != nullptr) { - *index = target - 0x0cu; - } + index = target - 0x0cu; return ExportTargetKind::Position; } if (target >= 0x20u && target <= 0x3fu) { - if (index != nullptr) { - *index = target - 0x20u; - } + index = target - 0x20u; return ExportTargetKind::Parameter; } return ExportTargetKind::Unknown; } -bool LowerExportInstruction(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerExportInstruction(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { uint32_t index = 0; - const auto kind = ExportTargetKindFromTarget(decoded.exp.target, &index); + const auto kind = ExportTargetKindFromTarget(decoded.exp.target, index); if (kind == ExportTargetKind::Unknown) { if (error != nullptr) { *error = fmt::format("unsupported EXP target 0x{:02x} at pc 0x{:08x}", @@ -934,30 +921,30 @@ bool LowerExportInstruction(const Decoder::Instruction& decoded, BasicBlock* blo const Decoder::Operand* sources[] = {&decoded.src0, &decoded.src1, &decoded.src2, &decoded.src3}; for (uint32_t i = 0; i < inst.src_count && i < 4u; i++) { - if (!LowerSourceOperand(*sources[i], &inst.src[i], error)) { + if (!LowerSourceOperand(*sources[i], inst.src[i], error)) { return false; } } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerControlMarker(const Decoder::Instruction& decoded, BasicBlock* block, Opcode op, +bool LowerControlMarker(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op, bool has_imm, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = op; inst.dst.kind = OperandKind::Null; inst.src_count = has_imm ? 1u : 0u; - if (has_imm && !LowerSourceOperand(decoded.src0, &inst.src[0], error)) { + if (has_imm && !LowerSourceOperand(decoded.src0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerControlInstruction(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerControlInstruction(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { switch (decoded.opcode) { case Decoder::Opcode::SNop: @@ -979,23 +966,18 @@ bool LowerControlInstruction(const Decoder::Instruction& decoded, BasicBlock* bl } } -bool LowerScalarGetpcB64(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerScalarGetpcB64(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { - if (block == nullptr) { - SetError(error, "internal IR error: missing block for s_getpc_b64"); - return false; - } - for (uint32_t i = 0; i < 2u; i++) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::MoveU32; inst.src[0] = i == 0u ? MakePcRelativeU32(decoded.pc + 4u) : MakeImmediateU32(0u); inst.src_count = 1; - if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), &inst.dst, error)) { + if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } return true; } @@ -1020,7 +1002,7 @@ SaveexecMode ScalarSaveexecMode(Decoder::Opcode opcode) { } } -bool LowerScalarSaveexec(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerScalarSaveexec(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -1030,11 +1012,11 @@ bool LowerScalarSaveexec(const Decoder::Instruction& decoded, BasicBlock* block, : Opcode::SaveexecB64; inst.saveexec_mode = ScalarSaveexecMode(decoded.opcode); inst.src_count = 1; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } @@ -1067,9 +1049,9 @@ bool IsTerminatorOpcode(Decoder::Opcode opcode) { } } -bool LowerImplemented(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error); +bool LowerImplemented(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error); -bool LowerDecodedInstruction(const Decoder::Instruction& inst, BasicBlock* block, +bool LowerDecodedInstruction(const Decoder::Instruction& inst, BasicBlock& block, std::string* error) { switch (inst.opcode) { case Decoder::Opcode::Unsupported: @@ -1144,47 +1126,43 @@ bool LowerDecodedInstruction(const Decoder::Instruction& inst, BasicBlock* block return LowerImplemented(inst, block, error); } -bool LowerImplemented(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerImplemented(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = LookupIrOpcode(decoded.opcode); inst.src_count = decoded.src_count; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error)) { return false; } ApplyDppDestinationMask(decoded, inst.dst); for (uint32_t i = 0; i < decoded.src_count && i < 3u; i++) { const auto src_index = (IsReversedBinary(decoded.opcode) && decoded.src_count == 2u) ? 1u - i : i; - if (!LowerSourceOperand(DecodedSourceAt(decoded, src_index), &inst.src[i], error)) { + if (!LowerSourceOperand(DecodedSourceAt(decoded, src_index), inst.src[i], error)) { return false; } } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return AppendScalarResultSccNonZero(decoded, block, error); } } // namespace bool LowerProgram(const Decoder::Program& decoded, const CFG::Graph& cfg, ShaderType stage, - uint32_t wave_size, Program* program, std::string* error) { - if (program == nullptr) { - SetError(error, "invalid IR output"); - return false; - } + uint32_t wave_size, Program& program, std::string* error) { if (wave_size != 32u && wave_size != 64u) { EXIT("invalid shader wave size: %u\n", wave_size); } - *program = {}; - program->stage = stage; - program->wave_size = wave_size; - program->dispatcher_fallback = cfg.irreducible; - program->cfg_failure_kind = cfg.failure_kind; - program->fallback_reason = cfg.unsupported_reason; - program->blocks.clear(); + program = {}; + program.stage = stage; + program.wave_size = wave_size; + program.dispatcher_fallback = cfg.irreducible; + program.cfg_failure_kind = cfg.failure_kind; + program.fallback_reason = cfg.unsupported_reason; + program.blocks.clear(); if (cfg.blocks.empty()) { SetError(error, "cannot lower empty CFG"); @@ -1211,12 +1189,12 @@ bool LowerProgram(const Decoder::Program& decoded, const CFG::Graph& cfg, Shader decoded.instructions[i].pc) != cfg.code_table_load_pcs.end()) { continue; } - if (!LowerDecodedInstruction(decoded.instructions[i], &block, error)) { + if (!LowerDecodedInstruction(decoded.instructions[i], block, error)) { return false; } } - program->blocks.push_back(std::move(block)); + program.blocks.push_back(std::move(block)); } return true; diff --git a/src/graphics/shader/recompiler/shaderIR/ShaderIRInternal.h b/src/graphics/shader/recompiler/shaderIR/ShaderIRInternal.h index c40a83eef..e445536e9 100644 --- a/src/graphics/shader/recompiler/shaderIR/ShaderIRInternal.h +++ b/src/graphics/shader/recompiler/shaderIR/ShaderIRInternal.h @@ -17,12 +17,12 @@ bool ScalarResultIs64Bit(Decoder::Opcode opcode); Operand MakeSccOperand(); Operand MakeImmediateU32(uint32_t value); Operand MakePcRelativeU32(uint32_t value); -bool AppendScalarResultSccNonZero(const Decoder::Instruction& decoded, BasicBlock* block, +bool AppendScalarResultSccNonZero(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error); uint32_t VectorByteConvertIndex(Decoder::Opcode opcode); void CopyOperandModifiers(const Decoder::Operand& decoded, Operand& operand); -bool LowerRegisterOperand(const Decoder::Operand& decoded, Operand* operand, std::string* error); -bool LowerSourceOperand(const Decoder::Operand& decoded, Operand* operand, std::string* error); +bool LowerRegisterOperand(const Decoder::Operand& decoded, Operand& operand, std::string* error); +bool LowerSourceOperand(const Decoder::Operand& decoded, Operand& operand, std::string* error); void ApplyDppDestinationMask(const Decoder::Instruction& decoded, Operand& dst); uint32_t ResourceIndexFromOperand(const Decoder::Operand& operand); MemoryInfo MemoryInfoFromDecoded(const Decoder::Instruction& decoded, ResourceKind kind); @@ -30,7 +30,7 @@ uint32_t RawScalarLoadBase(const Decoder::Operand& operand); void ClearRegisterOffsetModifiers(Decoder::Operand& operand); bool TryGetScalarDestinationCode(const Decoder::Operand& operand, uint32_t& code); bool TryOffsetScalarDestination(const Decoder::Operand& operand, uint32_t index, - Decoder::Operand* result); + Decoder::Operand& result); Decoder::Operand OffsetDecodedRegister(const Decoder::Operand& operand, uint32_t index); MemoryInfo OffsetMemoryInfo(const Decoder::Instruction& decoded, ResourceKind kind, uint32_t dword_index); @@ -38,7 +38,7 @@ uint32_t TypedBufferComponentOffsetBytes(const Decoder::Instruction& dec uint32_t component_index); uint32_t TypedBufferFormatComponentCount(const Decoder::Instruction& decoded); bool LowerMoveImmediateU32(uint32_t pc, const Decoder::Operand& dst, uint32_t value, - BasicBlock* block, std::string* error); + BasicBlock& block, std::string* error); MemoryInfo OffsetBufferMemoryInfo(const Decoder::Instruction& decoded, uint32_t component_index); MemoryInfo ByteOffsetMemoryInfo(const Decoder::Instruction& decoded, ResourceKind kind, uint32_t byte_offset); @@ -47,7 +47,7 @@ const Decoder::Operand& DecodedSourceAt(const Decoder::Instruction& decoded, uin Decoder::Operand M0Operand(); bool IsMemoryOpcode(Decoder::Opcode opcode); -bool LowerMemoryInstruction(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerMemoryInstruction(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error); } // namespace Libs::Graphics::ShaderRecompiler::IR diff --git a/src/graphics/shader/recompiler/shaderIR/ShaderIRMemory.cpp b/src/graphics/shader/recompiler/shaderIR/ShaderIRMemory.cpp index 8d5371b32..c02dadfdc 100644 --- a/src/graphics/shader/recompiler/shaderIR/ShaderIRMemory.cpp +++ b/src/graphics/shader/recompiler/shaderIR/ShaderIRMemory.cpp @@ -10,7 +10,7 @@ namespace Libs::Graphics::ShaderRecompiler::IR { namespace { -bool LowerScalarBufferLoadDword(const Decoder::Instruction& decoded, BasicBlock* block, Opcode op, +bool LowerScalarBufferLoadDword(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op, std::string* error) { for (uint32_t i = 0; i < decoded.data_dwords; i++) { Instruction inst; @@ -22,38 +22,38 @@ bool LowerScalarBufferLoadDword(const Decoder::Instruction& decoded, BasicBlock* // descriptor resource index. inst.memory.resource = op == Opcode::SLoadDword ? RawScalarLoadBase(decoded.src0) : ResourceIndexFromOperand(decoded.src0); - if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), &inst.dst, error) || - !LowerSourceOperand(decoded.src1, &inst.src[0], error)) { + if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error) || + !LowerSourceOperand(decoded.src1, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } return true; } -bool LowerBufferAddressSources(const Decoder::Instruction& decoded, Instruction* inst, +bool LowerBufferAddressSources(const Decoder::Instruction& decoded, Instruction& inst, uint32_t first_src, std::string* error) { uint32_t src = first_src; if (decoded.idxen) { - if (!LowerSourceOperand(decoded.src0, &inst->src[src++], error)) { + if (!LowerSourceOperand(decoded.src0, inst.src[src++], error)) { return false; } } if (decoded.offen) { const auto offset_source = decoded.idxen ? OffsetDecodedRegister(decoded.src0, 1) : decoded.src0; - if (!LowerSourceOperand(offset_source, &inst->src[src++], error)) { + if (!LowerSourceOperand(offset_source, inst.src[src++], error)) { return false; } } - if (!LowerSourceOperand(decoded.src2, &inst->src[src++], error)) { + if (!LowerSourceOperand(decoded.src2, inst.src[src++], error)) { return false; } - inst->src_count = src; + inst.src_count = src; return true; } -bool LowerBufferLoad(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerBufferLoad(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { const auto ir_op = decoded.data_bits == 8u ? (decoded.data_signed ? Opcode::BufferLoadSbyte : Opcode::BufferLoadUbyte) @@ -75,16 +75,16 @@ bool LowerBufferLoad(const Decoder::Instruction& decoded, BasicBlock* block, std inst.pc = decoded.pc; inst.op = ir_op; inst.memory = OffsetBufferMemoryInfo(decoded, i); - if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), &inst.dst, error) || - !LowerBufferAddressSources(decoded, &inst, 0, error)) { + if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error) || + !LowerBufferAddressSources(decoded, inst, 0, error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } return true; } -bool LowerBufferStore(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerBufferStore(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { const auto ir_op = decoded.data_bits == 8u ? Opcode::BufferStoreByte : decoded.data_bits == 16u ? Opcode::BufferStoreShort : Opcode::BufferStoreDword; @@ -101,28 +101,28 @@ bool LowerBufferStore(const Decoder::Instruction& decoded, BasicBlock* block, st inst.op = ir_op; inst.memory = OffsetBufferMemoryInfo(decoded, i); inst.dst.kind = OperandKind::Null; - if (!LowerSourceOperand(OffsetDecodedRegister(decoded.dst, i), &inst.src[0], error) || - !LowerBufferAddressSources(decoded, &inst, 1, error)) { + if (!LowerSourceOperand(OffsetDecodedRegister(decoded.dst, i), inst.src[0], error) || + !LowerBufferAddressSources(decoded, inst, 1, error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } return true; } -bool LowerBufferAtomicDword(const Decoder::Instruction& decoded, BasicBlock* block, Opcode op, +bool LowerBufferAtomicDword(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = op; inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::Buffer); inst.dst.kind = OperandKind::Null; - if ((decoded.glc && !LowerRegisterOperand(decoded.dst, &inst.dst, error)) || - !LowerSourceOperand(decoded.dst, &inst.src[0], error) || - !LowerBufferAddressSources(decoded, &inst, 1, error)) { + if ((decoded.glc && !LowerRegisterOperand(decoded.dst, inst.dst, error)) || + !LowerSourceOperand(decoded.dst, inst.src[0], error) || + !LowerBufferAddressSources(decoded, inst, 1, error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } @@ -130,7 +130,7 @@ ResourceKind DsMemoryKind(const Decoder::Instruction& decoded) { return decoded.gds ? ResourceKind::Gds : ResourceKind::Lds; } -bool LowerDsRead(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerDsRead(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { const auto ir_op = decoded.data_bits == 8u ? (decoded.data_signed ? Opcode::DsReadSbyte : Opcode::DsReadUbyte) : decoded.data_bits == 16u @@ -143,16 +143,16 @@ bool LowerDsRead(const Decoder::Instruction& decoded, BasicBlock* block, std::st inst.op = ir_op; inst.src_count = 1; inst.memory = OffsetMemoryInfo(decoded, DsMemoryKind(decoded), i); - if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error)) { + if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } return true; } -bool LowerDsRead2(const Decoder::Instruction& decoded, BasicBlock* block, uint32_t dwords_per_read, +bool LowerDsRead2(const Decoder::Instruction& decoded, BasicBlock& block, uint32_t dwords_per_read, std::string* error) { const uint32_t offsets[] = {decoded.offset, decoded.secondary_offset}; for (uint32_t read = 0; read < 2u; read++) { @@ -164,18 +164,18 @@ bool LowerDsRead2(const Decoder::Instruction& decoded, BasicBlock* block, uint32 inst.src_count = 1; inst.memory = ByteOffsetMemoryInfo(decoded, DsMemoryKind(decoded), offsets[read] + dword * 4u); - if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, index), &inst.dst, + if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, index), inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error)) { + !LowerSourceOperand(decoded.src0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } } return true; } -bool LowerDsAtomicU32(const Decoder::Instruction& decoded, BasicBlock* block, Opcode op, +bool LowerDsAtomicU32(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op, bool return_old, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -183,31 +183,31 @@ bool LowerDsAtomicU32(const Decoder::Instruction& decoded, BasicBlock* block, Op inst.src_count = 2; inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded)); inst.dst.kind = return_old ? OperandKind::Register : OperandKind::Null; - if ((return_old && !LowerRegisterOperand(decoded.dst, &inst.dst, error)) || - !LowerSourceOperand(decoded.src1, &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error)) { + if ((return_old && !LowerRegisterOperand(decoded.dst, inst.dst, error)) || + !LowerSourceOperand(decoded.src1, inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerDsSwizzleB32(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerDsSwizzleB32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; inst.op = Opcode::DsSwizzleB32; inst.src_count = 2; inst.src[1].kind = OperandKind::ImmediateU32; inst.src[1].imm = decoded.offset & 0xffffu; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerDsFloatMinMaxF32(const Decoder::Instruction& decoded, BasicBlock* block, Opcode op, +bool LowerDsFloatMinMaxF32(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -216,17 +216,17 @@ bool LowerDsFloatMinMaxF32(const Decoder::Instruction& decoded, BasicBlock* bloc inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded)); inst.memory.resource = 0; inst.dst.kind = OperandKind::Null; - if (!LowerSourceOperand(decoded.src1, &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error) || - !LowerSourceOperand(decoded.src2, &inst.src[2], error)) { + if (!LowerSourceOperand(decoded.src1, inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error) || + !LowerSourceOperand(decoded.src2, inst.src[2], error)) { return false; } inst.src_count = 3; - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerDsWriteAddtidB32(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerDsWriteAddtidB32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -236,15 +236,15 @@ bool LowerDsWriteAddtidB32(const Decoder::Instruction& decoded, BasicBlock* bloc inst.memory.resource = 0; inst.dst.kind = OperandKind::Null; const auto m0 = M0Operand(); - if (!LowerSourceOperand(decoded.src1, &inst.src[0], error) || - !LowerSourceOperand(m0, &inst.src[1], error)) { + if (!LowerSourceOperand(decoded.src1, inst.src[0], error) || + !LowerSourceOperand(m0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerDsReadAddtidB32(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerDsReadAddtidB32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -253,15 +253,15 @@ bool LowerDsReadAddtidB32(const Decoder::Instruction& decoded, BasicBlock* block inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded)); inst.memory.resource = 0; const auto m0 = M0Operand(); - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(m0, &inst.src[0], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(m0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerDsAppendConsume(const Decoder::Instruction& decoded, BasicBlock* block, Opcode op, +bool LowerDsAppendConsume(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -269,11 +269,11 @@ bool LowerDsAppendConsume(const Decoder::Instruction& decoded, BasicBlock* block inst.src_count = 1; inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded)); const auto m0 = M0Operand(); - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(m0, &inst.src[0], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(m0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } @@ -289,7 +289,7 @@ Opcode ImageAtomicIrOpcode(Decoder::Opcode opcode) { } } -bool LowerImageAtomicU32(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerImageAtomicU32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -298,16 +298,16 @@ bool LowerImageAtomicU32(const Decoder::Instruction& decoded, BasicBlock* block, inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::StorageImageUint); inst.memory.sampler = 0; inst.dst.kind = OperandKind::Null; - if ((decoded.glc && !LowerRegisterOperand(decoded.dst, &inst.dst, error)) || - !LowerSourceOperand(decoded.dst, &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error)) { + if ((decoded.glc && !LowerRegisterOperand(decoded.dst, inst.dst, error)) || + !LowerSourceOperand(decoded.dst, inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } -bool LowerFlatLoad(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerFlatLoad(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { const auto kind = FlatSegmentResourceKind(decoded.memory_segment); const auto ir_op = decoded.data_bits == 8u ? (decoded.data_signed ? Opcode::FlatLoadSbyte : Opcode::FlatLoadUbyte) @@ -322,15 +322,15 @@ bool LowerFlatLoad(const Decoder::Instruction& decoded, BasicBlock* block, std:: inst.src_count = decoded.src_count; inst.memory = MemoryInfoFromDecoded(decoded, kind); inst.memory.resource = 0; - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error)) { return false; } for (uint32_t i = 0; i < decoded.src_count && i < 3u; i++) { - if (!LowerSourceOperand(DecodedSourceAt(decoded, i), &inst.src[i], error)) { + if (!LowerSourceOperand(DecodedSourceAt(decoded, i), inst.src[i], error)) { return false; } } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } @@ -341,20 +341,20 @@ bool LowerFlatLoad(const Decoder::Instruction& decoded, BasicBlock* block, std:: inst.src_count = decoded.src_count; inst.memory = OffsetMemoryInfo(decoded, kind, dword); inst.memory.resource = 0; - if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, dword), &inst.dst, error)) { + if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, dword), inst.dst, error)) { return false; } for (uint32_t i = 0; i < decoded.src_count && i < 3u; i++) { - if (!LowerSourceOperand(DecodedSourceAt(decoded, i), &inst.src[i], error)) { + if (!LowerSourceOperand(DecodedSourceAt(decoded, i), inst.src[i], error)) { return false; } } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } return true; } -bool LowerFlatStore(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerFlatStore(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { const auto kind = FlatSegmentResourceKind(decoded.memory_segment); const auto ir_op = decoded.data_bits == 8u ? Opcode::FlatStoreByte : decoded.data_bits == 16u ? Opcode::FlatStoreShort @@ -368,20 +368,20 @@ bool LowerFlatStore(const Decoder::Instruction& decoded, BasicBlock* block, std: inst.memory = OffsetMemoryInfo(decoded, kind, dword); inst.memory.resource = 0; inst.dst.kind = OperandKind::Null; - if (!LowerSourceOperand(OffsetDecodedRegister(decoded.dst, dword), &inst.src[0], error)) { + if (!LowerSourceOperand(OffsetDecodedRegister(decoded.dst, dword), inst.src[0], error)) { return false; } for (uint32_t i = 0; i < decoded.src_count && i + 1u < 3u; i++) { - if (!LowerSourceOperand(DecodedSourceAt(decoded, i), &inst.src[i + 1u], error)) { + if (!LowerSourceOperand(DecodedSourceAt(decoded, i), inst.src[i + 1u], error)) { return false; } } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } return true; } -bool LowerDsWrite(const Decoder::Instruction& decoded, BasicBlock* block, std::string* error) { +bool LowerDsWrite(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { const auto ir_op = decoded.data_bits == 8u ? Opcode::DsWriteByte : decoded.data_bits == 16u ? Opcode::DsWriteShort : Opcode::DsWriteB32; @@ -393,16 +393,16 @@ bool LowerDsWrite(const Decoder::Instruction& decoded, BasicBlock* block, std::s inst.src_count = 2; inst.memory = OffsetMemoryInfo(decoded, DsMemoryKind(decoded), i); inst.dst.kind = OperandKind::Null; - if (!LowerSourceOperand(OffsetDecodedRegister(decoded.src1, i), &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error)) { + if (!LowerSourceOperand(OffsetDecodedRegister(decoded.src1, i), inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } return true; } -bool LowerDsWrite2(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerDsWrite2(const Decoder::Instruction& decoded, BasicBlock& block, uint32_t dwords_per_write, std::string* error) { const Decoder::Operand* data[] = {&decoded.src1, &decoded.src2}; const uint32_t offsets[] = {decoded.offset, decoded.secondary_offset}; @@ -415,18 +415,18 @@ bool LowerDsWrite2(const Decoder::Instruction& decoded, BasicBlock* block, inst.memory = ByteOffsetMemoryInfo(decoded, DsMemoryKind(decoded), offsets[write] + dword * 4u); inst.dst.kind = OperandKind::Null; - if (!LowerSourceOperand(OffsetDecodedRegister(*data[write], dword), &inst.src[0], + if (!LowerSourceOperand(OffsetDecodedRegister(*data[write], dword), inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error)) { + !LowerSourceOperand(decoded.src0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); } } return true; } -bool LowerImageOperation(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerImageOperation(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { Instruction inst; inst.pc = decoded.pc; @@ -437,11 +437,11 @@ bool LowerImageOperation(const Decoder::Instruction& decoded, BasicBlock* block, inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::StorageImage); inst.memory.sampler = 0; inst.dst.kind = OperandKind::Null; - if (!LowerSourceOperand(decoded.dst, &inst.src[0], error) || - !LowerSourceOperand(decoded.src0, &inst.src[1], error)) { + if (!LowerSourceOperand(decoded.dst, inst.src[0], error) || + !LowerSourceOperand(decoded.src0, inst.src[1], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } @@ -461,17 +461,17 @@ bool LowerImageOperation(const Decoder::Instruction& decoded, BasicBlock* block, : Opcode::ImageSample; inst.src_count = 1; inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::Image); - if (!LowerRegisterOperand(decoded.dst, &inst.dst, error) || - !LowerSourceOperand(decoded.src0, &inst.src[0], error)) { + if (!LowerRegisterOperand(decoded.dst, inst.dst, error) || + !LowerSourceOperand(decoded.src0, inst.src[0], error)) { return false; } - block->instructions.push_back(inst); + block.instructions.push_back(inst); return true; } } // namespace -bool LowerMemoryInstruction(const Decoder::Instruction& decoded, BasicBlock* block, +bool LowerMemoryInstruction(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) { switch (decoded.opcode) { case Decoder::Opcode::SLoadDword: diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterAluOps.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterAluOps.cpp index f619bea01..d20021c26 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterAluOps.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterAluOps.cpp @@ -2,220 +2,217 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { -void EmitPerInvocationMask(EmitterState* state, const IR::Operand& dst, uint32_t value_bool) { - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->uint_type, value, value_bool, - ConstantU32(state, 1), ConstantU32(state, 0)}); +void EmitPerInvocationMask(EmitterState& state, const IR::Operand& dst, uint32_t value_bool) { + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.uint_type, value, value_bool, ConstantU32(state, 1), + ConstantU32(state, 0)}); EmitStoreU32(state, dst, value); EmitStoreU32(state, OffsetRegisterOperand(dst, 1), ConstantU32(state, 0)); } -uint32_t EmitLogicalBinary(EmitterState* state, uint32_t opcode, uint32_t lhs, uint32_t rhs) { +uint32_t EmitLogicalBinary(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs) { const auto logical_opcode = opcode == OpBitwiseAnd ? OpLogicalAnd : opcode == OpBitwiseOr ? OpLogicalOr : OpLogicalNotEqual; - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({logical_opcode, state->bool_type, value, lhs, rhs}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({logical_opcode, state.bool_type, value, lhs, rhs}); return value; } -void EmitAbsI32(EmitterState* state, const IR::Instruction& inst) { +void EmitAbsI32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto neg = state->builder.AllocateId(); - const auto cond = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpSNegate, state->uint_type, neg, src}); - state->builder.AddFunction({OpSLessThan, state->bool_type, cond, src, ConstantU32(state, 0)}); - state->builder.AddFunction({OpSelect, state->uint_type, ret, cond, neg, src}); + const auto neg = state.builder.AllocateId(); + const auto cond = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpSNegate, state.uint_type, neg, src}); + state.builder.AddFunction({OpSLessThan, state.bool_type, cond, src, ConstantU32(state, 0)}); + state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, neg, src}); EmitStoreU32(state, inst.dst, ret); } -void EmitUnaryU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitUnaryU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, ret, src}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, ret, src}); EmitStoreU32(state, inst.dst, ret); } -void EmitUnaryU64(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { - if (state->per_invocation_masks) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalNot, state->bool_type, ret, - EmitLaneMaskOperandActiveBool(state, inst.src[0])}); +void EmitUnaryU64(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { + if (state.per_invocation_masks) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalNot, state.bool_type, ret, + EmitLaneMaskOperandActiveBool(state, inst.src[0])}); EmitPerInvocationMask(state, inst.dst, ret); return; } const auto low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto high = EmitSequentialValueLoad(state, inst.src[0], 1); - const auto ret_low = state->builder.AllocateId(); - const auto ret_high = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, ret_low, low}); - state->builder.AddFunction({opcode, state->uint_type, ret_high, high}); + const auto ret_low = state.builder.AllocateId(); + const auto ret_high = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, ret_low, low}); + state.builder.AddFunction({opcode, state.uint_type, ret_high, high}); EmitStoreU32(state, inst.dst, ret_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); } -void EmitFindLsbU32(EmitterState* state, const IR::Instruction& inst) { +void EmitFindLsbU32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto i32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->int_type, i32, state->glsl_std450, GlslFindILsb, src}); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, i32}); + const auto i32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.int_type, i32, state.glsl_std450, GlslFindILsb, src}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, i32}); EmitStoreU32(state, inst.dst, u32); } -void EmitFindMsbFromHighU32(EmitterState* state, const IR::Instruction& inst) { +void EmitFindMsbFromHighU32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto i32 = state->builder.AllocateId(); - const auto msb = state->builder.AllocateId(); - const auto pos = state->builder.AllocateId(); - const auto non_zero = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->int_type, i32, state->glsl_std450, GlslFindUMsb, src}); - state->builder.AddFunction({OpBitcast, state->uint_type, msb, i32}); - state->builder.AddFunction({OpISub, state->uint_type, pos, ConstantU32(state, 31), msb}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, non_zero, src, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, non_zero, pos, ConstantU32(state, 0xffffffffu)}); + const auto i32 = state.builder.AllocateId(); + const auto msb = state.builder.AllocateId(); + const auto pos = state.builder.AllocateId(); + const auto non_zero = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.int_type, i32, state.glsl_std450, GlslFindUMsb, src}); + state.builder.AddFunction({OpBitcast, state.uint_type, msb, i32}); + state.builder.AddFunction({OpISub, state.uint_type, pos, ConstantU32(state, 31), msb}); + state.builder.AddFunction({OpINotEqual, state.bool_type, non_zero, src, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, non_zero, pos, ConstantU32(state, 0xffffffffu)}); EmitStoreU32(state, inst.dst, ret); } -void EmitFindMsbFromHighU64(EmitterState* state, const IR::Instruction& inst) { +void EmitFindMsbFromHighU64(EmitterState& state, const IR::Instruction& inst) { const auto low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto high = EmitSequentialValueLoad(state, inst.src[0], 1); - const auto high_i32 = state->builder.AllocateId(); - const auto high_msb = state->builder.AllocateId(); - const auto high_pos = state->builder.AllocateId(); - const auto high_non_zero = state->builder.AllocateId(); - const auto low_i32 = state->builder.AllocateId(); - const auto low_msb = state->builder.AllocateId(); - const auto low_pos = state->builder.AllocateId(); - const auto low_total = state->builder.AllocateId(); - const auto low_non_zero = state->builder.AllocateId(); - const auto low_ret = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->int_type, high_i32, state->glsl_std450, GlslFindUMsb, high}); - state->builder.AddFunction({OpBitcast, state->uint_type, high_msb, high_i32}); - state->builder.AddFunction( - {OpISub, state->uint_type, high_pos, ConstantU32(state, 31), high_msb}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, high_non_zero, high, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpExtInst, state->int_type, low_i32, state->glsl_std450, GlslFindUMsb, low}); - state->builder.AddFunction({OpBitcast, state->uint_type, low_msb, low_i32}); - state->builder.AddFunction( - {OpISub, state->uint_type, low_pos, ConstantU32(state, 31), low_msb}); - state->builder.AddFunction( - {OpIAdd, state->uint_type, low_total, low_pos, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, low_non_zero, low, ConstantU32(state, 0)}); - state->builder.AddFunction({OpSelect, state->uint_type, low_ret, low_non_zero, low_total, - ConstantU32(state, 0xffffffffu)}); - state->builder.AddFunction({OpSelect, state->uint_type, ret, high_non_zero, high_pos, low_ret}); + const auto high_i32 = state.builder.AllocateId(); + const auto high_msb = state.builder.AllocateId(); + const auto high_pos = state.builder.AllocateId(); + const auto high_non_zero = state.builder.AllocateId(); + const auto low_i32 = state.builder.AllocateId(); + const auto low_msb = state.builder.AllocateId(); + const auto low_pos = state.builder.AllocateId(); + const auto low_total = state.builder.AllocateId(); + const auto low_non_zero = state.builder.AllocateId(); + const auto low_ret = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.int_type, high_i32, state.glsl_std450, GlslFindUMsb, high}); + state.builder.AddFunction({OpBitcast, state.uint_type, high_msb, high_i32}); + state.builder.AddFunction( + {OpISub, state.uint_type, high_pos, ConstantU32(state, 31), high_msb}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, high_non_zero, high, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpExtInst, state.int_type, low_i32, state.glsl_std450, GlslFindUMsb, low}); + state.builder.AddFunction({OpBitcast, state.uint_type, low_msb, low_i32}); + state.builder.AddFunction({OpISub, state.uint_type, low_pos, ConstantU32(state, 31), low_msb}); + state.builder.AddFunction( + {OpIAdd, state.uint_type, low_total, low_pos, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, low_non_zero, low, ConstantU32(state, 0)}); + state.builder.AddFunction({OpSelect, state.uint_type, low_ret, low_non_zero, low_total, + ConstantU32(state, 0xffffffffu)}); + state.builder.AddFunction({OpSelect, state.uint_type, ret, high_non_zero, high_pos, low_ret}); EmitStoreU32(state, inst.dst, ret); } -void EmitBitCountU64(EmitterState* state, const IR::Instruction& inst) { +void EmitBitCountU64(EmitterState& state, const IR::Instruction& inst) { const auto low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto high = EmitSequentialValueLoad(state, inst.src[0], 1); - const auto low_count = state->builder.AllocateId(); - const auto high_count = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitCount, state->uint_type, low_count, low}); - state->builder.AddFunction({OpBitCount, state->uint_type, high_count, high}); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, low_count, high_count}); + const auto low_count = state.builder.AllocateId(); + const auto high_count = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitCount, state.uint_type, low_count, low}); + state.builder.AddFunction({OpBitCount, state.uint_type, high_count, high}); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, low_count, high_count}); EmitStoreU32(state, inst.dst, ret); } -void EmitBitCountU32(EmitterState* state, const IR::Instruction& inst) { +void EmitBitCountU32(EmitterState& state, const IR::Instruction& inst) { const auto bits = EmitValueLoad(state, inst.src[0]); - const auto count = state->builder.AllocateId(); - state->builder.AddFunction({OpBitCount, state->uint_type, count, bits}); + const auto count = state.builder.AllocateId(); + state.builder.AddFunction({OpBitCount, state.uint_type, count, bits}); EmitStoreU32(state, inst.dst, count); } -void EmitBitCountAddU32(EmitterState* state, const IR::Instruction& inst) { +void EmitBitCountAddU32(EmitterState& state, const IR::Instruction& inst) { const auto bits = EmitValueLoad(state, inst.src[0]); const auto add = EmitValueLoad(state, inst.src[1]); - const auto count = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitCount, state->uint_type, count, bits}); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, count, add}); + const auto count = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitCount, state.uint_type, count, bits}); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, count, add}); EmitStoreU32(state, inst.dst, ret); } -void EmitBinaryU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitBinaryU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitValueLoad(state, inst.src[0]); auto rhs = EmitValueLoad(state, inst.src[1]); if (opcode == OpShiftLeftLogical || opcode == OpShiftRightLogical || opcode == OpShiftRightArithmetic) { rhs = EmitAndConstant(state, rhs, 31u); } - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, ret, lhs, rhs}); EmitStoreU32(state, inst.dst, ret); } -void EmitBinaryNotRhsU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitBinaryNotRhsU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); - const auto not_rhs = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpNot, state->uint_type, not_rhs, rhs}); - state->builder.AddFunction({opcode, state->uint_type, ret, lhs, not_rhs}); + const auto not_rhs = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpNot, state.uint_type, not_rhs, rhs}); + state.builder.AddFunction({opcode, state.uint_type, ret, lhs, not_rhs}); EmitStoreU32(state, inst.dst, ret); } -void EmitBinaryThenNotU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitBinaryThenNotU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); - const auto tmp = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, tmp, lhs, rhs}); - state->builder.AddFunction({OpNot, state->uint_type, ret, tmp}); + const auto tmp = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, tmp, lhs, rhs}); + state.builder.AddFunction({OpNot, state.uint_type, ret, tmp}); EmitStoreU32(state, inst.dst, ret); } -void EmitMaskedBitCountU32(EmitterState* state, const IR::Instruction& inst, uint32_t exec_index) { +void EmitMaskedBitCountU32(EmitterState& state, const IR::Instruction& inst, uint32_t exec_index) { const auto bits = EmitValueLoad(state, inst.src[0]); const auto add = EmitValueLoad(state, inst.src[1]); const auto thread_mask = EmitThreadMaskBelowPartU32(state, exec_index); - const auto active_bits = state->builder.AllocateId(); - const auto count = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, active_bits, bits, thread_mask}); - state->builder.AddFunction({OpBitCount, state->uint_type, count, active_bits}); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, count, add}); + const auto active_bits = state.builder.AllocateId(); + const auto count = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, active_bits, bits, thread_mask}); + state.builder.AddFunction({OpBitCount, state.uint_type, count, active_bits}); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, count, add}); EmitStoreU32(state, inst.dst, ret); } -uint32_t EmitMask5U32(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, ret, value, ConstantU32(state, 31)}); +uint32_t EmitMask5U32(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, ret, value, ConstantU32(state, 31)}); return ret; } -void EmitChainedBinaryU32(EmitterState* state, const IR::Instruction& inst, uint32_t first_op, +void EmitChainedBinaryU32(EmitterState& state, const IR::Instruction& inst, uint32_t first_op, uint32_t second_op, bool mask_first_rhs, bool mask_second_rhs) { const auto src0 = EmitValueLoad(state, inst.src[0]); const auto src1_raw = EmitValueLoad(state, inst.src[1]); const auto src2_raw = EmitValueLoad(state, inst.src[2]); const auto src1 = mask_first_rhs ? EmitMask5U32(state, src1_raw) : src1_raw; const auto src2 = mask_second_rhs ? EmitMask5U32(state, src2_raw) : src2_raw; - const auto tmp = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({first_op, state->uint_type, tmp, src0, src1}); - state->builder.AddFunction({second_op, state->uint_type, ret, tmp, src2}); + const auto tmp = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({first_op, state.uint_type, tmp, src0, src1}); + state.builder.AddFunction({second_op, state.uint_type, ret, tmp, src2}); EmitStoreU32(state, inst.dst, ret); } -void EmitBinaryU64(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { - if (state->per_invocation_masks) { +void EmitBinaryU64(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { + if (state.per_invocation_masks) { const auto ret = EmitLogicalBinary(state, opcode, EmitLaneMaskOperandActiveBool(state, inst.src[0]), EmitLaneMaskOperandActiveBool(state, inst.src[1])); @@ -226,19 +223,19 @@ void EmitBinaryU64(EmitterState* state, const IR::Instruction& inst, uint32_t op const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0); const auto rhs_high = EmitSequentialValueLoad(state, inst.src[1], 1); - const auto ret_low = state->builder.AllocateId(); - const auto ret_high = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, ret_low, lhs_low, rhs_low}); - state->builder.AddFunction({opcode, state->uint_type, ret_high, lhs_high, rhs_high}); + const auto ret_low = state.builder.AllocateId(); + const auto ret_high = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, ret_low, lhs_low, rhs_low}); + state.builder.AddFunction({opcode, state.uint_type, ret_high, lhs_high, rhs_high}); EmitStoreU32(state, inst.dst, ret_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); } -void EmitBinaryNotRhsU64(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { - if (state->per_invocation_masks) { - const auto not_rhs = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalNot, state->bool_type, not_rhs, - EmitLaneMaskOperandActiveBool(state, inst.src[1])}); +void EmitBinaryNotRhsU64(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { + if (state.per_invocation_masks) { + const auto not_rhs = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalNot, state.bool_type, not_rhs, + EmitLaneMaskOperandActiveBool(state, inst.src[1])}); const auto ret = EmitLogicalBinary( state, opcode, EmitLaneMaskOperandActiveBool(state, inst.src[0]), not_rhs); EmitPerInvocationMask(state, inst.dst, ret); @@ -248,25 +245,25 @@ void EmitBinaryNotRhsU64(EmitterState* state, const IR::Instruction& inst, uint3 const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0); const auto rhs_high = EmitSequentialValueLoad(state, inst.src[1], 1); - const auto not_low = state->builder.AllocateId(); - const auto not_high = state->builder.AllocateId(); - const auto ret_low = state->builder.AllocateId(); - const auto ret_high = state->builder.AllocateId(); - state->builder.AddFunction({OpNot, state->uint_type, not_low, rhs_low}); - state->builder.AddFunction({OpNot, state->uint_type, not_high, rhs_high}); - state->builder.AddFunction({opcode, state->uint_type, ret_low, lhs_low, not_low}); - state->builder.AddFunction({opcode, state->uint_type, ret_high, lhs_high, not_high}); + const auto not_low = state.builder.AllocateId(); + const auto not_high = state.builder.AllocateId(); + const auto ret_low = state.builder.AllocateId(); + const auto ret_high = state.builder.AllocateId(); + state.builder.AddFunction({OpNot, state.uint_type, not_low, rhs_low}); + state.builder.AddFunction({OpNot, state.uint_type, not_high, rhs_high}); + state.builder.AddFunction({opcode, state.uint_type, ret_low, lhs_low, not_low}); + state.builder.AddFunction({opcode, state.uint_type, ret_high, lhs_high, not_high}); EmitStoreU32(state, inst.dst, ret_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); } -void EmitBinaryThenNotU64(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { - if (state->per_invocation_masks) { +void EmitBinaryThenNotU64(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { + if (state.per_invocation_masks) { const auto value = EmitLogicalBinary(state, opcode, EmitLaneMaskOperandActiveBool(state, inst.src[0]), EmitLaneMaskOperandActiveBool(state, inst.src[1])); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalNot, state->bool_type, ret, value}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalNot, state.bool_type, ret, value}); EmitPerInvocationMask(state, inst.dst, ret); return; } @@ -274,207 +271,203 @@ void EmitBinaryThenNotU64(EmitterState* state, const IR::Instruction& inst, uint const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0); const auto rhs_high = EmitSequentialValueLoad(state, inst.src[1], 1); - const auto tmp_low = state->builder.AllocateId(); - const auto tmp_high = state->builder.AllocateId(); - const auto ret_low = state->builder.AllocateId(); - const auto ret_high = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, tmp_low, lhs_low, rhs_low}); - state->builder.AddFunction({opcode, state->uint_type, tmp_high, lhs_high, rhs_high}); - state->builder.AddFunction({OpNot, state->uint_type, ret_low, tmp_low}); - state->builder.AddFunction({OpNot, state->uint_type, ret_high, tmp_high}); + const auto tmp_low = state.builder.AllocateId(); + const auto tmp_high = state.builder.AllocateId(); + const auto ret_low = state.builder.AllocateId(); + const auto ret_high = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, tmp_low, lhs_low, rhs_low}); + state.builder.AddFunction({opcode, state.uint_type, tmp_high, lhs_high, rhs_high}); + state.builder.AddFunction({OpNot, state.uint_type, ret_low, tmp_low}); + state.builder.AddFunction({OpNot, state.uint_type, ret_high, tmp_high}); EmitStoreU32(state, inst.dst, ret_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); } -void EmitSelectU64(EmitterState* state, const IR::Instruction& inst) { +void EmitSelectU64(EmitterState& state, const IR::Instruction& inst) { const auto cond = EmitConditionBool(state, inst.src[0]); const auto true_low = EmitSequentialValueLoad(state, inst.src[1], 0); const auto true_high = EmitSequentialValueLoad(state, inst.src[1], 1); const auto false_low = EmitSequentialValueLoad(state, inst.src[2], 0); const auto false_high = EmitSequentialValueLoad(state, inst.src[2], 1); - const auto ret_low = state->builder.AllocateId(); - const auto ret_high = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->uint_type, ret_low, cond, true_low, false_low}); - state->builder.AddFunction({OpSelect, state->uint_type, ret_high, cond, true_high, false_high}); + const auto ret_low = state.builder.AllocateId(); + const auto ret_high = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.uint_type, ret_low, cond, true_low, false_low}); + state.builder.AddFunction({OpSelect, state.uint_type, ret_high, cond, true_high, false_high}); EmitStoreU32(state, inst.dst, ret_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); } -uint32_t EmitSelectValueU32(EmitterState* state, uint32_t cond, uint32_t true_value, +uint32_t EmitSelectValueU32(EmitterState& state, uint32_t cond, uint32_t true_value, uint32_t false_value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->uint_type, ret, cond, true_value, false_value}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, true_value, false_value}); return ret; } -void EmitStoreSccBool(EmitterState* state, uint32_t cond) { +void EmitStoreSccBool(EmitterState& state, uint32_t cond) { const auto value = EmitSelectValueU32(state, cond, ConstantU32(state, 1), ConstantU32(state, 0)); EmitStoreU32(state, SccOperand(), value); } -uint32_t EmitAndConstant(EmitterState* state, uint32_t value, uint32_t mask); +uint32_t EmitAndConstant(EmitterState& state, uint32_t value, uint32_t mask); -void EmitShiftLeftLogicalU64Values(EmitterState* state, uint32_t low, uint32_t high, uint32_t shift, - uint32_t* out_low, uint32_t* out_high) { +void EmitShiftLeftLogicalU64Values(EmitterState& state, uint32_t low, uint32_t high, uint32_t shift, + uint32_t& out_low, uint32_t& out_high) { const auto amount = EmitAndConstant(state, shift, 63u); const auto dword_shift = EmitAndConstant(state, amount, 31u); - const auto less32 = state->builder.AllocateId(); - const auto non_zero = state->builder.AllocateId(); - const auto carry_count_base = state->builder.AllocateId(); - const auto carry_count = state->builder.AllocateId(); - const auto low_part = state->builder.AllocateId(); - const auto high_part = state->builder.AllocateId(); - const auto carry_part = state->builder.AllocateId(); - const auto carry = state->builder.AllocateId(); - const auto high_less = state->builder.AllocateId(); - const auto high_ge = state->builder.AllocateId(); - state->builder.AddFunction( - {OpULessThan, state->bool_type, less32, amount, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, non_zero, amount, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpISub, state->uint_type, carry_count_base, ConstantU32(state, 32), dword_shift}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, carry_count, carry_count_base, ConstantU32(state, 31)}); - state->builder.AddFunction({OpShiftLeftLogical, state->uint_type, low_part, low, dword_shift}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, high_part, high, dword_shift}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, carry_part, low, carry_count}); - state->builder.AddFunction( - {OpSelect, state->uint_type, carry, non_zero, carry_part, ConstantU32(state, 0)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, high_less, high_part, carry}); - state->builder.AddFunction({OpShiftLeftLogical, state->uint_type, high_ge, low, dword_shift}); - *out_low = EmitSelectValueU32(state, less32, low_part, ConstantU32(state, 0)); - *out_high = EmitSelectValueU32(state, less32, high_less, high_ge); + const auto less32 = state.builder.AllocateId(); + const auto non_zero = state.builder.AllocateId(); + const auto carry_count_base = state.builder.AllocateId(); + const auto carry_count = state.builder.AllocateId(); + const auto low_part = state.builder.AllocateId(); + const auto high_part = state.builder.AllocateId(); + const auto carry_part = state.builder.AllocateId(); + const auto carry = state.builder.AllocateId(); + const auto high_less = state.builder.AllocateId(); + const auto high_ge = state.builder.AllocateId(); + state.builder.AddFunction( + {OpULessThan, state.bool_type, less32, amount, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, non_zero, amount, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpISub, state.uint_type, carry_count_base, ConstantU32(state, 32), dword_shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, carry_count, carry_count_base, ConstantU32(state, 31)}); + state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, low_part, low, dword_shift}); + state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, high_part, high, dword_shift}); + state.builder.AddFunction({OpShiftRightLogical, state.uint_type, carry_part, low, carry_count}); + state.builder.AddFunction( + {OpSelect, state.uint_type, carry, non_zero, carry_part, ConstantU32(state, 0)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, high_less, high_part, carry}); + state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, high_ge, low, dword_shift}); + out_low = EmitSelectValueU32(state, less32, low_part, ConstantU32(state, 0)); + out_high = EmitSelectValueU32(state, less32, high_less, high_ge); } -void EmitShiftLeftLogicalU64(EmitterState* state, const IR::Instruction& inst) { +void EmitShiftLeftLogicalU64(EmitterState& state, const IR::Instruction& inst) { const auto low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto shift = EmitValueLoad(state, inst.src[1]); uint32_t ret_low = 0; uint32_t ret_high = 0; - EmitShiftLeftLogicalU64Values(state, low, high, shift, &ret_low, &ret_high); + EmitShiftLeftLogicalU64Values(state, low, high, shift, ret_low, ret_high); EmitStoreU32(state, inst.dst, ret_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); } -void EmitShiftRightLogicalU64Values(EmitterState* state, uint32_t low, uint32_t high, - uint32_t shift, uint32_t* out_low, uint32_t* out_high) { +void EmitShiftRightLogicalU64Values(EmitterState& state, uint32_t low, uint32_t high, + uint32_t shift, uint32_t& out_low, uint32_t& out_high) { const auto amount = EmitAndConstant(state, shift, 63u); const auto dword_shift = EmitAndConstant(state, amount, 31u); - const auto less32 = state->builder.AllocateId(); - const auto non_zero = state->builder.AllocateId(); - const auto carry_count_base = state->builder.AllocateId(); - const auto carry_count = state->builder.AllocateId(); - const auto low_part = state->builder.AllocateId(); - const auto high_part = state->builder.AllocateId(); - const auto carry_part = state->builder.AllocateId(); - const auto carry = state->builder.AllocateId(); - const auto low_less = state->builder.AllocateId(); - const auto low_ge = state->builder.AllocateId(); - state->builder.AddFunction( - {OpULessThan, state->bool_type, less32, amount, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, non_zero, amount, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpISub, state->uint_type, carry_count_base, ConstantU32(state, 32), dword_shift}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, carry_count, carry_count_base, ConstantU32(state, 31)}); - state->builder.AddFunction({OpShiftRightLogical, state->uint_type, low_part, low, dword_shift}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, high_part, high, dword_shift}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, carry_part, high, carry_count}); - state->builder.AddFunction( - {OpSelect, state->uint_type, carry, non_zero, carry_part, ConstantU32(state, 0)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, low_less, low_part, carry}); - state->builder.AddFunction({OpShiftRightLogical, state->uint_type, low_ge, high, dword_shift}); - *out_low = EmitSelectValueU32(state, less32, low_less, low_ge); - *out_high = EmitSelectValueU32(state, less32, high_part, ConstantU32(state, 0)); + const auto less32 = state.builder.AllocateId(); + const auto non_zero = state.builder.AllocateId(); + const auto carry_count_base = state.builder.AllocateId(); + const auto carry_count = state.builder.AllocateId(); + const auto low_part = state.builder.AllocateId(); + const auto high_part = state.builder.AllocateId(); + const auto carry_part = state.builder.AllocateId(); + const auto carry = state.builder.AllocateId(); + const auto low_less = state.builder.AllocateId(); + const auto low_ge = state.builder.AllocateId(); + state.builder.AddFunction( + {OpULessThan, state.bool_type, less32, amount, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, non_zero, amount, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpISub, state.uint_type, carry_count_base, ConstantU32(state, 32), dword_shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, carry_count, carry_count_base, ConstantU32(state, 31)}); + state.builder.AddFunction({OpShiftRightLogical, state.uint_type, low_part, low, dword_shift}); + state.builder.AddFunction({OpShiftRightLogical, state.uint_type, high_part, high, dword_shift}); + state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, carry_part, high, carry_count}); + state.builder.AddFunction( + {OpSelect, state.uint_type, carry, non_zero, carry_part, ConstantU32(state, 0)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, low_less, low_part, carry}); + state.builder.AddFunction({OpShiftRightLogical, state.uint_type, low_ge, high, dword_shift}); + out_low = EmitSelectValueU32(state, less32, low_less, low_ge); + out_high = EmitSelectValueU32(state, less32, high_part, ConstantU32(state, 0)); } -void EmitShiftRightLogicalU64(EmitterState* state, const IR::Instruction& inst) { +void EmitShiftRightLogicalU64(EmitterState& state, const IR::Instruction& inst) { const auto low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto shift = EmitValueLoad(state, inst.src[1]); uint32_t ret_low = 0; uint32_t ret_high = 0; - EmitShiftRightLogicalU64Values(state, low, high, shift, &ret_low, &ret_high); + EmitShiftRightLogicalU64Values(state, low, high, shift, ret_low, ret_high); EmitStoreU32(state, inst.dst, ret_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); } -void EmitAdd3U32(EmitterState* state, const IR::Instruction& inst) { +void EmitAdd3U32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); const auto add = EmitValueLoad(state, inst.src[2]); - const auto tmp = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpIAdd, state->uint_type, tmp, lhs, rhs}); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, tmp, add}); + const auto tmp = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpIAdd, state.uint_type, tmp, lhs, rhs}); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, tmp, add}); EmitStoreU32(state, inst.dst, ret); } -uint32_t EmitAndConstant(EmitterState* state, uint32_t value, uint32_t mask) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, ret, value, ConstantU32(state, mask)}); +uint32_t EmitAndConstant(EmitterState& state, uint32_t value, uint32_t mask) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, ret, value, ConstantU32(state, mask)}); return ret; } -void EmitShiftU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitShiftU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 31u); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, ret, lhs, rhs}); EmitStoreU32(state, inst.dst, ret); } -void EmitBitClearU32(EmitterState* state, const IR::Instruction& inst) { +void EmitBitClearU32(EmitterState& state, const IR::Instruction& inst) { const auto value = EmitValueLoad(state, inst.src[0]); const auto bit = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 31u); - const auto mask = state->builder.AllocateId(); - const auto inv = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, mask, ConstantU32(state, 1), bit}); - state->builder.AddFunction({OpNot, state->uint_type, inv, mask}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, ret, value, inv}); + const auto mask = state.builder.AllocateId(); + const auto inv = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, mask, ConstantU32(state, 1), bit}); + state.builder.AddFunction({OpNot, state.uint_type, inv, mask}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, ret, value, inv}); EmitStoreU32(state, inst.dst, ret); } -void EmitBitSetU32(EmitterState* state, const IR::Instruction& inst) { +void EmitBitSetU32(EmitterState& state, const IR::Instruction& inst) { const auto value = EmitValueLoad(state, inst.src[0]); const auto bit = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 31u); - const auto mask = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, mask, ConstantU32(state, 1), bit}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, ret, value, mask}); + const auto mask = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, mask, ConstantU32(state, 1), bit}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, ret, value, mask}); EmitStoreU32(state, inst.dst, ret); } -uint32_t EmitNegateU32(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpSNegate, state->uint_type, ret, value}); +uint32_t EmitNegateU32(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpSNegate, state.uint_type, ret, value}); return ret; } -uint32_t EmitSignExtendLow16U32(EmitterState* state, uint32_t value) { - const auto signed_value = state->builder.AllocateId(); - const auto extracted = state->builder.AllocateId(); - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, signed_value, value}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, extracted, signed_value, - ConstantU32(state, 0), ConstantU32(state, 16)}); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, extracted}); +uint32_t EmitSignExtendLow16U32(EmitterState& state, uint32_t value) { + const auto signed_value = state.builder.AllocateId(); + const auto extracted = state.builder.AllocateId(); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, signed_value, value}); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, extracted, signed_value, + ConstantU32(state, 0), ConstantU32(state, 16)}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, extracted}); return bits; } -uint32_t EmitU16LaneBits(EmitterState* state, const IR::Operand& operand, bool high_lane, +uint32_t EmitU16LaneBits(EmitterState& state, const IR::Operand& operand, bool high_lane, bool sign_extend) { const auto raw = EmitValueLoad(state, operand); const auto lane = high_lane ? (operand.op_sel_hi ? 1u : 0u) : (operand.op_sel ? 1u : 0u); @@ -486,111 +479,110 @@ uint32_t EmitU16LaneBits(EmitterState* state, const IR::Operand& operand, bool h return sign_extend ? EmitSignExtendLow16U32(state, bits) : bits; } -void EmitShiftU16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode, +void EmitShiftU16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode, bool arithmetic) { const auto lhs = EmitU16LaneBits(state, inst.src[0], false, arithmetic); const auto rhs = EmitAndConstant(state, EmitU16LaneBits(state, inst.src[1], false), 0xfu); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, ret, lhs, rhs}); EmitStoreU32(state, inst.dst, EmitAndConstant(state, ret, 0xffffu)); } -void EmitBinaryU16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitBinaryU16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitU16LaneBits(state, inst.src[0], false); const auto rhs = EmitU16LaneBits(state, inst.src[1], false); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, ret, lhs, rhs}); EmitStoreU32(state, inst.dst, EmitAndConstant(state, ret, 0xffffu)); } -void EmitMinMaxU16(EmitterState* state, const IR::Instruction& inst, bool signed_value, +void EmitMinMaxU16(EmitterState& state, const IR::Instruction& inst, bool signed_value, bool max_value) { const auto lhs = EmitU16LaneBits(state, inst.src[0], false, signed_value); const auto rhs = EmitU16LaneBits(state, inst.src[1], false, signed_value); - const auto cond = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); + const auto cond = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); const auto op = signed_value ? (max_value ? OpSGreaterThan : OpSLessThan) : (max_value ? OpUGreaterThan : OpULessThan); - state->builder.AddFunction({op, state->bool_type, cond, lhs, rhs}); - state->builder.AddFunction({OpSelect, state->uint_type, ret, cond, lhs, rhs}); + state.builder.AddFunction({op, state.bool_type, cond, lhs, rhs}); + state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, lhs, rhs}); EmitStoreU32(state, inst.dst, EmitAndConstant(state, ret, 0xffffu)); } -uint32_t EmitXorConstant(EmitterState* state, uint32_t value, uint32_t mask) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseXor, state->uint_type, ret, value, ConstantU32(state, mask)}); +uint32_t EmitXorConstant(EmitterState& state, uint32_t value, uint32_t mask) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseXor, state.uint_type, ret, value, ConstantU32(state, mask)}); return ret; } -AddCarryResult EmitAddCarryValues(EmitterState* state, uint32_t lhs, uint32_t rhs, +AddCarryResult EmitAddCarryValues(EmitterState& state, uint32_t lhs, uint32_t rhs, uint32_t carry_in) { - const auto pair0 = state->builder.AllocateId(); - const auto sum0 = state->builder.AllocateId(); - const auto carry0 = state->builder.AllocateId(); - const auto pair1 = state->builder.AllocateId(); - const auto sum1 = state->builder.AllocateId(); - const auto carry1 = state->builder.AllocateId(); - const auto carry = state->builder.AllocateId(); - state->builder.AddFunction({OpIAddCarry, state->uint_pair_type, pair0, lhs, rhs}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, sum0, pair0, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, carry0, pair0, 1}); - state->builder.AddFunction({OpIAddCarry, state->uint_pair_type, pair1, sum0, carry_in}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, sum1, pair1, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, carry1, pair1, 1}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, carry, carry0, carry1}); + const auto pair0 = state.builder.AllocateId(); + const auto sum0 = state.builder.AllocateId(); + const auto carry0 = state.builder.AllocateId(); + const auto pair1 = state.builder.AllocateId(); + const auto sum1 = state.builder.AllocateId(); + const auto carry1 = state.builder.AllocateId(); + const auto carry = state.builder.AllocateId(); + state.builder.AddFunction({OpIAddCarry, state.uint_pair_type, pair0, lhs, rhs}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, sum0, pair0, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, carry0, pair0, 1}); + state.builder.AddFunction({OpIAddCarry, state.uint_pair_type, pair1, sum0, carry_in}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, sum1, pair1, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, carry1, pair1, 1}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, carry, carry0, carry1}); return {sum1, carry}; } -void EmitLaneMaskPairFromBool(EmitterState* state, const IR::Operand& dst, uint32_t value_bool) { - const auto write_mask = state->builder.AllocateId(); - state->builder.AddFunction( - {OpLogicalAnd, state->bool_type, write_mask, value_bool, EmitExecActiveBool(state)}); - if (state->per_invocation_masks) { +void EmitLaneMaskPairFromBool(EmitterState& state, const IR::Operand& dst, uint32_t value_bool) { + const auto write_mask = state.builder.AllocateId(); + state.builder.AddFunction( + {OpLogicalAnd, state.bool_type, write_mask, value_bool, EmitExecActiveBool(state)}); + if (state.per_invocation_masks) { EmitPerInvocationMask(state, dst, write_mask); return; } - const auto ballot = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformBallot, state->vec4_uint_type, ballot, - ConstantU32(state, ScopeSubgroup), write_mask}); + const auto ballot = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot, + ConstantU32(state, ScopeSubgroup), write_mask}); for (uint32_t part = 0; part < 2u; part++) { uint32_t result = ConstantU32(state, 0); - if (state->wave_size != 32u || part == 0u) { - result = state->builder.AllocateId(); - state->builder.AddFunction( - {OpCompositeExtract, state->uint_type, result, ballot, part}); + if (state.wave_size != 32u || part == 0u) { + result = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, result, ballot, part}); } EmitStoreU32(state, OffsetRegisterOperand(dst, part), result); } } -void EmitIAddCarryU32(EmitterState* state, const IR::Instruction& inst) { +void EmitIAddCarryU32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); const auto carry_in_active = EmitLaneMaskOperandActiveBool(state, inst.src[2]); - const auto carry_in = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->uint_type, carry_in, carry_in_active, - ConstantU32(state, 1), ConstantU32(state, 0)}); + const auto carry_in = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.uint_type, carry_in, carry_in_active, + ConstantU32(state, 1), ConstantU32(state, 0)}); const auto result = EmitAddCarryValues(state, lhs, rhs, carry_in); - const auto carry_bool = state->builder.AllocateId(); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, carry_bool, result.carry, ConstantU32(state, 0)}); + const auto carry_bool = state.builder.AllocateId(); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, carry_bool, result.carry, ConstantU32(state, 0)}); EmitStoreU32(state, inst.dst, result.sum); EmitLaneMaskPairFromBool(state, inst.dst2, carry_bool); } -void EmitISubBorrowU32(EmitterState* state, const IR::Instruction& inst) { +void EmitISubBorrowU32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); - const auto result = state->builder.AllocateId(); - const auto borrow = state->builder.AllocateId(); - state->builder.AddFunction({OpISub, state->uint_type, result, lhs, rhs}); - state->builder.AddFunction({OpUGreaterThan, state->bool_type, borrow, rhs, lhs}); + const auto result = state.builder.AllocateId(); + const auto borrow = state.builder.AllocateId(); + state.builder.AddFunction({OpISub, state.uint_type, result, lhs, rhs}); + state.builder.AddFunction({OpUGreaterThan, state.bool_type, borrow, rhs, lhs}); EmitStoreU32(state, inst.dst, result); EmitLaneMaskPairFromBool(state, inst.dst2, borrow); } -void EmitScalarAddCarryU32(EmitterState* state, const IR::Instruction& inst) { +void EmitScalarAddCarryU32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); const auto carry_in = EmitAndConstant(state, EmitValueLoad(state, inst.src[2]), 1u); @@ -599,239 +591,238 @@ void EmitScalarAddCarryU32(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, SccOperand(), result.carry); } -void EmitScalarSubBorrowU32(EmitterState* state, const IR::Instruction& inst) { +void EmitScalarSubBorrowU32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); - const auto result = state->builder.AllocateId(); - const auto borrow = state->builder.AllocateId(); - state->builder.AddFunction({OpISub, state->uint_type, result, lhs, rhs}); - state->builder.AddFunction({OpUGreaterThan, state->bool_type, borrow, rhs, lhs}); + const auto result = state.builder.AllocateId(); + const auto borrow = state.builder.AllocateId(); + state.builder.AddFunction({OpISub, state.uint_type, result, lhs, rhs}); + state.builder.AddFunction({OpUGreaterThan, state.bool_type, borrow, rhs, lhs}); EmitStoreU32(state, inst.dst, result); EmitStoreSccBool(state, borrow); } -void EmitScalarSubBorrowCarryU32(EmitterState* state, const IR::Instruction& inst) { +void EmitScalarSubBorrowCarryU32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); const auto borrow_in = EmitAndConstant(state, EmitValueLoad(state, inst.src[2]), 1u); - const auto partial = state->builder.AllocateId(); - const auto result = state->builder.AllocateId(); - const auto borrow0 = state->builder.AllocateId(); - const auto borrow1 = state->builder.AllocateId(); - state->builder.AddFunction({OpISub, state->uint_type, partial, lhs, rhs}); - state->builder.AddFunction({OpUGreaterThan, state->bool_type, borrow0, rhs, lhs}); - state->builder.AddFunction({OpISub, state->uint_type, result, partial, borrow_in}); - state->builder.AddFunction({OpUGreaterThan, state->bool_type, borrow1, borrow_in, partial}); + const auto partial = state.builder.AllocateId(); + const auto result = state.builder.AllocateId(); + const auto borrow0 = state.builder.AllocateId(); + const auto borrow1 = state.builder.AllocateId(); + state.builder.AddFunction({OpISub, state.uint_type, partial, lhs, rhs}); + state.builder.AddFunction({OpUGreaterThan, state.bool_type, borrow0, rhs, lhs}); + state.builder.AddFunction({OpISub, state.uint_type, result, partial, borrow_in}); + state.builder.AddFunction({OpUGreaterThan, state.bool_type, borrow1, borrow_in, partial}); EmitStoreU32(state, inst.dst, result); EmitStoreSccBool(state, EmitLogicalOrBool(state, borrow0, borrow1)); } -void EmitUMadU64U32(EmitterState* state, const IR::Instruction& inst) { +void EmitUMadU64U32(EmitterState& state, const IR::Instruction& inst) { const auto src0 = EmitValueLoad(state, inst.src[0]); const auto src1 = EmitValueLoad(state, inst.src[1]); const auto add_low = EmitSequentialValueLoad(state, inst.src[2], 0); const auto add_high = EmitSequentialValueLoad(state, inst.src[2], 1); - const auto mul_pair = state->builder.AllocateId(); - const auto mul_low = state->builder.AllocateId(); - const auto mul_high = state->builder.AllocateId(); - const auto low_pair = state->builder.AllocateId(); - const auto result_low = state->builder.AllocateId(); - const auto carry_low = state->builder.AllocateId(); - const auto high_pair = state->builder.AllocateId(); - const auto high_sum = state->builder.AllocateId(); - const auto carry_high0 = state->builder.AllocateId(); - const auto carry_pair = state->builder.AllocateId(); - const auto result_high = state->builder.AllocateId(); - const auto carry_high1 = state->builder.AllocateId(); - const auto carry = state->builder.AllocateId(); - const auto carry_bool = state->builder.AllocateId(); + const auto mul_pair = state.builder.AllocateId(); + const auto mul_low = state.builder.AllocateId(); + const auto mul_high = state.builder.AllocateId(); + const auto low_pair = state.builder.AllocateId(); + const auto result_low = state.builder.AllocateId(); + const auto carry_low = state.builder.AllocateId(); + const auto high_pair = state.builder.AllocateId(); + const auto high_sum = state.builder.AllocateId(); + const auto carry_high0 = state.builder.AllocateId(); + const auto carry_pair = state.builder.AllocateId(); + const auto result_high = state.builder.AllocateId(); + const auto carry_high1 = state.builder.AllocateId(); + const auto carry = state.builder.AllocateId(); + const auto carry_bool = state.builder.AllocateId(); - state->builder.AddFunction({OpUMulExtended, state->uint_pair_type, mul_pair, src0, src1}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, mul_low, mul_pair, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, mul_high, mul_pair, 1}); - state->builder.AddFunction({OpIAddCarry, state->uint_pair_type, low_pair, mul_low, add_low}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, result_low, low_pair, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, carry_low, low_pair, 1}); - state->builder.AddFunction({OpIAddCarry, state->uint_pair_type, high_pair, mul_high, add_high}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, high_sum, high_pair, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, carry_high0, high_pair, 1}); - state->builder.AddFunction( - {OpIAddCarry, state->uint_pair_type, carry_pair, high_sum, carry_low}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, result_high, carry_pair, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, carry_high1, carry_pair, 1}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, carry, carry_high0, carry_high1}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, carry_bool, carry, ConstantU32(state, 0)}); + state.builder.AddFunction({OpUMulExtended, state.uint_pair_type, mul_pair, src0, src1}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, mul_low, mul_pair, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, mul_high, mul_pair, 1}); + state.builder.AddFunction({OpIAddCarry, state.uint_pair_type, low_pair, mul_low, add_low}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, result_low, low_pair, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, carry_low, low_pair, 1}); + state.builder.AddFunction({OpIAddCarry, state.uint_pair_type, high_pair, mul_high, add_high}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, high_sum, high_pair, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, carry_high0, high_pair, 1}); + state.builder.AddFunction({OpIAddCarry, state.uint_pair_type, carry_pair, high_sum, carry_low}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, result_high, carry_pair, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, carry_high1, carry_pair, 1}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, carry, carry_high0, carry_high1}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, carry_bool, carry, ConstantU32(state, 0)}); EmitStoreU32(state, inst.dst, result_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), result_high); EmitLaneMaskPairFromBool(state, inst.dst2, carry_bool); } -void EmitScalarSignedOverflowI32(EmitterState* state, const IR::Instruction& inst, bool subtract) { +void EmitScalarSignedOverflowI32(EmitterState& state, const IR::Instruction& inst, bool subtract) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); - const auto result = state->builder.AllocateId(); - const auto lhs_sign = state->builder.AllocateId(); - const auto rhs_sign = state->builder.AllocateId(); - const auto result_sign = state->builder.AllocateId(); - const auto sign_match = state->builder.AllocateId(); - const auto sign_change = state->builder.AllocateId(); - const auto overflow = state->builder.AllocateId(); - state->builder.AddFunction({subtract ? OpISub : OpIAdd, state->uint_type, result, lhs, rhs}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, lhs_sign, lhs, ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, rhs_sign, rhs, ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, result_sign, result, ConstantU32(state, 31)}); - state->builder.AddFunction( - {subtract ? OpINotEqual : OpIEqual, state->bool_type, sign_match, lhs_sign, rhs_sign}); - state->builder.AddFunction({OpINotEqual, state->bool_type, sign_change, lhs_sign, result_sign}); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, overflow, sign_match, sign_change}); + const auto result = state.builder.AllocateId(); + const auto lhs_sign = state.builder.AllocateId(); + const auto rhs_sign = state.builder.AllocateId(); + const auto result_sign = state.builder.AllocateId(); + const auto sign_match = state.builder.AllocateId(); + const auto sign_change = state.builder.AllocateId(); + const auto overflow = state.builder.AllocateId(); + state.builder.AddFunction({subtract ? OpISub : OpIAdd, state.uint_type, result, lhs, rhs}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, lhs_sign, lhs, ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, rhs_sign, rhs, ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, result_sign, result, ConstantU32(state, 31)}); + state.builder.AddFunction( + {subtract ? OpINotEqual : OpIEqual, state.bool_type, sign_match, lhs_sign, rhs_sign}); + state.builder.AddFunction({OpINotEqual, state.bool_type, sign_change, lhs_sign, result_sign}); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, overflow, sign_match, sign_change}); EmitStoreU32(state, inst.dst, result); EmitStoreSccBool(state, overflow); } -void EmitScalarShiftLeftAddCarryU32(EmitterState* state, const IR::Instruction& inst) { +void EmitScalarShiftLeftAddCarryU32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[2]); const auto shift = inst.src[1].kind == IR::OperandKind::ImmediateU32 ? inst.src[1].imm : 0u; - const auto shifted = state->builder.AllocateId(); - const auto pair = state->builder.AllocateId(); - const auto result = state->builder.AllocateId(); - const auto add_carry = state->builder.AllocateId(); - const auto shifted_out = state->builder.AllocateId(); - const auto shift_carry = state->builder.AllocateId(); - const auto add_carry_bool = state->builder.AllocateId(); - const auto carry = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shifted, lhs, ConstantU32(state, shift)}); - state->builder.AddFunction({OpIAddCarry, state->uint_pair_type, pair, shifted, rhs}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, result, pair, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, add_carry, pair, 1}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, shifted_out, lhs, ConstantU32(state, 32u - shift)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, shift_carry, shifted_out, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, add_carry_bool, add_carry, ConstantU32(state, 0)}); - state->builder.AddFunction({OpLogicalOr, state->bool_type, carry, shift_carry, add_carry_bool}); + const auto shifted = state.builder.AllocateId(); + const auto pair = state.builder.AllocateId(); + const auto result = state.builder.AllocateId(); + const auto add_carry = state.builder.AllocateId(); + const auto shifted_out = state.builder.AllocateId(); + const auto shift_carry = state.builder.AllocateId(); + const auto add_carry_bool = state.builder.AllocateId(); + const auto carry = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shifted, lhs, ConstantU32(state, shift)}); + state.builder.AddFunction({OpIAddCarry, state.uint_pair_type, pair, shifted, rhs}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, result, pair, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, add_carry, pair, 1}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, shifted_out, lhs, ConstantU32(state, 32u - shift)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, shift_carry, shifted_out, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, add_carry_bool, add_carry, ConstantU32(state, 0)}); + state.builder.AddFunction({OpLogicalOr, state.bool_type, carry, shift_carry, add_carry_bool}); EmitStoreU32(state, inst.dst, result); EmitStoreSccBool(state, carry); } -void EmitMulU24U32(EmitterState* state, const IR::Instruction& inst) { +void EmitMulU24U32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitAndConstant(state, EmitValueLoad(state, inst.src[0]), 0x00ffffffu); const auto rhs = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 0x00ffffffu); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpIMul, state->uint_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpIMul, state.uint_type, ret, lhs, rhs}); EmitStoreU32(state, inst.dst, ret); } -void EmitMulI24U32(EmitterState* state, const IR::Instruction& inst) { +void EmitMulI24U32(EmitterState& state, const IR::Instruction& inst) { const auto lhs_bits = EmitValueLoad(state, inst.src[0]); const auto rhs_bits = EmitValueLoad(state, inst.src[1]); - const auto lhs_i32 = state->builder.AllocateId(); - const auto rhs_i32 = state->builder.AllocateId(); - const auto lhs_i24 = state->builder.AllocateId(); - const auto rhs_i24 = state->builder.AllocateId(); - const auto mul = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, lhs_i32, lhs_bits}); - state->builder.AddFunction({OpBitcast, state->int_type, rhs_i32, rhs_bits}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, lhs_i24, lhs_i32, - ConstantU32(state, 0), ConstantU32(state, 24)}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, rhs_i24, rhs_i32, - ConstantU32(state, 0), ConstantU32(state, 24)}); - state->builder.AddFunction({OpIMul, state->int_type, mul, lhs_i24, rhs_i24}); - state->builder.AddFunction({OpBitcast, state->uint_type, ret, mul}); + const auto lhs_i32 = state.builder.AllocateId(); + const auto rhs_i32 = state.builder.AllocateId(); + const auto lhs_i24 = state.builder.AllocateId(); + const auto rhs_i24 = state.builder.AllocateId(); + const auto mul = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, lhs_i32, lhs_bits}); + state.builder.AddFunction({OpBitcast, state.int_type, rhs_i32, rhs_bits}); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, lhs_i24, lhs_i32, + ConstantU32(state, 0), ConstantU32(state, 24)}); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, rhs_i24, rhs_i32, + ConstantU32(state, 0), ConstantU32(state, 24)}); + state.builder.AddFunction({OpIMul, state.int_type, mul, lhs_i24, rhs_i24}); + state.builder.AddFunction({OpBitcast, state.uint_type, ret, mul}); EmitStoreU32(state, inst.dst, ret); } -void EmitMulHighU32(EmitterState* state, const IR::Instruction& inst) { +void EmitMulHighU32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); - const auto full = state->builder.AllocateId(); - const auto high = state->builder.AllocateId(); - state->builder.AddFunction({OpUMulExtended, state->uint_pair_type, full, lhs, rhs}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, high, full, 1}); + const auto full = state.builder.AllocateId(); + const auto high = state.builder.AllocateId(); + state.builder.AddFunction({OpUMulExtended, state.uint_pair_type, full, lhs, rhs}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, high, full, 1}); EmitStoreU32(state, inst.dst, high); } -void EmitMulHighI32(EmitterState* state, const IR::Instruction& inst) { +void EmitMulHighI32(EmitterState& state, const IR::Instruction& inst) { const auto lhs_bits = EmitValueLoad(state, inst.src[0]); const auto rhs_bits = EmitValueLoad(state, inst.src[1]); - const auto lhs = state->builder.AllocateId(); - const auto rhs = state->builder.AllocateId(); - const auto full = state->builder.AllocateId(); - const auto high_i32 = state->builder.AllocateId(); - const auto high_u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, lhs, lhs_bits}); - state->builder.AddFunction({OpBitcast, state->int_type, rhs, rhs_bits}); - state->builder.AddFunction({OpSMulExtended, state->int_pair_type, full, lhs, rhs}); - state->builder.AddFunction({OpCompositeExtract, state->int_type, high_i32, full, 1}); - state->builder.AddFunction({OpBitcast, state->uint_type, high_u32, high_i32}); + const auto lhs = state.builder.AllocateId(); + const auto rhs = state.builder.AllocateId(); + const auto full = state.builder.AllocateId(); + const auto high_i32 = state.builder.AllocateId(); + const auto high_u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, lhs, lhs_bits}); + state.builder.AddFunction({OpBitcast, state.int_type, rhs, rhs_bits}); + state.builder.AddFunction({OpSMulExtended, state.int_pair_type, full, lhs, rhs}); + state.builder.AddFunction({OpCompositeExtract, state.int_type, high_i32, full, 1}); + state.builder.AddFunction({OpBitcast, state.uint_type, high_u32, high_i32}); EmitStoreU32(state, inst.dst, high_u32); } -void EmitMadU32U24(EmitterState* state, const IR::Instruction& inst) { +void EmitMadU32U24(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitAndConstant(state, EmitValueLoad(state, inst.src[0]), 0x00ffffffu); const auto rhs = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 0x00ffffffu); const auto add = EmitValueLoad(state, inst.src[2]); - const auto mul = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpIMul, state->uint_type, mul, lhs, rhs}); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, mul, add}); + const auto mul = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpIMul, state.uint_type, mul, lhs, rhs}); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, mul, add}); EmitStoreU32(state, inst.dst, ret); } -void EmitMadI32I24(EmitterState* state, const IR::Instruction& inst) { +void EmitMadI32I24(EmitterState& state, const IR::Instruction& inst) { const auto lhs_bits = EmitValueLoad(state, inst.src[0]); const auto rhs_bits = EmitValueLoad(state, inst.src[1]); const auto add_bits = EmitValueLoad(state, inst.src[2]); - const auto lhs_i32 = state->builder.AllocateId(); - const auto rhs_i32 = state->builder.AllocateId(); - const auto add_i32 = state->builder.AllocateId(); - const auto lhs_i24 = state->builder.AllocateId(); - const auto rhs_i24 = state->builder.AllocateId(); - const auto mul = state->builder.AllocateId(); - const auto add = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, lhs_i32, lhs_bits}); - state->builder.AddFunction({OpBitcast, state->int_type, rhs_i32, rhs_bits}); - state->builder.AddFunction({OpBitcast, state->int_type, add_i32, add_bits}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, lhs_i24, lhs_i32, - ConstantU32(state, 0), ConstantU32(state, 24)}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, rhs_i24, rhs_i32, - ConstantU32(state, 0), ConstantU32(state, 24)}); - state->builder.AddFunction({OpIMul, state->int_type, mul, lhs_i24, rhs_i24}); - state->builder.AddFunction({OpIAdd, state->int_type, add, mul, add_i32}); - state->builder.AddFunction({OpBitcast, state->uint_type, ret, add}); + const auto lhs_i32 = state.builder.AllocateId(); + const auto rhs_i32 = state.builder.AllocateId(); + const auto add_i32 = state.builder.AllocateId(); + const auto lhs_i24 = state.builder.AllocateId(); + const auto rhs_i24 = state.builder.AllocateId(); + const auto mul = state.builder.AllocateId(); + const auto add = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, lhs_i32, lhs_bits}); + state.builder.AddFunction({OpBitcast, state.int_type, rhs_i32, rhs_bits}); + state.builder.AddFunction({OpBitcast, state.int_type, add_i32, add_bits}); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, lhs_i24, lhs_i32, + ConstantU32(state, 0), ConstantU32(state, 24)}); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, rhs_i24, rhs_i32, + ConstantU32(state, 0), ConstantU32(state, 24)}); + state.builder.AddFunction({OpIMul, state.int_type, mul, lhs_i24, rhs_i24}); + state.builder.AddFunction({OpIAdd, state.int_type, add, mul, add_i32}); + state.builder.AddFunction({OpBitcast, state.uint_type, ret, add}); EmitStoreU32(state, inst.dst, ret); } -uint32_t EmitShiftLeftConstant(EmitterState* state, uint32_t value, uint32_t shift) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, ret, value, ConstantU32(state, shift)}); +uint32_t EmitShiftLeftConstant(EmitterState& state, uint32_t value, uint32_t shift) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, ret, value, ConstantU32(state, shift)}); return ret; } -uint32_t EmitShiftRightConstant(EmitterState* state, uint32_t value, uint32_t shift) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, ret, value, ConstantU32(state, shift)}); +uint32_t EmitShiftRightConstant(EmitterState& state, uint32_t value, uint32_t shift) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, ret, value, ConstantU32(state, shift)}); return ret; } -uint32_t EmitOrU32(EmitterState* state, uint32_t lhs, uint32_t rhs) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, ret, lhs, rhs}); +uint32_t EmitOrU32(EmitterState& state, uint32_t lhs, uint32_t rhs) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, ret, lhs, rhs}); return ret; } -uint32_t EmitBitReplicateHalfU32(EmitterState* state, uint32_t value) { +uint32_t EmitBitReplicateHalfU32(EmitterState& state, uint32_t value) { auto ret = EmitOrU32(state, value, EmitShiftLeftConstant(state, value, 8)); ret = EmitAndConstant(state, ret, 0x00ff00ffu); ret = EmitOrU32(state, ret, EmitShiftLeftConstant(state, ret, 4)); @@ -843,7 +834,7 @@ uint32_t EmitBitReplicateHalfU32(EmitterState* state, uint32_t value) { return EmitOrU32(state, ret, EmitShiftLeftConstant(state, ret, 1)); } -void EmitBitReplicateB64B32(EmitterState* state, const IR::Instruction& inst) { +void EmitBitReplicateB64B32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); const auto low = EmitBitReplicateHalfU32(state, EmitAndConstant(state, src, 0x0000ffffu)); const auto high = EmitBitReplicateHalfU32(state, EmitShiftRightConstant(state, src, 16)); @@ -851,66 +842,63 @@ void EmitBitReplicateB64B32(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), high); } -uint32_t EmitBitFieldExtractConstant(EmitterState* state, uint32_t value, uint32_t offset, +uint32_t EmitBitFieldExtractConstant(EmitterState& state, uint32_t value, uint32_t offset, uint32_t count) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitFieldUExtract, state->uint_type, ret, value, - ConstantU32(state, offset), ConstantU32(state, count)}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitFieldUExtract, state.uint_type, ret, value, + ConstantU32(state, offset), ConstantU32(state, count)}); return ret; } -uint32_t EmitRightAlignedMaskU32(EmitterState* state, uint32_t count) { - const auto shifted_one = state->builder.AllocateId(); - const auto mask = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shifted_one, ConstantU32(state, 1), count}); - state->builder.AddFunction( - {OpISub, state->uint_type, mask, shifted_one, ConstantU32(state, 1)}); +uint32_t EmitRightAlignedMaskU32(EmitterState& state, uint32_t count) { + const auto shifted_one = state.builder.AllocateId(); + const auto mask = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shifted_one, ConstantU32(state, 1), count}); + state.builder.AddFunction({OpISub, state.uint_type, mask, shifted_one, ConstantU32(state, 1)}); return mask; } -void EmitBitFieldMaskU32(EmitterState* state, const IR::Instruction& inst) { +void EmitBitFieldMaskU32(EmitterState& state, const IR::Instruction& inst) { const auto count = EmitAndConstant(state, EmitValueLoad(state, inst.src[0]), 31u); const auto offset = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 31u); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitFieldInsert, state->uint_type, ret, ConstantU32(state, 0), - ConstantU32(state, 0xffffffffu), offset, count}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitFieldInsert, state.uint_type, ret, ConstantU32(state, 0), + ConstantU32(state, 0xffffffffu), offset, count}); EmitStoreU32(state, inst.dst, ret); } -void EmitRightAlignedMaskU64(EmitterState* state, uint32_t count, uint32_t* out_low, - uint32_t* out_high) { - const auto count_lt32 = state->builder.AllocateId(); - const auto count_gt32 = state->builder.AllocateId(); - const auto low_count = state->builder.AllocateId(); - const auto high_base = state->builder.AllocateId(); - const auto high_count = state->builder.AllocateId(); - state->builder.AddFunction( - {OpULessThan, state->bool_type, count_lt32, count, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpUGreaterThan, state->bool_type, count_gt32, count, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, low_count, count_lt32, count, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpISub, state->uint_type, high_base, count, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, high_count, count_gt32, high_base, ConstantU32(state, 0)}); - *out_low = state->builder.AllocateId(); - *out_high = state->builder.AllocateId(); - state->builder.AddFunction({OpBitFieldInsert, state->uint_type, *out_low, ConstantU32(state, 0), - ConstantU32(state, 0xffffffffu), ConstantU32(state, 0), low_count}); - state->builder.AddFunction({OpBitFieldInsert, state->uint_type, *out_high, - ConstantU32(state, 0), ConstantU32(state, 0xffffffffu), - ConstantU32(state, 0), high_count}); +void EmitRightAlignedMaskU64(EmitterState& state, uint32_t count, uint32_t& out_low, + uint32_t& out_high) { + const auto count_lt32 = state.builder.AllocateId(); + const auto count_gt32 = state.builder.AllocateId(); + const auto low_count = state.builder.AllocateId(); + const auto high_base = state.builder.AllocateId(); + const auto high_count = state.builder.AllocateId(); + state.builder.AddFunction( + {OpULessThan, state.bool_type, count_lt32, count, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpUGreaterThan, state.bool_type, count_gt32, count, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, low_count, count_lt32, count, ConstantU32(state, 32)}); + state.builder.AddFunction({OpISub, state.uint_type, high_base, count, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, high_count, count_gt32, high_base, ConstantU32(state, 0)}); + out_low = state.builder.AllocateId(); + out_high = state.builder.AllocateId(); + state.builder.AddFunction({OpBitFieldInsert, state.uint_type, out_low, ConstantU32(state, 0), + ConstantU32(state, 0xffffffffu), ConstantU32(state, 0), low_count}); + state.builder.AddFunction({OpBitFieldInsert, state.uint_type, out_high, ConstantU32(state, 0), + ConstantU32(state, 0xffffffffu), ConstantU32(state, 0), high_count}); } -void EmitBitFieldMaskU64(EmitterState* state, const IR::Instruction& inst) { +void EmitBitFieldMaskU64(EmitterState& state, const IR::Instruction& inst) { const auto count = EmitAndConstant(state, EmitValueLoad(state, inst.src[0]), 63u); - if (state->per_invocation_masks && inst.dst.kind == IR::OperandKind::Register && + if (state.per_invocation_masks && inst.dst.kind == IR::OperandKind::Register && IsMaskRegisterFile(inst.dst.reg.file)) { - const auto active = state->builder.AllocateId(); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, active, count, ConstantU32(state, 0)}); + const auto active = state.builder.AllocateId(); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, active, count, ConstantU32(state, 0)}); EmitPerInvocationMask(state, inst.dst, active); return; } @@ -919,148 +907,146 @@ void EmitBitFieldMaskU64(EmitterState* state, const IR::Instruction& inst) { uint32_t high_mask = 0; uint32_t shifted_low = 0; uint32_t shifted_high = 0; - EmitRightAlignedMaskU64(state, count, &low_mask, &high_mask); - EmitShiftLeftLogicalU64Values(state, low_mask, high_mask, offset, &shifted_low, &shifted_high); + EmitRightAlignedMaskU64(state, count, low_mask, high_mask); + EmitShiftLeftLogicalU64Values(state, low_mask, high_mask, offset, shifted_low, shifted_high); EmitStoreU32(state, inst.dst, shifted_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), shifted_high); } -void EmitBitFieldExtractU64(EmitterState* state, const IR::Instruction& inst) { +void EmitBitFieldExtractU64(EmitterState& state, const IR::Instruction& inst) { const auto src_low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto src_high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto field = EmitValueLoad(state, inst.src[1]); const auto offset = EmitBitFieldExtractConstant(state, field, 0, 6); const auto raw_count = EmitBitFieldExtractConstant(state, field, 16, 7); - const auto available = state->builder.AllocateId(); - const auto use_raw = state->builder.AllocateId(); - const auto count = state->builder.AllocateId(); + const auto available = state.builder.AllocateId(); + const auto use_raw = state.builder.AllocateId(); + const auto count = state.builder.AllocateId(); uint32_t shifted_low = 0; uint32_t shifted_high = 0; uint32_t mask_low = 0; uint32_t mask_high = 0; - const auto ret_low = state->builder.AllocateId(); - const auto ret_high = state->builder.AllocateId(); - state->builder.AddFunction( - {OpISub, state->uint_type, available, ConstantU32(state, 64), offset}); - state->builder.AddFunction({OpULessThan, state->bool_type, use_raw, raw_count, available}); - state->builder.AddFunction({OpSelect, state->uint_type, count, use_raw, raw_count, available}); - EmitShiftRightLogicalU64Values(state, src_low, src_high, offset, &shifted_low, &shifted_high); - EmitRightAlignedMaskU64(state, count, &mask_low, &mask_high); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, ret_low, shifted_low, mask_low}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, ret_high, shifted_high, mask_high}); + const auto ret_low = state.builder.AllocateId(); + const auto ret_high = state.builder.AllocateId(); + state.builder.AddFunction({OpISub, state.uint_type, available, ConstantU32(state, 64), offset}); + state.builder.AddFunction({OpULessThan, state.bool_type, use_raw, raw_count, available}); + state.builder.AddFunction({OpSelect, state.uint_type, count, use_raw, raw_count, available}); + EmitShiftRightLogicalU64Values(state, src_low, src_high, offset, shifted_low, shifted_high); + EmitRightAlignedMaskU64(state, count, mask_low, mask_high); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, ret_low, shifted_low, mask_low}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, ret_high, shifted_high, mask_high}); EmitStoreU32(state, inst.dst, ret_low); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); } -void EmitBitFieldExtractU32(EmitterState* state, const IR::Instruction& inst) { +void EmitBitFieldExtractU32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); const auto field = EmitValueLoad(state, inst.src[1]); const auto offset = EmitBitFieldExtractConstant(state, field, 0, 5); const auto count = EmitBitFieldExtractConstant(state, field, 16, 7); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitFieldUExtract, state->uint_type, ret, src, offset, count}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitFieldUExtract, state.uint_type, ret, src, offset, count}); EmitStoreU32(state, inst.dst, ret); } -void EmitBitFieldExtract3U32(EmitterState* state, const IR::Instruction& inst, bool signed_value) { +void EmitBitFieldExtract3U32(EmitterState& state, const IR::Instruction& inst, bool signed_value) { const auto src = EmitValueLoad(state, inst.src[0]); const auto offset = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 31u); const auto count = EmitAndConstant(state, EmitValueLoad(state, inst.src[2]), 31u); - const auto ret = state->builder.AllocateId(); + const auto ret = state.builder.AllocateId(); if (signed_value) { - const auto shifted = state->builder.AllocateId(); + const auto shifted = state.builder.AllocateId(); const auto mask = EmitRightAlignedMaskU32(state, count); - state->builder.AddFunction( - {OpShiftRightArithmetic, state->uint_type, shifted, src, offset}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, ret, shifted, mask}); + state.builder.AddFunction({OpShiftRightArithmetic, state.uint_type, shifted, src, offset}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, ret, shifted, mask}); EmitStoreU32(state, inst.dst, ret); return; } - state->builder.AddFunction({OpBitFieldUExtract, state->uint_type, ret, src, offset, count}); + state.builder.AddFunction({OpBitFieldUExtract, state.uint_type, ret, src, offset, count}); EmitStoreU32(state, inst.dst, ret); } -void EmitBitFieldInsertSelectU32(EmitterState* state, const IR::Instruction& inst) { +void EmitBitFieldInsertSelectU32(EmitterState& state, const IR::Instruction& inst) { const auto mask = EmitValueLoad(state, inst.src[0]); const auto insert = EmitValueLoad(state, inst.src[1]); const auto base = EmitValueLoad(state, inst.src[2]); - const auto not_mask = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); - const auto preserved = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpNot, state->uint_type, not_mask, mask}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, selected, mask, insert}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, preserved, not_mask, base}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, ret, selected, preserved}); + const auto not_mask = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); + const auto preserved = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpNot, state.uint_type, not_mask, mask}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, selected, mask, insert}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, preserved, not_mask, base}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, ret, selected, preserved}); EmitStoreU32(state, inst.dst, ret); } -void EmitAlignBitU32(EmitterState* state, const IR::Instruction& inst) { +void EmitAlignBitU32(EmitterState& state, const IR::Instruction& inst) { const auto hi = EmitValueLoad(state, inst.src[0]); const auto lo = EmitValueLoad(state, inst.src[1]); const auto shift = EmitAndConstant(state, EmitValueLoad(state, inst.src[2]), 31u); - const auto lo_part = state->builder.AllocateId(); - const auto hi_shift_raw = state->builder.AllocateId(); - const auto hi_shift = state->builder.AllocateId(); - const auto hi_part_raw = state->builder.AllocateId(); - const auto non_zero = state->builder.AllocateId(); - const auto hi_part = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpShiftRightLogical, state->uint_type, lo_part, lo, shift}); - state->builder.AddFunction( - {OpISub, state->uint_type, hi_shift_raw, ConstantU32(state, 32), shift}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, hi_shift, hi_shift_raw, ConstantU32(state, 31)}); - state->builder.AddFunction({OpShiftLeftLogical, state->uint_type, hi_part_raw, hi, hi_shift}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, non_zero, shift, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, hi_part, non_zero, hi_part_raw, ConstantU32(state, 0)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, ret, lo_part, hi_part}); + const auto lo_part = state.builder.AllocateId(); + const auto hi_shift_raw = state.builder.AllocateId(); + const auto hi_shift = state.builder.AllocateId(); + const auto hi_part_raw = state.builder.AllocateId(); + const auto non_zero = state.builder.AllocateId(); + const auto hi_part = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpShiftRightLogical, state.uint_type, lo_part, lo, shift}); + state.builder.AddFunction( + {OpISub, state.uint_type, hi_shift_raw, ConstantU32(state, 32), shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, hi_shift, hi_shift_raw, ConstantU32(state, 31)}); + state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, hi_part_raw, hi, hi_shift}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, non_zero, shift, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, hi_part, non_zero, hi_part_raw, ConstantU32(state, 0)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, ret, lo_part, hi_part}); EmitStoreU32(state, inst.dst, ret); } -void EmitSelectU32(EmitterState* state, const IR::Instruction& inst) { +void EmitSelectU32(EmitterState& state, const IR::Instruction& inst) { const auto cond = EmitConditionBool(state, inst.src[0]); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->uint_type, ret, cond, - EmitValueLoad(state, inst.src[1]), - EmitValueLoad(state, inst.src[2])}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, + EmitValueLoad(state, inst.src[1]), + EmitValueLoad(state, inst.src[2])}); EmitStoreU32(state, inst.dst, ret); } -void EmitSelectMaskU32(EmitterState* state, const IR::Instruction& inst) { +void EmitSelectMaskU32(EmitterState& state, const IR::Instruction& inst) { const auto cond = EmitLaneMaskOperandActiveBool(state, inst.src[0]); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->uint_type, ret, cond, - EmitValueLoad(state, inst.src[1]), - EmitValueLoad(state, inst.src[2])}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, + EmitValueLoad(state, inst.src[1]), + EmitValueLoad(state, inst.src[2])}); EmitStoreU32(state, inst.dst, ret); } -void EmitSelectF32Bits(EmitterState* state, const IR::Instruction& inst) { +void EmitSelectF32Bits(EmitterState& state, const IR::Instruction& inst) { const auto cond = EmitConditionBool(state, inst.src[0]); - const auto selected = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->float_type, selected, cond, - EmitFloatLoad(state, inst.src[1]), - EmitFloatLoad(state, inst.src[2])}); - state->builder.AddFunction({OpBitcast, state->uint_type, ret, selected}); + const auto selected = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.float_type, selected, cond, + EmitFloatLoad(state, inst.src[1]), + EmitFloatLoad(state, inst.src[2])}); + state.builder.AddFunction({OpBitcast, state.uint_type, ret, selected}); EmitStoreU32(state, inst.dst, ret); } -void EmitSelectMaskF32Bits(EmitterState* state, const IR::Instruction& inst) { +void EmitSelectMaskF32Bits(EmitterState& state, const IR::Instruction& inst) { const auto cond = EmitLaneMaskOperandActiveBool(state, inst.src[0]); - const auto selected = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->float_type, selected, cond, - EmitFloatLoad(state, inst.src[1]), - EmitFloatLoad(state, inst.src[2])}); - state->builder.AddFunction({OpBitcast, state->uint_type, ret, selected}); + const auto selected = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.float_type, selected, cond, + EmitFloatLoad(state, inst.src[1]), + EmitFloatLoad(state, inst.src[2])}); + state.builder.AddFunction({OpBitcast, state.uint_type, ret, selected}); EmitStoreU32(state, inst.dst, ret); } -void EmitPackU16(EmitterState* state, const IR::Instruction& inst, bool high_src0, bool high_src1) { +void EmitPackU16(EmitterState& state, const IR::Instruction& inst, bool high_src0, bool high_src1) { const auto src0 = EmitValueLoad(state, inst.src[0]); const auto src1 = EmitValueLoad(state, inst.src[1]); const auto lo = high_src0 ? EmitBitFieldExtractConstant(state, src0, 16, 16) @@ -1068,108 +1054,106 @@ void EmitPackU16(EmitterState* state, const IR::Instruction& inst, bool high_src const auto hi = high_src1 ? EmitBitFieldExtractConstant(state, src1, 16, 16) : EmitAndConstant(state, src1, 0xffffu); const auto shifted = EmitShiftLeftConstant(state, hi, 16); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, ret, lo, shifted}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, ret, lo, shifted}); EmitStoreU32(state, inst.dst, ret); } -void EmitPackU8F32(EmitterState* state, const IR::Instruction& inst) { +void EmitPackU8F32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitFloatLoad(state, inst.src[0]); const auto byte_index = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 3u); const auto base = EmitValueLoad(state, inst.src[2]); const auto truncated = EmitTruncF32Value(state, src); - const auto below_zero = state->builder.AllocateId(); - const auto above_max = state->builder.AllocateId(); - const auto safe_low = state->builder.AllocateId(); - const auto safe_value = state->builder.AllocateId(); - const auto converted = state->builder.AllocateId(); - state->builder.AddFunction( - {OpFOrdLessThanEqual, state->bool_type, below_zero, src, ConstantF32(state, 0)}); - state->builder.AddFunction({OpFOrdGreaterThanEqual, state->bool_type, above_max, src, - ConstantF32(state, 0x437f0000u)}); + const auto below_zero = state.builder.AllocateId(); + const auto above_max = state.builder.AllocateId(); + const auto safe_low = state.builder.AllocateId(); + const auto safe_value = state.builder.AllocateId(); + const auto converted = state.builder.AllocateId(); + state.builder.AddFunction( + {OpFOrdLessThanEqual, state.bool_type, below_zero, src, ConstantF32(state, 0)}); + state.builder.AddFunction( + {OpFOrdGreaterThanEqual, state.bool_type, above_max, src, ConstantF32(state, 0x437f0000u)}); const auto zero_or_nan = EmitLogicalOrBool(state, EmitClassifyF32(state, src).nan, below_zero); - state->builder.AddFunction( - {OpSelect, state->float_type, safe_low, zero_or_nan, ConstantF32(state, 0), truncated}); - state->builder.AddFunction({OpSelect, state->float_type, safe_value, above_max, - ConstantF32(state, 0x437f0000u), safe_low}); - state->builder.AddFunction({OpConvertFToU, state->uint_type, converted, safe_value}); + state.builder.AddFunction( + {OpSelect, state.float_type, safe_low, zero_or_nan, ConstantF32(state, 0), truncated}); + state.builder.AddFunction({OpSelect, state.float_type, safe_value, above_max, + ConstantF32(state, 0x437f0000u), safe_low}); + state.builder.AddFunction({OpConvertFToU, state.uint_type, converted, safe_value}); const auto byte_value = EmitAndConstant(state, converted, 0xffu); - const auto shift = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shift, byte_index, ConstantU32(state, 3)}); - const auto byte_mask = state->builder.AllocateId(); - const auto inv_mask = state->builder.AllocateId(); - const auto cleared = state->builder.AllocateId(); - const auto shifted = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, byte_mask, ConstantU32(state, 0xffu), shift}); - state->builder.AddFunction({OpNot, state->uint_type, inv_mask, byte_mask}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, cleared, base, inv_mask}); - state->builder.AddFunction({OpShiftLeftLogical, state->uint_type, shifted, byte_value, shift}); + const auto shift = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shift, byte_index, ConstantU32(state, 3)}); + const auto byte_mask = state.builder.AllocateId(); + const auto inv_mask = state.builder.AllocateId(); + const auto cleared = state.builder.AllocateId(); + const auto shifted = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, byte_mask, ConstantU32(state, 0xffu), shift}); + state.builder.AddFunction({OpNot, state.uint_type, inv_mask, byte_mask}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, cleared, base, inv_mask}); + state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, shifted, byte_value, shift}); EmitStoreU32(state, inst.dst, EmitOrU32(state, cleared, shifted)); } -void EmitBinaryF32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitBinaryF32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitFloatLoad(state, inst.src[0]); const auto rhs = EmitFloatLoad(state, inst.src[1]); - const auto f32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->float_type, f32, lhs, rhs}); + const auto f32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.float_type, f32, lhs, rhs}); const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -void EmitLdexpF32(EmitterState* state, const IR::Instruction& inst) { +void EmitLdexpF32(EmitterState& state, const IR::Instruction& inst) { const auto value = EmitFloatLoad(state, inst.src[0]); const auto exp_bits = EmitValueLoad(state, inst.src[1]); - const auto exp_i32 = state->builder.AllocateId(); - const auto ret_f32 = state->builder.AllocateId(); - const auto ret_u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, exp_i32, exp_bits}); - state->builder.AddFunction( - {OpExtInst, state->float_type, ret_f32, state->glsl_std450, GlslLdexp, value, exp_i32}); + const auto exp_i32 = state.builder.AllocateId(); + const auto ret_f32 = state.builder.AllocateId(); + const auto ret_u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, exp_i32, exp_bits}); + state.builder.AddFunction( + {OpExtInst, state.float_type, ret_f32, state.glsl_std450, GlslLdexp, value, exp_i32}); const auto result = ApplyResultModifiersF32(state, ret_f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, ret_u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, ret_u32, result}); EmitStoreU32(state, inst.dst, ret_u32); } -uint32_t EmitCompareU32Constant(EmitterState* state, uint32_t opcode, uint32_t value, +uint32_t EmitCompareU32Constant(EmitterState& state, uint32_t opcode, uint32_t value, uint32_t constant) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {opcode, state->bool_type, ret, value, ConstantU32(state, constant)}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, ret, value, ConstantU32(state, constant)}); return ret; } -uint32_t EmitSubConstantMinusU32(EmitterState* state, uint32_t constant, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpISub, state->uint_type, ret, ConstantU32(state, constant), value}); +uint32_t EmitSubConstantMinusU32(EmitterState& state, uint32_t constant, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpISub, state.uint_type, ret, ConstantU32(state, constant), value}); return ret; } -uint32_t EmitF32ToF16RtzBits(EmitterState* state, uint32_t f32) { - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, f32}); +uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32) { + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, f32}); const auto sign = EmitAndConstant(state, EmitShiftRightConstant(state, bits, 16), 0x8000u); const auto exp = EmitAndConstant(state, EmitShiftRightConstant(state, bits, 23), 0xffu); const auto mant = EmitAndConstant(state, bits, 0x007fffffu); - const auto half_exp = state->builder.AllocateId(); - const auto normal_exp = state->builder.AllocateId(); + const auto half_exp = state.builder.AllocateId(); + const auto normal_exp = state.builder.AllocateId(); const auto normal_mant = EmitShiftRightConstant(state, mant, 13); - const auto normal_payload = state->builder.AllocateId(); - const auto normal = state->builder.AllocateId(); - state->builder.AddFunction({OpISub, state->uint_type, half_exp, exp, ConstantU32(state, 112)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, normal_exp, half_exp, ConstantU32(state, 10)}); - state->builder.AddFunction( - {OpBitwiseOr, state->uint_type, normal_payload, normal_exp, normal_mant}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, normal, sign, normal_payload}); + const auto normal_payload = state.builder.AllocateId(); + const auto normal = state.builder.AllocateId(); + state.builder.AddFunction({OpISub, state.uint_type, half_exp, exp, ConstantU32(state, 112)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, normal_exp, half_exp, ConstantU32(state, 10)}); + state.builder.AddFunction( + {OpBitwiseOr, state.uint_type, normal_payload, normal_exp, normal_mant}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, normal, sign, normal_payload}); const auto mant_with_hidden = EmitOrU32(state, mant, ConstantU32(state, 0x00800000u)); const auto raw_sub_shift = EmitSubConstantMinusU32(state, 126, exp); @@ -1179,11 +1163,11 @@ uint32_t EmitF32ToF16RtzBits(EmitterState* state, uint32_t f32) { EmitSelectValueU32(state, exp_lt_103, ConstantU32(state, 31), raw_sub_shift); const auto sub_shift = EmitSelectValueU32(state, exp_gt_112, ConstantU32(state, 14), sub_shift_low); - const auto sub_mant = state->builder.AllocateId(); - const auto subnormal = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, sub_mant, mant_with_hidden, sub_shift}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, subnormal, sign, sub_mant}); + const auto sub_mant = state.builder.AllocateId(); + const auto subnormal = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, sub_mant, mant_with_hidden, sub_shift}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, subnormal, sign, sub_mant}); const auto nan_payload = EmitOrU32(state, EmitShiftRightConstant(state, mant, 13), ConstantU32(state, 0x0200u)); @@ -1203,7 +1187,7 @@ uint32_t EmitF32ToF16RtzBits(EmitterState* state, uint32_t f32) { return EmitAndConstant(state, EmitSelectValueU32(state, exp_eq_255, special, finite2), 0xffffu); } -void EmitPackF32ToF16Rtz(EmitterState* state, const IR::Instruction& inst) { +void EmitPackF32ToF16Rtz(EmitterState& state, const IR::Instruction& inst) { const auto lo = EmitF32ToF16RtzBits(state, EmitFloatLoad(state, inst.src[0])); const auto hi = EmitF32ToF16RtzBits(state, EmitFloatLoad(state, inst.src[1])); const auto shifted = EmitShiftLeftConstant(state, hi, 16); @@ -1211,63 +1195,62 @@ void EmitPackF32ToF16Rtz(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, inst.dst, ret); } -void EmitPackNormalizedF32(EmitterState* state, const IR::Instruction& inst, uint32_t ext_inst) { +void EmitPackNormalizedF32(EmitterState& state, const IR::Instruction& inst, uint32_t ext_inst) { const auto src0 = EmitFloatLoad(state, inst.src[0]); const auto src1 = EmitFloatLoad(state, inst.src[1]); - const auto pair = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec2_float_type, pair, src0, src1}); - state->builder.AddFunction( - {OpExtInst, state->uint_type, ret, state->glsl_std450, ext_inst, pair}); + const auto pair = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, pair, src0, src1}); + state.builder.AddFunction({OpExtInst, state.uint_type, ret, state.glsl_std450, ext_inst, pair}); EmitStoreU32(state, inst.dst, ret); } -uint32_t EmitMinMaxU32Value(EmitterState* state, uint32_t lhs, uint32_t rhs, bool max_value) { - const auto cond = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {max_value ? OpUGreaterThan : OpULessThan, state->bool_type, cond, lhs, rhs}); - state->builder.AddFunction({OpSelect, state->uint_type, ret, cond, lhs, rhs}); +uint32_t EmitMinMaxU32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) { + const auto cond = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {max_value ? OpUGreaterThan : OpULessThan, state.bool_type, cond, lhs, rhs}); + state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, lhs, rhs}); return ret; } -void EmitMinMaxU32(EmitterState* state, const IR::Instruction& inst, bool max_value) { +void EmitMinMaxU32(EmitterState& state, const IR::Instruction& inst, bool max_value) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); const auto ret = EmitMinMaxU32Value(state, lhs, rhs, max_value); EmitStoreU32(state, inst.dst, ret); } -void EmitSadU32(EmitterState* state, const IR::Instruction& inst) { +void EmitSadU32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); const auto add = EmitValueLoad(state, inst.src[2]); const auto high = EmitMinMaxU32Value(state, lhs, rhs, true); const auto low = EmitMinMaxU32Value(state, lhs, rhs, false); - const auto diff = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpISub, state->uint_type, diff, high, low}); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, diff, add}); + const auto diff = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpISub, state.uint_type, diff, high, low}); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, diff, add}); EmitStoreU32(state, inst.dst, ret); } -uint32_t EmitMinMaxI32Value(EmitterState* state, uint32_t lhs, uint32_t rhs, bool max_value) { - const auto cond = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {max_value ? OpSGreaterThan : OpSLessThan, state->bool_type, cond, lhs, rhs}); - state->builder.AddFunction({OpSelect, state->uint_type, ret, cond, lhs, rhs}); +uint32_t EmitMinMaxI32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) { + const auto cond = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {max_value ? OpSGreaterThan : OpSLessThan, state.bool_type, cond, lhs, rhs}); + state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, lhs, rhs}); return ret; } -void EmitMinMaxI32(EmitterState* state, const IR::Instruction& inst, bool max_value) { +void EmitMinMaxI32(EmitterState& state, const IR::Instruction& inst, bool max_value) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); const auto ret = EmitMinMaxI32Value(state, lhs, rhs, max_value); EmitStoreU32(state, inst.dst, ret); } -void EmitMinMax3U32(EmitterState* state, const IR::Instruction& inst, bool signed_value, +void EmitMinMax3U32(EmitterState& state, const IR::Instruction& inst, bool signed_value, bool max_value) { const auto src0 = EmitValueLoad(state, inst.src[0]); const auto src1 = EmitValueLoad(state, inst.src[1]); @@ -1279,7 +1262,7 @@ void EmitMinMax3U32(EmitterState* state, const IR::Instruction& inst, bool signe EmitStoreU32(state, inst.dst, ret); } -void EmitMed3U32(EmitterState* state, const IR::Instruction& inst, bool signed_value) { +void EmitMed3U32(EmitterState& state, const IR::Instruction& inst, bool signed_value) { const auto src0 = EmitValueLoad(state, inst.src[0]); const auto src1 = EmitValueLoad(state, inst.src[1]); const auto src2 = EmitValueLoad(state, inst.src[2]); @@ -1294,43 +1277,43 @@ void EmitMed3U32(EmitterState* state, const IR::Instruction& inst, bool signed_v EmitStoreU32(state, inst.dst, ret); } -uint32_t EmitBitcastF32ToU32(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, ret, value}); +uint32_t EmitBitcastF32ToU32(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, ret, value}); return ret; } -uint32_t EmitBitcastU32ToF32(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->float_type, ret, value}); +uint32_t EmitBitcastU32ToF32(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.float_type, ret, value}); return ret; } -uint32_t EmitAndU32(EmitterState* state, uint32_t lhs, uint32_t rhs) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, ret, lhs, rhs}); +uint32_t EmitAndU32(EmitterState& state, uint32_t lhs, uint32_t rhs) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, ret, lhs, rhs}); return ret; } -uint32_t EmitLogicalAndBool(EmitterState* state, uint32_t lhs, uint32_t rhs) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, ret, lhs, rhs}); +uint32_t EmitLogicalAndBool(EmitterState& state, uint32_t lhs, uint32_t rhs) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, ret, lhs, rhs}); return ret; } -uint32_t EmitLogicalOrBool(EmitterState* state, uint32_t lhs, uint32_t rhs) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalOr, state->bool_type, ret, lhs, rhs}); +uint32_t EmitLogicalOrBool(EmitterState& state, uint32_t lhs, uint32_t rhs) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalOr, state.bool_type, ret, lhs, rhs}); return ret; } -uint32_t EmitLogicalNotBool(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalNot, state->bool_type, ret, value}); +uint32_t EmitLogicalNotBool(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalNot, state.bool_type, ret, value}); return ret; } -F32Class EmitClassifyF32(EmitterState* state, uint32_t value) { +F32Class EmitClassifyF32(EmitterState& state, uint32_t value) { F32Class cls; cls.bits = EmitBitcastF32ToU32(state, value); const auto abs_bits = EmitAndConstant(state, cls.bits, 0x7fffffffu); @@ -1347,14 +1330,14 @@ F32Class EmitClassifyF32(EmitterState* state, uint32_t value) { return cls; } -uint32_t EmitClassMaskBitMatch(EmitterState* state, uint32_t mask, uint32_t bit, +uint32_t EmitClassMaskBitMatch(EmitterState& state, uint32_t mask, uint32_t bit, uint32_t class_match) { const auto selected = EmitCompareU32Constant(state, OpINotEqual, EmitAndConstant(state, mask, 1u << bit), 0); return EmitLogicalAndBool(state, selected, class_match); } -uint32_t EmitClassMaskF32(EmitterState* state, uint32_t value, uint32_t mask) { +uint32_t EmitClassMaskF32(EmitterState& state, uint32_t value, uint32_t mask) { const auto bits = EmitBitcastF32ToU32(state, value); const auto sign_bits = EmitAndConstant(state, bits, 0x80000000u); const auto abs_bits = EmitAndConstant(state, bits, 0x7fffffffu); @@ -1406,13 +1389,13 @@ uint32_t EmitClassMaskF32(EmitterState* state, uint32_t value, uint32_t mask) { EmitClassMaskBitMatch(state, mask, 9, EmitLogicalAndBool(state, inf, positive))); } -uint32_t EmitMinMaxF32Value(EmitterState* state, uint32_t lhs, uint32_t rhs, bool max_value) { +uint32_t EmitMinMaxF32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) { const auto lhs_class = EmitClassifyF32(state, lhs); const auto rhs_class = EmitClassifyF32(state, rhs); - const auto numeric_cond = state->builder.AllocateId(); - state->builder.AddFunction({max_value ? OpFOrdGreaterThanEqual : OpFOrdLessThan, - state->bool_type, numeric_cond, lhs, rhs}); + const auto numeric_cond = state.builder.AllocateId(); + state.builder.AddFunction({max_value ? OpFOrdGreaterThanEqual : OpFOrdLessThan, state.bool_type, + numeric_cond, lhs, rhs}); const auto ordered_bits = EmitSelectValueU32(state, numeric_cond, lhs_class.bits, rhs_class.bits); @@ -1432,21 +1415,21 @@ uint32_t EmitMinMaxF32Value(EmitterState* state, uint32_t lhs, uint32_t rhs, boo return EmitBitcastU32ToF32(state, result_bits); } -void EmitMinMaxF32(EmitterState* state, const IR::Instruction& inst, bool max_value) { +void EmitMinMaxF32(EmitterState& state, const IR::Instruction& inst, bool max_value) { const auto lhs = EmitFloatLoad(state, inst.src[0]); const auto rhs = EmitFloatLoad(state, inst.src[1]); - const auto u32 = state->builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); const auto f32 = EmitMinMaxF32Value(state, lhs, rhs, max_value); const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -void EmitCompareResult(EmitterState* state, const IR::Operand& dst, uint32_t cond) { +void EmitCompareResult(EmitterState& state, const IR::Operand& dst, uint32_t cond) { if (IsSccOperand(dst)) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, cond, ConstantU32(state, 1), ConstantU32(state, 0)}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, cond, ConstantU32(state, 1), ConstantU32(state, 0)}); EmitStoreU32(state, dst, ret); return; } @@ -1454,156 +1437,156 @@ void EmitCompareResult(EmitterState* state, const IR::Operand& dst, uint32_t con EmitLaneMaskPairFromBool(state, dst, cond); } -void EmitCompareU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitCompareU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->bool_type, cond, lhs, rhs}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, cond, lhs, rhs}); EmitCompareResult(state, inst.dst, cond); } -void EmitCompareU16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitCompareU16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitAndConstant(state, EmitValueLoad(state, inst.src[0]), 0xffffu); const auto rhs = EmitAndConstant(state, EmitValueLoad(state, inst.src[1]), 0xffffu); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->bool_type, cond, lhs, rhs}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, cond, lhs, rhs}); EmitCompareResult(state, inst.dst, cond); } -void EmitCompareI16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitCompareI16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitSignExtendLow16U32(state, EmitValueLoad(state, inst.src[0])); const auto rhs = EmitSignExtendLow16U32(state, EmitValueLoad(state, inst.src[1])); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->bool_type, cond, lhs, rhs}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, cond, lhs, rhs}); EmitCompareResult(state, inst.dst, cond); } -void EmitBitCompareB32(EmitterState* state, const IR::Instruction& inst, bool bit_set) { +void EmitBitCompareB32(EmitterState& state, const IR::Instruction& inst, bool bit_set) { const auto value = EmitValueLoad(state, inst.src[0]); - const auto bit_index = state->builder.AllocateId(); - const auto bit = state->builder.AllocateId(); - const auto cond = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, bit_index, - EmitValueLoad(state, inst.src[1]), ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpBitFieldUExtract, state->uint_type, bit, value, bit_index, ConstantU32(state, 1)}); - state->builder.AddFunction( - {OpIEqual, state->bool_type, cond, bit, ConstantU32(state, bit_set ? 1u : 0u)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, cond, ConstantU32(state, 1), ConstantU32(state, 0)}); + const auto bit_index = state.builder.AllocateId(); + const auto bit = state.builder.AllocateId(); + const auto cond = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, bit_index, + EmitValueLoad(state, inst.src[1]), ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpBitFieldUExtract, state.uint_type, bit, value, bit_index, ConstantU32(state, 1)}); + state.builder.AddFunction( + {OpIEqual, state.bool_type, cond, bit, ConstantU32(state, bit_set ? 1u : 0u)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, cond, ConstantU32(state, 1), ConstantU32(state, 0)}); EmitStoreU32(state, inst.dst, ret); } -void EmitCompareNeU64(EmitterState* state, const IR::Instruction& inst) { +void EmitCompareNeU64(EmitterState& state, const IR::Instruction& inst) { const auto lhs_low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0); const auto rhs_high = EmitSequentialValueLoad(state, inst.src[1], 1); - const auto ne_low = state->builder.AllocateId(); - const auto ne_high = state->builder.AllocateId(); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({OpINotEqual, state->bool_type, ne_low, lhs_low, rhs_low}); - state->builder.AddFunction({OpINotEqual, state->bool_type, ne_high, lhs_high, rhs_high}); - state->builder.AddFunction({OpLogicalOr, state->bool_type, cond, ne_low, ne_high}); + const auto ne_low = state.builder.AllocateId(); + const auto ne_high = state.builder.AllocateId(); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({OpINotEqual, state.bool_type, ne_low, lhs_low, rhs_low}); + state.builder.AddFunction({OpINotEqual, state.bool_type, ne_high, lhs_high, rhs_high}); + state.builder.AddFunction({OpLogicalOr, state.bool_type, cond, ne_low, ne_high}); EmitCompareResult(state, inst.dst, cond); } -void EmitCompareConstant(EmitterState* state, const IR::Instruction& inst, bool value) { - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({value ? OpIEqual : OpINotEqual, state->bool_type, cond, - ConstantU32(state, 0), ConstantU32(state, 0)}); +void EmitCompareConstant(EmitterState& state, const IR::Instruction& inst, bool value) { + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({value ? OpIEqual : OpINotEqual, state.bool_type, cond, + ConstantU32(state, 0), ConstantU32(state, 0)}); EmitCompareResult(state, inst.dst, cond); } -void EmitCompareMaskU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitCompareMaskU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitValueLoad(state, inst.src[0]); const auto rhs = EmitValueLoad(state, inst.src[1]); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->bool_type, cond, lhs, rhs}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, cond, lhs, rhs}); EmitCompareResult(state, inst.dst, cond); } -void EmitCompareF32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitCompareF32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitFloatLoad(state, inst.src[0]); const auto rhs = EmitFloatLoad(state, inst.src[1]); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->bool_type, cond, lhs, rhs}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, cond, lhs, rhs}); EmitCompareResult(state, inst.dst, cond); } -void EmitCompareOrderedF32(EmitterState* state, const IR::Instruction& inst, bool ordered) { +void EmitCompareOrderedF32(EmitterState& state, const IR::Instruction& inst, bool ordered) { const auto lhs = EmitFloatLoad(state, inst.src[0]); const auto rhs = EmitFloatLoad(state, inst.src[1]); - const auto lhs_check = state->builder.AllocateId(); - const auto rhs_check = state->builder.AllocateId(); - const auto cond = state->builder.AllocateId(); + const auto lhs_check = state.builder.AllocateId(); + const auto rhs_check = state.builder.AllocateId(); + const auto cond = state.builder.AllocateId(); if (ordered) { - state->builder.AddFunction({OpFOrdEqual, state->bool_type, lhs_check, lhs, lhs}); - state->builder.AddFunction({OpFOrdEqual, state->bool_type, rhs_check, rhs, rhs}); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, cond, lhs_check, rhs_check}); + state.builder.AddFunction({OpFOrdEqual, state.bool_type, lhs_check, lhs, lhs}); + state.builder.AddFunction({OpFOrdEqual, state.bool_type, rhs_check, rhs, rhs}); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, cond, lhs_check, rhs_check}); } else { - state->builder.AddFunction({OpFUnordNotEqual, state->bool_type, lhs_check, lhs, lhs}); - state->builder.AddFunction({OpFUnordNotEqual, state->bool_type, rhs_check, rhs, rhs}); - state->builder.AddFunction({OpLogicalOr, state->bool_type, cond, lhs_check, rhs_check}); + state.builder.AddFunction({OpFUnordNotEqual, state.bool_type, lhs_check, lhs, lhs}); + state.builder.AddFunction({OpFUnordNotEqual, state.bool_type, rhs_check, rhs, rhs}); + state.builder.AddFunction({OpLogicalOr, state.bool_type, cond, lhs_check, rhs_check}); } EmitCompareResult(state, inst.dst, cond); } -void EmitCompareClassF32(EmitterState* state, const IR::Instruction& inst) { +void EmitCompareClassF32(EmitterState& state, const IR::Instruction& inst) { const auto value = EmitFloatLoad(state, inst.src[0]); const auto mask = EmitValueLoad(state, inst.src[1]); EmitCompareResult(state, inst.dst, EmitClassMaskF32(state, value, mask)); } -void EmitCompareMaskF32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitCompareMaskF32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitFloatLoad(state, inst.src[0]); const auto rhs = EmitFloatLoad(state, inst.src[1]); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->bool_type, cond, lhs, rhs}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, cond, lhs, rhs}); EmitCompareResult(state, inst.dst, cond); } -void EmitConvertU32ToF32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertU32ToF32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto f32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertUToF, state->float_type, f32, src}); + const auto f32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertUToF, state.float_type, f32, src}); const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -void EmitConvertI32ToF32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertI32ToF32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto i32 = state->builder.AllocateId(); - const auto f32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, i32, src}); - state->builder.AddFunction({OpConvertSToF, state->float_type, f32, i32}); + const auto i32 = state.builder.AllocateId(); + const auto f32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, i32, src}); + state.builder.AddFunction({OpConvertSToF, state.float_type, f32, i32}); const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -uint32_t EmitTruncF32Value(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, ret, state->glsl_std450, GlslTrunc, value}); +uint32_t EmitTruncF32Value(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, ret, state.glsl_std450, GlslTrunc, value}); return ret; } -void EmitConvertF32ToU32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertF32ToU32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitFloatLoad(state, inst.src[0]); const auto trunc = EmitTruncF32Value(state, src); - const auto converted = state->builder.AllocateId(); - const auto below_zero = state->builder.AllocateId(); - const auto above_max = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertFToU, state->uint_type, converted, trunc}); - state->builder.AddFunction( - {OpFOrdLessThanEqual, state->bool_type, below_zero, src, ConstantF32(state, 0)}); - state->builder.AddFunction({OpFOrdGreaterThanEqual, state->bool_type, above_max, src, - ConstantF32(state, 0x4f800000u)}); + const auto converted = state.builder.AllocateId(); + const auto below_zero = state.builder.AllocateId(); + const auto above_max = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertFToU, state.uint_type, converted, trunc}); + state.builder.AddFunction( + {OpFOrdLessThanEqual, state.bool_type, below_zero, src, ConstantF32(state, 0)}); + state.builder.AddFunction( + {OpFOrdGreaterThanEqual, state.bool_type, above_max, src, ConstantF32(state, 0x4f800000u)}); const auto zero_or_nan = EmitLogicalOrBool(state, EmitClassifyF32(state, src).nan, below_zero); const auto saturated = EmitSelectValueU32(state, above_max, ConstantU32(state, 0xffffffffu), converted); @@ -1611,19 +1594,19 @@ void EmitConvertF32ToU32(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, inst.dst, ret); } -void EmitConvertF32ToI32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertF32ToI32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitFloatLoad(state, inst.src[0]); const auto trunc = EmitTruncF32Value(state, src); - const auto i32 = state->builder.AllocateId(); - const auto converted = state->builder.AllocateId(); - const auto below_min = state->builder.AllocateId(); - const auto above_max = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertFToS, state->int_type, i32, trunc}); - state->builder.AddFunction({OpBitcast, state->uint_type, converted, i32}); - state->builder.AddFunction( - {OpFOrdLessThanEqual, state->bool_type, below_min, src, ConstantF32(state, 0xcf000000u)}); - state->builder.AddFunction({OpFOrdGreaterThanEqual, state->bool_type, above_max, src, - ConstantF32(state, 0x4f000000u)}); + const auto i32 = state.builder.AllocateId(); + const auto converted = state.builder.AllocateId(); + const auto below_min = state.builder.AllocateId(); + const auto above_max = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertFToS, state.int_type, i32, trunc}); + state.builder.AddFunction({OpBitcast, state.uint_type, converted, i32}); + state.builder.AddFunction( + {OpFOrdLessThanEqual, state.bool_type, below_min, src, ConstantF32(state, 0xcf000000u)}); + state.builder.AddFunction( + {OpFOrdGreaterThanEqual, state.bool_type, above_max, src, ConstantF32(state, 0x4f000000u)}); const auto high_sat = EmitSelectValueU32(state, above_max, ConstantU32(state, 0x7fffffffu), converted); const auto low_sat = @@ -1633,261 +1616,260 @@ void EmitConvertF32ToI32(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, inst.dst, ret); } -void EmitConvertF32ToF16(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertF32ToF16(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitFloatLoad(state, inst.src[0]); - const auto pair = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpCompositeConstruct, state->vec2_float_type, pair, src, ConstantF32(state, 0)}); - state->builder.AddFunction( - {OpExtInst, state->uint_type, u32, state->glsl_std450, GlslPackHalf2x16, pair}); + const auto pair = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpCompositeConstruct, state.vec2_float_type, pair, src, ConstantF32(state, 0)}); + state.builder.AddFunction( + {OpExtInst, state.uint_type, u32, state.glsl_std450, GlslPackHalf2x16, pair}); EmitStoreU32(state, inst.dst, u32); } -void EmitConvertF16ToF32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertF16ToF32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto unpacked = state->builder.AllocateId(); - auto f32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->vec2_float_type, unpacked, state->glsl_std450, GlslUnpackHalf2x16, src}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, f32, unpacked, 0}); + const auto unpacked = state.builder.AllocateId(); + auto f32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, src}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, f32, unpacked, 0}); if (inst.src[0].absolute) { - const auto abs_value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, abs_value, state->glsl_std450, GlslFAbs, f32}); + const auto abs_value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, abs_value, state.glsl_std450, GlslFAbs, f32}); f32 = abs_value; } if (inst.src[0].negate) { - const auto neg_value = state->builder.AllocateId(); - state->builder.AddFunction({OpFNegate, state->float_type, neg_value, f32}); + const auto neg_value = state.builder.AllocateId(); + state.builder.AddFunction({OpFNegate, state.float_type, neg_value, f32}); f32 = neg_value; } const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -void EmitConvertF16ToU16(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertF16ToU16(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto unpacked = state->builder.AllocateId(); - auto f32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->vec2_float_type, unpacked, state->glsl_std450, GlslUnpackHalf2x16, src}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, f32, unpacked, 0}); + const auto unpacked = state.builder.AllocateId(); + auto f32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, src}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, f32, unpacked, 0}); if (inst.src[0].absolute) { - const auto abs_value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, abs_value, state->glsl_std450, GlslFAbs, f32}); + const auto abs_value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, abs_value, state.glsl_std450, GlslFAbs, f32}); f32 = abs_value; } if (inst.src[0].negate) { - const auto neg_value = state->builder.AllocateId(); - state->builder.AddFunction({OpFNegate, state->float_type, neg_value, f32}); + const auto neg_value = state.builder.AllocateId(); + state.builder.AddFunction({OpFNegate, state.float_type, neg_value, f32}); f32 = neg_value; } const auto truncated = EmitTruncF32Value(state, f32); - const auto below_zero = state->builder.AllocateId(); - const auto above_max = state->builder.AllocateId(); - const auto safe_low = state->builder.AllocateId(); - const auto safe_value = state->builder.AllocateId(); - const auto converted = state->builder.AllocateId(); - state->builder.AddFunction( - {OpFOrdLessThanEqual, state->bool_type, below_zero, f32, ConstantF32(state, 0)}); - state->builder.AddFunction({OpFOrdGreaterThanEqual, state->bool_type, above_max, f32, - ConstantF32(state, 0x477fff00u)}); + const auto below_zero = state.builder.AllocateId(); + const auto above_max = state.builder.AllocateId(); + const auto safe_low = state.builder.AllocateId(); + const auto safe_value = state.builder.AllocateId(); + const auto converted = state.builder.AllocateId(); + state.builder.AddFunction( + {OpFOrdLessThanEqual, state.bool_type, below_zero, f32, ConstantF32(state, 0)}); + state.builder.AddFunction( + {OpFOrdGreaterThanEqual, state.bool_type, above_max, f32, ConstantF32(state, 0x477fff00u)}); const auto zero_or_nan = EmitLogicalOrBool(state, EmitClassifyF32(state, f32).nan, below_zero); - state->builder.AddFunction( - {OpSelect, state->float_type, safe_low, zero_or_nan, ConstantF32(state, 0), truncated}); - state->builder.AddFunction({OpSelect, state->float_type, safe_value, above_max, - ConstantF32(state, 0x477fff00u), safe_low}); - state->builder.AddFunction({OpConvertFToU, state->uint_type, converted, safe_value}); + state.builder.AddFunction( + {OpSelect, state.float_type, safe_low, zero_or_nan, ConstantF32(state, 0), truncated}); + state.builder.AddFunction({OpSelect, state.float_type, safe_value, above_max, + ConstantF32(state, 0x477fff00u), safe_low}); + state.builder.AddFunction({OpConvertFToU, state.uint_type, converted, safe_value}); EmitStoreU32(state, inst.dst, EmitAndConstant(state, converted, 0xffffu)); } -void EmitConvertU16ToF16(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertU16ToF16(EmitterState& state, const IR::Instruction& inst) { const auto src_bits = EmitU16LaneBits(state, inst.src[0], false, false); - const auto f32 = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertUToF, state->float_type, f32, src_bits}); + const auto f32 = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertUToF, state.float_type, f32, src_bits}); EmitStoreU32(state, inst.dst, EmitPackLowF32ToF16Bits(state, f32)); } -void EmitConvertI16ToF16(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertI16ToF16(EmitterState& state, const IR::Instruction& inst) { const auto src_bits = EmitU16LaneBits(state, inst.src[0], false, true); - const auto i32 = state->builder.AllocateId(); - const auto f32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, i32, src_bits}); - state->builder.AddFunction({OpConvertSToF, state->float_type, f32, i32}); + const auto i32 = state.builder.AllocateId(); + const auto f32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, i32, src_bits}); + state.builder.AddFunction({OpConvertSToF, state.float_type, f32, i32}); EmitStoreU32(state, inst.dst, EmitPackLowF32ToF16Bits(state, f32)); } -void EmitConvertF16ToI16(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertF16ToI16(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto unpacked = state->builder.AllocateId(); - auto f32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->vec2_float_type, unpacked, state->glsl_std450, GlslUnpackHalf2x16, src}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, f32, unpacked, 0}); + const auto unpacked = state.builder.AllocateId(); + auto f32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, src}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, f32, unpacked, 0}); if (inst.src[0].absolute) { - const auto abs_value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, abs_value, state->glsl_std450, GlslFAbs, f32}); + const auto abs_value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, abs_value, state.glsl_std450, GlslFAbs, f32}); f32 = abs_value; } if (inst.src[0].negate) { - const auto neg_value = state->builder.AllocateId(); - state->builder.AddFunction({OpFNegate, state->float_type, neg_value, f32}); + const auto neg_value = state.builder.AllocateId(); + state.builder.AddFunction({OpFNegate, state.float_type, neg_value, f32}); f32 = neg_value; } const auto truncated = EmitTruncF32Value(state, f32); - const auto below_min = state->builder.AllocateId(); - const auto above_max = state->builder.AllocateId(); - const auto safe_low = state->builder.AllocateId(); - const auto safe_value = state->builder.AllocateId(); - const auto nan_safe = state->builder.AllocateId(); - const auto i32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpFOrdLessThanEqual, state->bool_type, below_min, f32, ConstantF32(state, 0xc7000000u)}); - state->builder.AddFunction({OpFOrdGreaterThanEqual, state->bool_type, above_max, f32, - ConstantF32(state, 0x46fffe00u)}); - state->builder.AddFunction({OpSelect, state->float_type, safe_low, below_min, - ConstantF32(state, 0xc7000000u), truncated}); - state->builder.AddFunction({OpSelect, state->float_type, safe_value, above_max, - ConstantF32(state, 0x46fffe00u), safe_low}); - state->builder.AddFunction({OpSelect, state->float_type, nan_safe, - EmitClassifyF32(state, f32).nan, ConstantF32(state, 0), - safe_value}); - state->builder.AddFunction({OpConvertFToS, state->int_type, i32, nan_safe}); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, i32}); + const auto below_min = state.builder.AllocateId(); + const auto above_max = state.builder.AllocateId(); + const auto safe_low = state.builder.AllocateId(); + const auto safe_value = state.builder.AllocateId(); + const auto nan_safe = state.builder.AllocateId(); + const auto i32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpFOrdLessThanEqual, state.bool_type, below_min, f32, ConstantF32(state, 0xc7000000u)}); + state.builder.AddFunction( + {OpFOrdGreaterThanEqual, state.bool_type, above_max, f32, ConstantF32(state, 0x46fffe00u)}); + state.builder.AddFunction({OpSelect, state.float_type, safe_low, below_min, + ConstantF32(state, 0xc7000000u), truncated}); + state.builder.AddFunction({OpSelect, state.float_type, safe_value, above_max, + ConstantF32(state, 0x46fffe00u), safe_low}); + state.builder.AddFunction({OpSelect, state.float_type, nan_safe, + EmitClassifyF32(state, f32).nan, ConstantF32(state, 0), safe_value}); + state.builder.AddFunction({OpConvertFToS, state.int_type, i32, nan_safe}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, i32}); EmitStoreU32(state, inst.dst, EmitAndConstant(state, u32, 0xffffu)); } -void EmitConvertRoundPlusInfF32ToI32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertRoundPlusInfF32ToI32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitFloatLoad(state, inst.src[0]); - const auto biased = state->builder.AllocateId(); - const auto rounded = state->builder.AllocateId(); - const auto i32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpFAdd, state->float_type, biased, src, ConstantF32(state, 0x3f000000u)}); - state->builder.AddFunction( - {OpExtInst, state->float_type, rounded, state->glsl_std450, GlslFloor, biased}); - state->builder.AddFunction({OpConvertFToS, state->int_type, i32, rounded}); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, i32}); + const auto biased = state.builder.AllocateId(); + const auto rounded = state.builder.AllocateId(); + const auto i32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpFAdd, state.float_type, biased, src, ConstantF32(state, 0x3f000000u)}); + state.builder.AddFunction( + {OpExtInst, state.float_type, rounded, state.glsl_std450, GlslFloor, biased}); + state.builder.AddFunction({OpConvertFToS, state.int_type, i32, rounded}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, i32}); EmitStoreU32(state, inst.dst, u32); } -void EmitConvertFloorF32ToI32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertFloorF32ToI32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitFloatLoad(state, inst.src[0]); - const auto floor = state->builder.AllocateId(); - const auto i32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, floor, state->glsl_std450, GlslFloor, src}); - state->builder.AddFunction({OpConvertFToS, state->int_type, i32, floor}); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, i32}); + const auto floor = state.builder.AllocateId(); + const auto i32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, floor, state.glsl_std450, GlslFloor, src}); + state.builder.AddFunction({OpConvertFToS, state.int_type, i32, floor}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, i32}); EmitStoreU32(state, inst.dst, u32); } -void EmitConvertI4ToOffsetF32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertI4ToOffsetF32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); - const auto src_i32 = state->builder.AllocateId(); - const auto nibble = state->builder.AllocateId(); - const auto f32 = state->builder.AllocateId(); - const auto scaled = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, src_i32, src}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, nibble, src_i32, - ConstantU32(state, 0), ConstantU32(state, 4)}); - state->builder.AddFunction({OpConvertSToF, state->float_type, f32, nibble}); - state->builder.AddFunction( - {OpFDiv, state->float_type, scaled, f32, ConstantF32(state, 0x41800000u)}); + const auto src_i32 = state.builder.AllocateId(); + const auto nibble = state.builder.AllocateId(); + const auto f32 = state.builder.AllocateId(); + const auto scaled = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, src_i32, src}); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, nibble, src_i32, + ConstantU32(state, 0), ConstantU32(state, 4)}); + state.builder.AddFunction({OpConvertSToF, state.float_type, f32, nibble}); + state.builder.AddFunction( + {OpFDiv, state.float_type, scaled, f32, ConstantF32(state, 0x41800000u)}); const auto result = ApplyResultModifiersF32(state, scaled, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -void EmitConvertByteU32ToF32(EmitterState* state, const IR::Instruction& inst) { +void EmitConvertByteU32ToF32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); const auto index = inst.src[1].kind == IR::OperandKind::ImmediateU32 ? inst.src[1].imm : 0u; const auto byte = EmitBitFieldExtractConstant(state, src, (index & 3u) * 8u, 8u); - const auto f32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertUToF, state->float_type, f32, byte}); + const auto f32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertUToF, state.float_type, f32, byte}); const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -uint32_t EmitFlushF32DenormToSignedZero(EmitterState* state, uint32_t value) { - const auto bits = state->builder.AllocateId(); - const auto abs_bits = state->builder.AllocateId(); - const auto sign_bits = state->builder.AllocateId(); - const auto non_zero = state->builder.AllocateId(); - const auto subnormal = state->builder.AllocateId(); - const auto flush = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, value}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, abs_bits, bits, ConstantU32(state, 0x7fffffffu)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, sign_bits, bits, ConstantU32(state, 0x80000000u)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, non_zero, abs_bits, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpULessThan, state->bool_type, subnormal, abs_bits, ConstantU32(state, 0x00800000u)}); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, flush, non_zero, subnormal}); - state->builder.AddFunction({OpSelect, state->uint_type, selected, flush, sign_bits, bits}); - state->builder.AddFunction({OpBitcast, state->float_type, ret, selected}); +uint32_t EmitFlushF32DenormToSignedZero(EmitterState& state, uint32_t value) { + const auto bits = state.builder.AllocateId(); + const auto abs_bits = state.builder.AllocateId(); + const auto sign_bits = state.builder.AllocateId(); + const auto non_zero = state.builder.AllocateId(); + const auto subnormal = state.builder.AllocateId(); + const auto flush = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, value}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, abs_bits, bits, ConstantU32(state, 0x7fffffffu)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, sign_bits, bits, ConstantU32(state, 0x80000000u)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, non_zero, abs_bits, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpULessThan, state.bool_type, subnormal, abs_bits, ConstantU32(state, 0x00800000u)}); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, flush, non_zero, subnormal}); + state.builder.AddFunction({OpSelect, state.uint_type, selected, flush, sign_bits, bits}); + state.builder.AddFunction({OpBitcast, state.float_type, ret, selected}); return ret; } -void EmitRcpF32(EmitterState* state, const IR::Instruction& inst) { +void EmitRcpF32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitFlushF32DenormToSignedZero(state, EmitFloatLoad(state, inst.src[0])); - const auto f32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpFDiv, state->float_type, f32, ConstantF32(state, 0x3f800000u), src}); + const auto f32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpFDiv, state.float_type, f32, ConstantF32(state, 0x3f800000u), src}); const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -uint32_t EmitTrigCycleF32(EmitterState* state, uint32_t src, bool preserve_signed_zero) { - const auto fract = state->builder.AllocateId(); - const auto bits = state->builder.AllocateId(); - const auto abs_bits = state->builder.AllocateId(); - const auto large = state->builder.AllocateId(); - const auto finite = state->builder.AllocateId(); - const auto large_finite = state->builder.AllocateId(); - const auto reduced = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, fract, state->glsl_std450, GlslFract, src}); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, src}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, abs_bits, bits, ConstantU32(state, 0x7fffffffu)}); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, large, abs_bits, ConstantU32(state, 0x4b000000u)}); - state->builder.AddFunction( - {OpULessThan, state->bool_type, finite, abs_bits, ConstantU32(state, 0x7f800000u)}); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, large_finite, large, finite}); - state->builder.AddFunction( - {OpSelect, state->float_type, reduced, large_finite, ConstantF32(state, 0), fract}); +uint32_t EmitTrigCycleF32(EmitterState& state, uint32_t src, bool preserve_signed_zero) { + const auto fract = state.builder.AllocateId(); + const auto bits = state.builder.AllocateId(); + const auto abs_bits = state.builder.AllocateId(); + const auto large = state.builder.AllocateId(); + const auto finite = state.builder.AllocateId(); + const auto large_finite = state.builder.AllocateId(); + const auto reduced = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, fract, state.glsl_std450, GlslFract, src}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, src}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, abs_bits, bits, ConstantU32(state, 0x7fffffffu)}); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, large, abs_bits, ConstantU32(state, 0x4b000000u)}); + state.builder.AddFunction( + {OpULessThan, state.bool_type, finite, abs_bits, ConstantU32(state, 0x7f800000u)}); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, large_finite, large, finite}); + state.builder.AddFunction( + {OpSelect, state.float_type, reduced, large_finite, ConstantF32(state, 0), fract}); if (!preserve_signed_zero) { return reduced; } - const auto zero = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpIEqual, state->bool_type, zero, abs_bits, ConstantU32(state, 0)}); - state->builder.AddFunction({OpSelect, state->float_type, ret, zero, src, reduced}); + const auto zero = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpIEqual, state.bool_type, zero, abs_bits, ConstantU32(state, 0)}); + state.builder.AddFunction({OpSelect, state.float_type, ret, zero, src, reduced}); return ret; } -void EmitFloatExtInst(EmitterState* state, const IR::Instruction& inst, uint32_t ext_inst, +void EmitFloatExtInst(EmitterState& state, const IR::Instruction& inst, uint32_t ext_inst, bool scale_by_two_pi, bool flush_denorm) { auto src = EmitFloatLoad(state, inst.src[0]); if (flush_denorm) { @@ -1895,72 +1877,71 @@ void EmitFloatExtInst(EmitterState* state, const IR::Instruction& inst, uint32_t } if (scale_by_two_pi) { src = EmitTrigCycleF32(state, src, ext_inst == GlslSin); - const auto scaled = state->builder.AllocateId(); - state->builder.AddFunction( - {OpFMul, state->float_type, scaled, src, ConstantF32(state, 0x40c90fdbu)}); + const auto scaled = state.builder.AllocateId(); + state.builder.AddFunction( + {OpFMul, state.float_type, scaled, src, ConstantF32(state, 0x40c90fdbu)}); src = scaled; } - const auto f32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, f32, state->glsl_std450, ext_inst, src}); + const auto f32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpExtInst, state.float_type, f32, state.glsl_std450, ext_inst, src}); const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -void EmitMadF32(EmitterState* state, const IR::Instruction& inst) { +void EmitMadF32(EmitterState& state, const IR::Instruction& inst) { const auto lhs = EmitMixF32Load(state, inst.src[0]); const auto rhs = EmitMixF32Load(state, inst.src[1]); const auto add = EmitMixF32Load(state, inst.src[2]); - const auto f32 = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, f32, state->glsl_std450, GlslFma, lhs, rhs, add}); + const auto f32 = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, f32, state.glsl_std450, GlslFma, lhs, rhs, add}); const auto result = ApplyResultModifiersF32(state, f32, inst.dst); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, result}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, result}); EmitStoreU32(state, inst.dst, u32); } -uint32_t EmitFNegateValue(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpFNegate, state->float_type, ret, value}); +uint32_t EmitFNegateValue(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpFNegate, state.float_type, ret, value}); return ret; } -uint32_t EmitFAbsValue(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, ret, state->glsl_std450, GlslFAbs, value}); +uint32_t EmitFAbsValue(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, ret, state.glsl_std450, GlslFAbs, value}); return ret; } -uint32_t EmitFCompareValue(EmitterState* state, uint32_t opcode, uint32_t lhs, uint32_t rhs) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->bool_type, ret, lhs, rhs}); +uint32_t EmitFCompareValue(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, ret, lhs, rhs}); return ret; } -uint32_t EmitLogicalAndValue(EmitterState* state, uint32_t lhs, uint32_t rhs) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, ret, lhs, rhs}); +uint32_t EmitLogicalAndValue(EmitterState& state, uint32_t lhs, uint32_t rhs) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, ret, lhs, rhs}); return ret; } -uint32_t EmitFSelectValue(EmitterState* state, uint32_t cond, uint32_t true_value, +uint32_t EmitFSelectValue(EmitterState& state, uint32_t cond, uint32_t true_value, uint32_t false_value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->float_type, ret, cond, true_value, false_value}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.float_type, ret, cond, true_value, false_value}); return ret; } -uint32_t EmitFMulConstant(EmitterState* state, uint32_t value, uint32_t bits) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpFMul, state->float_type, ret, value, ConstantF32(state, bits)}); +uint32_t EmitFMulConstant(EmitterState& state, uint32_t value, uint32_t bits) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpFMul, state.float_type, ret, value, ConstantF32(state, bits)}); return ret; } -CubeF32Values EmitCubeF32Values(EmitterState* state, const IR::Instruction& inst) { +CubeF32Values EmitCubeF32Values(EmitterState& state, const IR::Instruction& inst) { CubeF32Values cube; cube.x = EmitFloatLoad(state, inst.src[0]); cube.y = EmitFloatLoad(state, inst.src[1]); @@ -1981,7 +1962,7 @@ CubeF32Values EmitCubeF32Values(EmitterState* state, const IR::Instruction& inst return cube; } -uint32_t EmitCubeIdF32(EmitterState* state, const CubeF32Values& cube) { +uint32_t EmitCubeIdF32(EmitterState& state, const CubeF32Values& cube) { const auto x_face = EmitFSelectValue(state, cube.x_neg, ConstantF32(state, 0x3f800000u), ConstantF32(state, 0)); const auto y_face = EmitFSelectValue(state, cube.y_neg, ConstantF32(state, 0x40400000u), @@ -1992,20 +1973,20 @@ uint32_t EmitCubeIdF32(EmitterState* state, const CubeF32Values& cube) { return EmitFSelectValue(state, cube.z_face, z_face, xy); } -uint32_t EmitCubeScF32(EmitterState* state, const CubeF32Values& cube) { +uint32_t EmitCubeScF32(EmitterState& state, const CubeF32Values& cube) { const auto x_sc = EmitFSelectValue(state, cube.x_neg, cube.z, cube.nz); const auto z_sc = EmitFSelectValue(state, cube.z_neg, cube.nx, cube.x); const auto xy = EmitFSelectValue(state, cube.y_face, cube.x, x_sc); return EmitFSelectValue(state, cube.z_face, z_sc, xy); } -uint32_t EmitCubeTcF32(EmitterState* state, const CubeF32Values& cube) { +uint32_t EmitCubeTcF32(EmitterState& state, const CubeF32Values& cube) { const auto y_tc = EmitFSelectValue(state, cube.y_neg, cube.nz, cube.z); const auto xy = EmitFSelectValue(state, cube.y_face, y_tc, cube.ny); return EmitFSelectValue(state, cube.z_face, cube.ny, xy); } -uint32_t EmitCubeMaF32(EmitterState* state, const CubeF32Values& cube) { +uint32_t EmitCubeMaF32(EmitterState& state, const CubeF32Values& cube) { const auto x_ma = EmitFMulConstant(state, cube.x, 0x40000000u); const auto y_ma = EmitFMulConstant(state, cube.y, 0x40000000u); const auto z_ma = EmitFMulConstant(state, cube.z, 0x40000000u); @@ -2013,7 +1994,7 @@ uint32_t EmitCubeMaF32(EmitterState* state, const CubeF32Values& cube) { return EmitFSelectValue(state, cube.z_face, z_ma, xy); } -void EmitCubeF32(EmitterState* state, const IR::Instruction& inst) { +void EmitCubeF32(EmitterState& state, const IR::Instruction& inst) { const auto cube = EmitCubeF32Values(state, inst); uint32_t ret = 0; switch (inst.op) { @@ -2023,71 +2004,71 @@ void EmitCubeF32(EmitterState* state, const IR::Instruction& inst) { case IR::Opcode::CubeMaF32: ret = EmitCubeMaF32(state, cube); break; default: ret = ConstantF32(state, 0); break; } - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, ret}); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, ret}); EmitStoreU32(state, inst.dst, bits); } -void EmitDot2AccF32F16(EmitterState* state, const IR::Instruction& inst) { +void EmitDot2AccF32F16(EmitterState& state, const IR::Instruction& inst) { const auto src0 = EmitValueLoad(state, inst.src[0]); const auto src1 = EmitValueLoad(state, inst.src[1]); - const auto vec0 = state->builder.AllocateId(); - const auto vec1 = state->builder.AllocateId(); - const auto a_lo = state->builder.AllocateId(); - const auto a_hi = state->builder.AllocateId(); - const auto b_lo = state->builder.AllocateId(); - const auto b_hi = state->builder.AllocateId(); + const auto vec0 = state.builder.AllocateId(); + const auto vec1 = state.builder.AllocateId(); + const auto a_lo = state.builder.AllocateId(); + const auto a_hi = state.builder.AllocateId(); + const auto b_lo = state.builder.AllocateId(); + const auto b_hi = state.builder.AllocateId(); const auto acc = EmitFloatLoad(state, inst.src[2]); - const auto lo = state->builder.AllocateId(); - const auto dot = state->builder.AllocateId(); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->vec2_float_type, vec0, state->glsl_std450, GlslUnpackHalf2x16, src0}); - state->builder.AddFunction( - {OpExtInst, state->vec2_float_type, vec1, state->glsl_std450, GlslUnpackHalf2x16, src1}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, a_lo, vec0, 0}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, a_hi, vec0, 1}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, b_lo, vec1, 0}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, b_hi, vec1, 1}); - state->builder.AddFunction( - {OpExtInst, state->float_type, lo, state->glsl_std450, GlslFma, a_lo, b_lo, acc}); - state->builder.AddFunction( - {OpExtInst, state->float_type, dot, state->glsl_std450, GlslFma, a_hi, b_hi, lo}); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, dot}); + const auto lo = state.builder.AllocateId(); + const auto dot = state.builder.AllocateId(); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.vec2_float_type, vec0, state.glsl_std450, GlslUnpackHalf2x16, src0}); + state.builder.AddFunction( + {OpExtInst, state.vec2_float_type, vec1, state.glsl_std450, GlslUnpackHalf2x16, src1}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, a_lo, vec0, 0}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, a_hi, vec0, 1}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, b_lo, vec1, 0}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, b_hi, vec1, 1}); + state.builder.AddFunction( + {OpExtInst, state.float_type, lo, state.glsl_std450, GlslFma, a_lo, b_lo, acc}); + state.builder.AddFunction( + {OpExtInst, state.float_type, dot, state.glsl_std450, GlslFma, a_hi, b_hi, lo}); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, dot}); EmitStoreU32(state, inst.dst, u32); } -uint32_t EmitPackedF16Lane(EmitterState* state, const IR::Operand& operand, bool high_lane) { +uint32_t EmitPackedF16Lane(EmitterState& state, const IR::Operand& operand, bool high_lane) { const auto raw = EmitValueLoad(state, operand); - const auto unpacked = state->builder.AllocateId(); - auto value = state->builder.AllocateId(); + const auto unpacked = state.builder.AllocateId(); + auto value = state.builder.AllocateId(); const auto lane = high_lane ? (operand.op_sel_hi ? 1u : 0u) : (operand.op_sel ? 1u : 0u); - state->builder.AddFunction( - {OpExtInst, state->vec2_float_type, unpacked, state->glsl_std450, GlslUnpackHalf2x16, raw}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, value, unpacked, lane}); + state.builder.AddFunction( + {OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, raw}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, value, unpacked, lane}); if (operand.absolute) { - const auto abs_value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, abs_value, state->glsl_std450, GlslFAbs, value}); + const auto abs_value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, abs_value, state.glsl_std450, GlslFAbs, value}); value = abs_value; } if (high_lane ? operand.negate_hi : operand.negate) { - const auto neg_value = state->builder.AllocateId(); - state->builder.AddFunction({OpFNegate, state->float_type, neg_value, value}); + const auto neg_value = state.builder.AllocateId(); + state.builder.AddFunction({OpFNegate, state.float_type, neg_value, value}); value = neg_value; } return value; } -void EmitCompareF16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitCompareF16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitPackedF16Lane(state, inst.src[0], false); const auto rhs = EmitPackedF16Lane(state, inst.src[1], false); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->bool_type, cond, lhs, rhs}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.bool_type, cond, lhs, rhs}); EmitCompareResult(state, inst.dst, cond); } -uint32_t EmitPackedF16LaneBits(EmitterState* state, const IR::Operand& operand, bool high_lane) { +uint32_t EmitPackedF16LaneBits(EmitterState& state, const IR::Operand& operand, bool high_lane) { const auto raw = EmitValueLoad(state, operand); const auto lane = high_lane ? (operand.op_sel_hi ? 1u : 0u) : (operand.op_sel ? 1u : 0u); auto bits = lane != 0u ? EmitShiftRightConstant(state, raw, 16) : raw; @@ -2101,33 +2082,33 @@ uint32_t EmitPackedF16LaneBits(EmitterState* state, const IR::Operand& operand, return bits; } -uint32_t EmitF16BitsToF32(EmitterState* state, uint32_t bits) { - const auto unpacked = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpExtInst, state->vec2_float_type, unpacked, state->glsl_std450, - GlslUnpackHalf2x16, bits}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, ret, unpacked, 0}); +uint32_t EmitF16BitsToF32(EmitterState& state, uint32_t bits) { + const auto unpacked = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, bits}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, ret, unpacked, 0}); return ret; } -uint32_t EmitPackLowF32ToF16Bits(EmitterState* state, uint32_t value) { - const auto pair = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpCompositeConstruct, state->vec2_float_type, pair, value, ConstantF32(state, 0)}); - state->builder.AddFunction( - {OpExtInst, state->uint_type, ret, state->glsl_std450, GlslPackHalf2x16, pair}); +uint32_t EmitPackLowF32ToF16Bits(EmitterState& state, uint32_t value) { + const auto pair = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpCompositeConstruct, state.vec2_float_type, pair, value, ConstantF32(state, 0)}); + state.builder.AddFunction( + {OpExtInst, state.uint_type, ret, state.glsl_std450, GlslPackHalf2x16, pair}); return EmitAndConstant(state, ret, 0xffffu); } -void EmitPackB32F16(EmitterState* state, const IR::Instruction& inst) { +void EmitPackB32F16(EmitterState& state, const IR::Instruction& inst) { const auto lo = EmitPackedF16LaneBits(state, inst.src[0], false); const auto hi = EmitShiftLeftConstant(state, EmitPackedF16LaneBits(state, inst.src[1], false), 16); EmitStoreU32(state, inst.dst, EmitOrU32(state, lo, hi)); } -F16Class EmitClassifyF16Bits(EmitterState* state, uint32_t value) { +F16Class EmitClassifyF16Bits(EmitterState& state, uint32_t value) { F16Class cls; cls.bits = EmitAndConstant(state, value, 0xffffu); const auto abs_bits = EmitAndConstant(state, cls.bits, 0x7fffu); @@ -2144,7 +2125,7 @@ F16Class EmitClassifyF16Bits(EmitterState* state, uint32_t value) { return cls; } -uint32_t EmitNegativeNumericF16Bool(EmitterState* state, const F16Class& cls) { +uint32_t EmitNegativeNumericF16Bool(EmitterState& state, const F16Class& cls) { const auto sign = EmitCompareU32Constant(state, OpINotEqual, EmitAndConstant(state, cls.bits, 0x8000u), 0); const auto nonzero = EmitLogicalNotBool(state, cls.zero); @@ -2152,32 +2133,32 @@ uint32_t EmitNegativeNumericF16Bool(EmitterState* state, const F16Class& cls) { EmitLogicalNotBool(state, cls.nan)); } -uint32_t EmitRcpF16Bits(EmitterState* state, uint32_t bits) { +uint32_t EmitRcpF16Bits(EmitterState& state, uint32_t bits) { const auto f32 = EmitF16BitsToF32(state, bits); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpFDiv, state->float_type, ret, ConstantF32(state, 0x3f800000u), f32}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpFDiv, state.float_type, ret, ConstantF32(state, 0x3f800000u), f32}); return EmitPackLowF32ToF16Bits(state, ret); } -uint32_t EmitSqrtF16Bits(EmitterState* state, uint32_t bits) { +uint32_t EmitSqrtF16Bits(EmitterState& state, uint32_t bits) { const auto cls = EmitClassifyF16Bits(state, bits); const auto f32 = EmitF16BitsToF32(state, cls.bits); - const auto sqrt = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, sqrt, state->glsl_std450, GlslSqrt, f32}); + const auto sqrt = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, sqrt, state.glsl_std450, GlslSqrt, f32}); const auto packed = EmitPackLowF32ToF16Bits(state, sqrt); const auto numeric = EmitSelectValueU32(state, EmitNegativeNumericF16Bool(state, cls), ConstantU32(state, 0xfe00u), packed); return EmitSelectValueU32(state, cls.zero, cls.bits, numeric); } -uint32_t EmitRsqF16Bits(EmitterState* state, uint32_t bits) { +uint32_t EmitRsqF16Bits(EmitterState& state, uint32_t bits) { const auto cls = EmitClassifyF16Bits(state, bits); const auto f32 = EmitF16BitsToF32(state, cls.bits); - const auto rsq = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, rsq, state->glsl_std450, GlslInverseSqrt, f32}); + const auto rsq = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, rsq, state.glsl_std450, GlslInverseSqrt, f32}); const auto packed = EmitPackLowF32ToF16Bits(state, rsq); const auto sign = EmitCompareU32Constant(state, OpINotEqual, EmitAndConstant(state, cls.bits, 0x8000u), 0); @@ -2188,34 +2169,34 @@ uint32_t EmitRsqF16Bits(EmitterState* state, uint32_t bits) { return EmitSelectValueU32(state, cls.zero, zero_result, numeric); } -uint32_t EmitLog2F16Bits(EmitterState* state, uint32_t bits) { +uint32_t EmitLog2F16Bits(EmitterState& state, uint32_t bits) { const auto cls = EmitClassifyF16Bits(state, bits); const auto f32 = EmitF16BitsToF32(state, cls.bits); - const auto log2 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, log2, state->glsl_std450, GlslLog2, f32}); + const auto log2 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, log2, state.glsl_std450, GlslLog2, f32}); const auto packed = EmitPackLowF32ToF16Bits(state, log2); return EmitSelectValueU32(state, EmitNegativeNumericF16Bool(state, cls), ConstantU32(state, 0xfe00u), packed); } -uint32_t EmitExp2F16Bits(EmitterState* state, uint32_t bits) { +uint32_t EmitExp2F16Bits(EmitterState& state, uint32_t bits) { const auto f32 = EmitF16BitsToF32(state, bits); - const auto exp2 = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, exp2, state->glsl_std450, GlslExp2, f32}); + const auto exp2 = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, exp2, state.glsl_std450, GlslExp2, f32}); return EmitPackLowF32ToF16Bits(state, exp2); } -uint32_t EmitF16MathExtInstBits(EmitterState* state, uint32_t bits, uint32_t ext_inst) { +uint32_t EmitF16MathExtInstBits(EmitterState& state, uint32_t bits, uint32_t ext_inst) { const auto f32 = EmitF16BitsToF32(state, bits); - const auto result = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, result, state->glsl_std450, ext_inst, f32}); + const auto result = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, result, state.glsl_std450, ext_inst, f32}); return EmitPackLowF32ToF16Bits(state, result); } -void EmitSpecialF16(EmitterState* state, const IR::Instruction& inst) { +void EmitSpecialF16(EmitterState& state, const IR::Instruction& inst) { const auto bits = EmitPackedF16LaneBits(state, inst.src[0], false); uint32_t ret = ConstantU32(state, 0); switch (inst.op) { @@ -2235,30 +2216,30 @@ void EmitSpecialF16(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, inst.dst, ret); } -void EmitBinaryF16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitBinaryF16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { const auto lhs = EmitPackedF16Lane(state, inst.src[0], false); const auto rhs = EmitPackedF16Lane(state, inst.src[1], false); - auto value = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->float_type, value, lhs, rhs}); + auto value = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.float_type, value, lhs, rhs}); value = ApplyResultModifiersF32(state, value, inst.dst); EmitStoreU32(state, inst.dst, EmitPackLowF32ToF16Bits(state, value)); } -void EmitFmaF16(EmitterState* state, const IR::Instruction& inst) { +void EmitFmaF16(EmitterState& state, const IR::Instruction& inst) { const auto fma = ApplyResultModifiersF32(state, EmitPackedF16FmaLane(state, inst, false), inst.dst); EmitStoreU32(state, inst.dst, EmitPackLowF32ToF16Bits(state, fma)); } -uint32_t EmitMinMaxF16Bits(EmitterState* state, uint32_t lhs, uint32_t rhs, bool max_value) { +uint32_t EmitMinMaxF16Bits(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value) { const auto lhs_class = EmitClassifyF16Bits(state, lhs); const auto rhs_class = EmitClassifyF16Bits(state, rhs); const auto lhs_f32 = EmitF16BitsToF32(state, lhs_class.bits); const auto rhs_f32 = EmitF16BitsToF32(state, rhs_class.bits); - const auto numeric_cond = state->builder.AllocateId(); - state->builder.AddFunction({max_value ? OpFOrdGreaterThanEqual : OpFOrdLessThan, - state->bool_type, numeric_cond, lhs_f32, rhs_f32}); + const auto numeric_cond = state.builder.AllocateId(); + state.builder.AddFunction({max_value ? OpFOrdGreaterThanEqual : OpFOrdLessThan, state.bool_type, + numeric_cond, lhs_f32, rhs_f32}); const auto ordered_bits = EmitSelectValueU32(state, numeric_cond, lhs_class.bits, rhs_class.bits); @@ -2278,20 +2259,20 @@ uint32_t EmitMinMaxF16Bits(EmitterState* state, uint32_t lhs, uint32_t rhs, bool return EmitAndConstant(state, result_bits, 0xffffu); } -void EmitMinMaxF16(EmitterState* state, const IR::Instruction& inst, bool max_value) { +void EmitMinMaxF16(EmitterState& state, const IR::Instruction& inst, bool max_value) { const auto bits = EmitMinMaxF16Bits(state, EmitPackedF16LaneBits(state, inst.src[0], false), EmitPackedF16LaneBits(state, inst.src[1], false), max_value); EmitStoreU32(state, inst.dst, bits); } -uint32_t EmitMinMax3F16Bits(EmitterState* state, uint32_t src0, uint32_t src1, uint32_t src2, +uint32_t EmitMinMax3F16Bits(EmitterState& state, uint32_t src0, uint32_t src1, uint32_t src2, bool max_value) { return EmitMinMaxF16Bits(state, EmitMinMaxF16Bits(state, src0, src1, max_value), src2, max_value); } -void EmitMinMax3F16(EmitterState* state, const IR::Instruction& inst, bool max_value) { +void EmitMinMax3F16(EmitterState& state, const IR::Instruction& inst, bool max_value) { const auto bits = EmitMinMax3F16Bits(state, EmitPackedF16LaneBits(state, inst.src[0], false), EmitPackedF16LaneBits(state, inst.src[1], false), @@ -2299,21 +2280,21 @@ void EmitMinMax3F16(EmitterState* state, const IR::Instruction& inst, bool max_v EmitStoreU32(state, inst.dst, bits); } -uint32_t EmitF16BitsEqualBool(EmitterState* state, uint32_t lhs, uint32_t rhs) { +uint32_t EmitF16BitsEqualBool(EmitterState& state, uint32_t lhs, uint32_t rhs) { const auto lhs_f32 = EmitF16BitsToF32(state, lhs); const auto rhs_f32 = EmitF16BitsToF32(state, rhs); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpFOrdEqual, state->bool_type, ret, lhs_f32, rhs_f32}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpFOrdEqual, state.bool_type, ret, lhs_f32, rhs_f32}); return ret; } -uint32_t EmitAnyNanF16Bool(EmitterState* state, uint32_t src0, uint32_t src1, uint32_t src2) { +uint32_t EmitAnyNanF16Bool(EmitterState& state, uint32_t src0, uint32_t src1, uint32_t src2) { const auto nan01 = EmitLogicalOrBool(state, EmitClassifyF16Bits(state, src0).nan, EmitClassifyF16Bits(state, src1).nan); return EmitLogicalOrBool(state, nan01, EmitClassifyF16Bits(state, src2).nan); } -void EmitMed3F16(EmitterState* state, const IR::Instruction& inst) { +void EmitMed3F16(EmitterState& state, const IR::Instruction& inst) { const auto src0 = EmitPackedF16LaneBits(state, inst.src[0], false); const auto src1 = EmitPackedF16LaneBits(state, inst.src[1], false); const auto src2 = EmitPackedF16LaneBits(state, inst.src[2], false); @@ -2332,7 +2313,7 @@ void EmitMed3F16(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, inst.dst, bits); } -uint32_t EmitPackedMinMaxF16(EmitterState* state, const IR::Instruction& inst, bool max_value) { +uint32_t EmitPackedMinMaxF16(EmitterState& state, const IR::Instruction& inst, bool max_value) { const auto lo = EmitMinMaxF16Bits(state, EmitPackedF16LaneBits(state, inst.src[0], false), EmitPackedF16LaneBits(state, inst.src[1], false), max_value); const auto hi = EmitMinMaxF16Bits(state, EmitPackedF16LaneBits(state, inst.src[0], true), @@ -2340,26 +2321,26 @@ uint32_t EmitPackedMinMaxF16(EmitterState* state, const IR::Instruction& inst, b return EmitOrU32(state, lo, EmitShiftLeftConstant(state, hi, 16)); } -uint32_t EmitPackedF16BinaryLane(EmitterState* state, const IR::Instruction& inst, bool high_lane, +uint32_t EmitPackedF16BinaryLane(EmitterState& state, const IR::Instruction& inst, bool high_lane, uint32_t opcode) { const auto lhs = EmitPackedF16Lane(state, inst.src[0], high_lane); const auto rhs = EmitPackedF16Lane(state, inst.src[1], high_lane); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->float_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.float_type, ret, lhs, rhs}); return ret; } -uint32_t EmitPackedF16FmaLane(EmitterState* state, const IR::Instruction& inst, bool high_lane) { +uint32_t EmitPackedF16FmaLane(EmitterState& state, const IR::Instruction& inst, bool high_lane) { const auto lhs = EmitPackedF16Lane(state, inst.src[0], high_lane); const auto rhs = EmitPackedF16Lane(state, inst.src[1], high_lane); const auto add = EmitPackedF16Lane(state, inst.src[2], high_lane); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, ret, state->glsl_std450, GlslFma, lhs, rhs, add}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, ret, state.glsl_std450, GlslFma, lhs, rhs, add}); return ret; } -uint32_t EmitPackedF16BitsWithResultModifiers(EmitterState* state, uint32_t bits, +uint32_t EmitPackedF16BitsWithResultModifiers(EmitterState& state, uint32_t bits, const IR::Operand& dst) { if (!dst.clamp && dst.omod == 0u) { return bits; @@ -2368,15 +2349,15 @@ uint32_t EmitPackedF16BitsWithResultModifiers(EmitterState* state, uint32_t bits state, EmitF16BitsToF32(state, EmitAndConstant(state, bits, 0xffffu)), dst); auto hi = ApplyResultModifiersF32( state, EmitF16BitsToF32(state, EmitShiftRightConstant(state, bits, 16)), dst); - const auto pair = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec2_float_type, pair, lo, hi}); - state->builder.AddFunction( - {OpExtInst, state->uint_type, ret, state->glsl_std450, GlslPackHalf2x16, pair}); + const auto pair = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, pair, lo, hi}); + state.builder.AddFunction( + {OpExtInst, state.uint_type, ret, state.glsl_std450, GlslPackHalf2x16, pair}); return ret; } -void EmitPackedF16(EmitterState* state, const IR::Instruction& inst) { +void EmitPackedF16(EmitterState& state, const IR::Instruction& inst) { uint32_t lo = 0; uint32_t hi = 0; switch (inst.op) { @@ -2410,26 +2391,26 @@ void EmitPackedF16(EmitterState* state, const IR::Instruction& inst) { lo = ApplyResultModifiersF32(state, lo, inst.dst); hi = ApplyResultModifiersF32(state, hi, inst.dst); - const auto pair = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec2_float_type, pair, lo, hi}); - state->builder.AddFunction( - {OpExtInst, state->uint_type, ret, state->glsl_std450, GlslPackHalf2x16, pair}); + const auto pair = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, pair, lo, hi}); + state.builder.AddFunction( + {OpExtInst, state.uint_type, ret, state.glsl_std450, GlslPackHalf2x16, pair}); EmitStoreU32(state, inst.dst, ret); } -uint32_t EmitPackedInteger16Select(EmitterState* state, uint32_t lhs, uint32_t rhs, +uint32_t EmitPackedInteger16Select(EmitterState& state, uint32_t lhs, uint32_t rhs, bool signed_compare, bool max_value) { - const auto cond = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); + const auto cond = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); const auto op = signed_compare ? (max_value ? OpSGreaterThanEqual : OpSLessThan) : (max_value ? OpUGreaterThanEqual : OpULessThan); - state->builder.AddFunction({op, state->bool_type, cond, lhs, rhs}); - state->builder.AddFunction({OpSelect, state->uint_type, ret, cond, lhs, rhs}); + state.builder.AddFunction({op, state.bool_type, cond, lhs, rhs}); + state.builder.AddFunction({OpSelect, state.uint_type, ret, cond, lhs, rhs}); return ret; } -uint32_t EmitPackedInteger16Lane(EmitterState* state, const IR::Instruction& inst, bool high_lane) { +uint32_t EmitPackedInteger16Lane(EmitterState& state, const IR::Instruction& inst, bool high_lane) { const auto opcode = inst.op; if (opcode == IR::Opcode::PackedLshlrevB16 || opcode == IR::Opcode::PackedLshrrevB16 || opcode == IR::Opcode::PackedAshrrevI16) { @@ -2437,11 +2418,11 @@ uint32_t EmitPackedInteger16Lane(EmitterState* state, const IR::Instruction& ins EmitAndConstant(state, EmitU16LaneBits(state, inst.src[0], high_lane), 0xfu); const auto arithmetic = opcode == IR::Opcode::PackedAshrrevI16; const auto value = EmitU16LaneBits(state, inst.src[1], high_lane, arithmetic); - const auto ret = state->builder.AllocateId(); + const auto ret = state.builder.AllocateId(); const auto shift_op = opcode == IR::Opcode::PackedLshlrevB16 ? OpShiftLeftLogical : arithmetic ? OpShiftRightArithmetic : OpShiftRightLogical; - state->builder.AddFunction({shift_op, state->uint_type, ret, value, count}); + state.builder.AddFunction({shift_op, state.uint_type, ret, value, count}); return ret; } @@ -2455,27 +2436,27 @@ uint32_t EmitPackedInteger16Lane(EmitterState* state, const IR::Instruction& ins case IR::Opcode::PackedMadU16: { const auto addend = EmitU16LaneBits(state, inst.src[2], high_lane, opcode == IR::Opcode::PackedMadI16); - const auto mul = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpIMul, state->uint_type, mul, lhs, rhs}); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, mul, addend}); + const auto mul = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpIMul, state.uint_type, mul, lhs, rhs}); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, mul, addend}); return ret; } case IR::Opcode::PackedMulLoU16: { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpIMul, state->uint_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpIMul, state.uint_type, ret, lhs, rhs}); return ret; } case IR::Opcode::PackedAddI16: case IR::Opcode::PackedAddU16: { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, lhs, rhs}); return ret; } case IR::Opcode::PackedSubI16: case IR::Opcode::PackedSubU16: { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpISub, state->uint_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpISub, state.uint_type, ret, lhs, rhs}); return ret; } case IR::Opcode::PackedMaxI16: @@ -2490,7 +2471,7 @@ uint32_t EmitPackedInteger16Lane(EmitterState* state, const IR::Instruction& ins return ConstantU32(state, 0); } -void EmitPackedInteger16(EmitterState* state, const IR::Instruction& inst) { +void EmitPackedInteger16(EmitterState& state, const IR::Instruction& inst) { const auto lo = EmitPackedInteger16Lane(state, inst, false); const auto hi = EmitPackedInteger16Lane(state, inst, true); const auto lo_bits = EmitAndConstant(state, lo, 0xffffu); @@ -2498,36 +2479,36 @@ void EmitPackedInteger16(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, inst.dst, EmitOrU32(state, lo_bits, hi_bits)); } -void EmitMadMixF16(EmitterState* state, const IR::Instruction& inst) { +void EmitMadMixF16(EmitterState& state, const IR::Instruction& inst) { const auto src0 = EmitMixF32Load(state, inst.src[0]); const auto src1 = EmitMixF32Load(state, inst.src[1]); const auto src2 = EmitMixF32Load(state, inst.src[2]); - const auto fma = state->builder.AllocateId(); - const auto pair = state->builder.AllocateId(); - const auto packed = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, fma, state->glsl_std450, GlslFma, src0, src1, src2}); + const auto fma = state.builder.AllocateId(); + const auto pair = state.builder.AllocateId(); + const auto packed = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, fma, state.glsl_std450, GlslFma, src0, src1, src2}); const auto result = ApplyResultModifiersF32(state, fma, inst.dst); - state->builder.AddFunction( - {OpCompositeConstruct, state->vec2_float_type, pair, result, ConstantF32(state, 0)}); - state->builder.AddFunction( - {OpExtInst, state->uint_type, packed, state->glsl_std450, GlslPackHalf2x16, pair}); + state.builder.AddFunction( + {OpCompositeConstruct, state.vec2_float_type, pair, result, ConstantF32(state, 0)}); + state.builder.AddFunction( + {OpExtInst, state.uint_type, packed, state.glsl_std450, GlslPackHalf2x16, pair}); EmitStoreU32(state, inst.dst, packed); } -void EmitMinMax3F32(EmitterState* state, const IR::Instruction& inst, bool max_value) { +void EmitMinMax3F32(EmitterState& state, const IR::Instruction& inst, bool max_value) { const auto src0 = EmitFloatLoad(state, inst.src[0]); const auto src1 = EmitFloatLoad(state, inst.src[1]); const auto src2 = EmitFloatLoad(state, inst.src[2]); const auto tmp = EmitMinMaxF32Value(state, src0, src1, max_value); const auto base = EmitMinMaxF32Value(state, tmp, src2, max_value); const auto f32 = ApplyResultModifiersF32(state, base, inst.dst); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, f32}); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, f32}); EmitStoreU32(state, inst.dst, u32); } -void EmitMed3F32(EmitterState* state, const IR::Instruction& inst) { +void EmitMed3F32(EmitterState& state, const IR::Instruction& inst) { const auto src0 = EmitFloatLoad(state, inst.src[0]); const auto src1 = EmitFloatLoad(state, inst.src[1]); const auto src2 = EmitFloatLoad(state, inst.src[2]); @@ -2541,8 +2522,8 @@ void EmitMed3F32(EmitterState* state, const IR::Instruction& inst) { const auto any_nan = EmitLogicalOrBool(state, nan01, EmitClassifyF32(state, src2).nan); const auto base = EmitFSelectValue(state, any_nan, min3, median); const auto f32 = ApplyResultModifiersF32(state, base, inst.dst); - const auto u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, u32, f32}); + const auto u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, u32, f32}); EmitStoreU32(state, inst.dst, u32); } diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterAnalysis.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterAnalysis.cpp index 419fe72fc..30e29fe96 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterAnalysis.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterAnalysis.cpp @@ -60,12 +60,12 @@ void SetError(std::string* error, const char* message) { } } -void CollectRegister(std::vector* registers, IR::Register reg) { - if (std::any_of(registers->begin(), registers->end(), +void CollectRegister(std::vector& registers, IR::Register reg) { + if (std::any_of(registers.begin(), registers.end(), [reg](const RegisterBinding& binding) { return binding.reg == reg; })) { return; } - registers->push_back({reg, 0}); + registers.push_back({reg, 0}); } IR::Operand MakeRegisterOperand(IR::RegisterFile file, uint32_t index) { @@ -98,7 +98,7 @@ bool IsSccOperand(const IR::Operand& operand) { bool IsCompareOpcode(IR::Opcode op); -void CollectMaskStateRegisters(std::vector* registers) { +void CollectMaskStateRegisters(std::vector& registers) { CollectRegister(registers, {IR::RegisterFile::Exec, 0}); CollectRegister(registers, {IR::RegisterFile::Exec, 1}); CollectRegister(registers, {IR::RegisterFile::Vcc, 0}); @@ -106,7 +106,7 @@ void CollectMaskStateRegisters(std::vector* registers) { CollectRegister(registers, SccRegister()); } -void CollectSequentialRegisters(std::vector* registers, const IR::Operand& base, +void CollectSequentialRegisters(std::vector& registers, const IR::Operand& base, uint32_t count) { if (base.kind != IR::OperandKind::Register) { return; @@ -129,8 +129,8 @@ uint32_t MaxCollectedVectorRegisterEnd(const std::vector& regis } void CollectMoveRelSourceRegisters(const IR::Program& program, - std::vector* registers) { - const auto max_vector_end = MaxCollectedVectorRegisterEnd(*registers); + std::vector& registers) { + const auto max_vector_end = MaxCollectedVectorRegisterEnd(registers); for (const auto& block: program.blocks) { for (const auto& inst: block.instructions) { if (inst.op != IR::Opcode::MoveRelSourceU32 || @@ -184,7 +184,7 @@ uint32_t PairDwordSourceCount(IR::Opcode op, uint32_t src_count) { } } -void CollectRegisters(const IR::Program& program, std::vector* registers) { +void CollectRegisters(const IR::Program& program, std::vector& registers) { CollectMaskStateRegisters(registers); for (const auto& block: program.blocks) { for (const auto& inst: block.instructions) { @@ -267,16 +267,16 @@ bool HasOutput(const std::vector& outputs, IR::StageOutputKind ki }); } -void CopyProgramInputsAndOutputs(EmitterState* state, const IR::Program& program) { +void CopyProgramInputsAndOutputs(EmitterState& state, const IR::Program& program) { for (const auto& input: program.info.inputs) { - state->inputs.push_back( + state.inputs.push_back( {input.kind, input.location, input.component_count, 0, input.debug_name}); } for (const auto& output: program.info.outputs) { - if (HasOutput(state->outputs, output.kind, output.index)) { + if (HasOutput(state.outputs, output.kind, output.index)) { continue; } - state->outputs.push_back( + state.outputs.push_back( {output.kind, output.index, output.location, 0, output.debug_name}); } } @@ -528,23 +528,23 @@ uint32_t PointerForRegister(const EmitterState& state, IR::Register reg) { return 0; } -uint32_t ConstantU32(EmitterState* state, uint32_t value); -void EmitStoreU32(EmitterState* state, const IR::Operand& dst, uint32_t value); -uint32_t EmitSubgroupLocalInvocationId(EmitterState* state); -uint32_t EmitLaneIndexActiveBool(EmitterState* state, uint32_t lane); +uint32_t ConstantU32(EmitterState& state, uint32_t value); +void EmitStoreU32(EmitterState& state, const IR::Operand& dst, uint32_t value); +uint32_t EmitSubgroupLocalInvocationId(EmitterState& state); +uint32_t EmitLaneIndexActiveBool(EmitterState& state, uint32_t lane); [[noreturn]] void ExitDescriptorBindingFailure(const EmitterState& state, IR::DescriptorBindingKind kind, uint32_t resource, const char* reason) { EXIT("shader binding resolution failed during SPIR-V emit: hash=0x%016" PRIx64 " stage=%u resource=%" PRIu32 " binding_kind=%u reason=%s\n", - state.program->shader_hash, static_cast(state.stage), resource, + state.program.shader_hash, static_cast(state.stage), resource, static_cast(kind), reason); std::abort(); } DescriptorResourceBinding ResourceForDescriptor(const EmitterState& state, IR::DescriptorBindingKind kind, uint32_t resource) { - const auto* descriptor = IR::FindBinding(state.program->bindings, kind); + const auto* descriptor = IR::FindBinding(state.program.bindings, kind); if (descriptor == nullptr) { ExitDescriptorBindingFailure(state, kind, resource, "descriptor group was not allocated"); } @@ -557,15 +557,15 @@ DescriptorResourceBinding ResourceForDescriptor(const EmitterState& state, return {descriptor, static_cast(found - descriptor->resources.begin())}; } -uint32_t DescriptorElementPointer(EmitterState* state, uint32_t result_ptr_type, +uint32_t DescriptorElementPointer(EmitterState& state, uint32_t result_ptr_type, uint32_t variable_id, uint32_t array_index, IR::DescriptorBindingKind kind, uint32_t resource, const char* variable_name) { if (variable_id == 0) { - ExitDescriptorBindingFailure(*state, kind, resource, variable_name); + ExitDescriptorBindingFailure(state, kind, resource, variable_name); } - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction( + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction( {OpAccessChain, result_ptr_type, pointer, variable_id, ConstantU32(state, array_index)}); return pointer; } @@ -673,71 +673,71 @@ IR::DescriptorBindingKind StorageBindingKind(bool uint_image, ImageViewKind view } } -uint32_t LoadSampledImageDescriptor(EmitterState* state, const IR::MemoryInfo& mem, uint32_t use_pc, +uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, ImageViewKind view) { (void)use_pc; const bool integer = mem.kind == IR::ResourceKind::ImageUint; const auto kind = SampledBindingKind(integer, view); - const auto binding = ResourceForDescriptor(*state, kind, mem.resource); - const auto& descriptors = state->sampled_images[SampledImageIndex(integer, view)]; + const auto binding = ResourceForDescriptor(state, kind, mem.resource); + const auto& descriptors = state.sampled_images[SampledImageIndex(integer, view)]; const auto pointer = DescriptorElementPointer( state, descriptors.pointer_type, descriptors.variable, binding.array_index, kind, mem.resource, "sampled image descriptor array was not emitted"); - const auto image = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, ImageViewImageType(*state, view, integer), image, pointer}); + const auto image = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, ImageViewImageType(state, view, integer), image, pointer}); return image; } -uint32_t LoadSamplerDescriptor(EmitterState* state, uint32_t sampler, uint32_t use_pc) { +uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler, uint32_t use_pc) { (void)use_pc; const auto binding = - ResourceForDescriptor(*state, IR::DescriptorBindingKind::Samplers, sampler); + ResourceForDescriptor(state, IR::DescriptorBindingKind::Samplers, sampler); const auto pointer = DescriptorElementPointer( - state, state->ptr_uniform_sampler, state->sampler_variable, binding.array_index, + state, state.ptr_uniform_sampler, state.sampler_variable, binding.array_index, IR::DescriptorBindingKind::Samplers, sampler, "sampler descriptor array was not emitted"); - const auto sampler_id = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->sampler_type, sampler_id, pointer}); + const auto sampler_id = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.sampler_type, sampler_id, pointer}); return sampler_id; } -uint32_t MakeSampledImage(EmitterState* state, const IR::MemoryInfo& mem, uint32_t use_pc, +uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, ImageViewKind view) { const auto image = LoadSampledImageDescriptor(state, mem, use_pc, view); const auto sampler = LoadSamplerDescriptor(state, mem.sampler, use_pc); if (image == 0 || sampler == 0) { ExitDescriptorBindingFailure( - *state, SampledBindingKind(mem.kind == IR::ResourceKind::ImageUint, view), mem.resource, + state, SampledBindingKind(mem.kind == IR::ResourceKind::ImageUint, view), mem.resource, "sampled image or sampler descriptor load failed"); } - const auto sampled_image = state->builder.AllocateId(); - state->builder.AddFunction( + const auto sampled_image = state.builder.AllocateId(); + state.builder.AddFunction( {OpSampledImage, - ImageViewSampledImageType(*state, view, mem.kind == IR::ResourceKind::ImageUint), + ImageViewSampledImageType(state, view, mem.kind == IR::ResourceKind::ImageUint), sampled_image, image, sampler}); return sampled_image; } -uint32_t StorageImageDescriptorPointer(EmitterState* state, uint32_t resource, bool uint_image, +uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource, bool uint_image, uint32_t use_pc, ImageViewKind view) { (void)use_pc; const auto kind = StorageBindingKind(uint_image, view); - const auto binding = ResourceForDescriptor(*state, kind, resource); - const auto ptr_type = StorageImagePointerType(*state, uint_image, view); - const auto variable = StorageImageVariable(*state, uint_image, view); + const auto binding = ResourceForDescriptor(state, kind, resource); + const auto ptr_type = StorageImagePointerType(state, uint_image, view); + const auto variable = StorageImageVariable(state, uint_image, view); return DescriptorElementPointer(state, ptr_type, variable, binding.array_index, kind, resource, "storage image descriptor array was not emitted"); } -uint32_t LoadStorageImageDescriptor(EmitterState* state, uint32_t resource, bool uint_image, +uint32_t LoadStorageImageDescriptor(EmitterState& state, uint32_t resource, bool uint_image, uint32_t use_pc, ImageViewKind view) { const auto pointer = StorageImageDescriptorPointer(state, resource, uint_image, use_pc, view); if (pointer == 0) { - ExitDescriptorBindingFailure(*state, StorageBindingKind(uint_image, view), resource, + ExitDescriptorBindingFailure(state, StorageBindingKind(uint_image, view), resource, "storage image descriptor pointer creation failed"); } - const auto type = StorageImageType(*state, uint_image, view); - const auto image = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, type, image, pointer}); + const auto type = StorageImageType(state, uint_image, view); + const auto image = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, type, image, pointer}); return image; } diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterControlFlow.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterControlFlow.cpp index 86e87a512..b37fff981 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterControlFlow.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterControlFlow.cpp @@ -2,8 +2,8 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { -void ComputeReachableBlocks(EmitterState* state, const IR::Program& program) { - state->reachable_blocks.assign(program.blocks.size(), false); +void ComputeReachableBlocks(EmitterState& state, const IR::Program& program) { + state.reachable_blocks.assign(program.blocks.size(), false); if (program.blocks.empty()) { return; } @@ -13,38 +13,38 @@ void ComputeReachableBlocks(EmitterState* state, const IR::Program& program) { while (!stack.empty()) { const auto block_id = stack.back(); stack.pop_back(); - if (block_id >= program.blocks.size() || state->reachable_blocks[block_id]) { + if (block_id >= program.blocks.size() || state.reachable_blocks[block_id]) { continue; } - state->reachable_blocks[block_id] = true; + state.reachable_blocks[block_id] = true; for (auto succ: program.blocks[block_id].successors) { - if (succ < program.blocks.size() && !state->reachable_blocks[succ]) { + if (succ < program.blocks.size() && !state.reachable_blocks[succ]) { stack.push_back(succ); } } } } -void AllocateBlockLabels(EmitterState* state, const IR::Program& program) { +void AllocateBlockLabels(EmitterState& state, const IR::Program& program) { for (const auto& block: program.blocks) { - if (block.id < state->reachable_blocks.size() && state->reachable_blocks[block.id]) { - state->block_labels.emplace(block.id, state->builder.AllocateId()); + if (block.id < state.reachable_blocks.size() && state.reachable_blocks[block.id]) { + state.block_labels.emplace(block.id, state.builder.AllocateId()); } } } -void AllocateDispatcherState(EmitterState* state, const IR::Program& program) { - state->dispatcher_fallback = program.dispatcher_fallback; - if (!state->dispatcher_fallback) { +void AllocateDispatcherState(EmitterState& state, const IR::Program& program) { + state.dispatcher_fallback = program.dispatcher_fallback; + if (!state.dispatcher_fallback) { return; } - state->dispatch_pc_variable = state->builder.AllocateId(); - state->dispatch_header_label = state->builder.AllocateId(); - state->dispatch_select_label = state->builder.AllocateId(); - state->dispatch_default_label = state->builder.AllocateId(); - state->dispatch_after_switch_label = state->builder.AllocateId(); - state->dispatch_continue_label = state->builder.AllocateId(); - state->dispatch_merge_label = state->builder.AllocateId(); + state.dispatch_pc_variable = state.builder.AllocateId(); + state.dispatch_header_label = state.builder.AllocateId(); + state.dispatch_select_label = state.builder.AllocateId(); + state.dispatch_default_label = state.builder.AllocateId(); + state.dispatch_after_switch_label = state.builder.AllocateId(); + state.dispatch_continue_label = state.builder.AllocateId(); + state.dispatch_merge_label = state.builder.AllocateId(); } uint32_t BlockLabel(const EmitterState& state, uint32_t block_id) { @@ -52,7 +52,7 @@ uint32_t BlockLabel(const EmitterState& state, uint32_t block_id) { return it == state.block_labels.end() ? 0 : it->second; } -uint32_t EmitBranchCondition(EmitterState* state, CFG::BranchCondition condition) { +uint32_t EmitBranchCondition(EmitterState& state, CFG::BranchCondition condition) { switch (condition) { case CFG::BranchCondition::SccZero: return EmitSccBool(state, false); case CFG::BranchCondition::SccNonZero: return EmitSccBool(state, true); @@ -68,29 +68,29 @@ uint32_t EmitBranchCondition(EmitterState* state, CFG::BranchCondition condition } } -void EmitStructuredPrefix(EmitterState* state, const CFG::Terminator& term) { +void EmitStructuredPrefix(EmitterState& state, const CFG::Terminator& term) { if (term.loop_header) { - const auto merge_label = BlockLabel(*state, term.merge_block); - const auto continue_label = BlockLabel(*state, term.continue_block); + const auto merge_label = BlockLabel(state, term.merge_block); + const auto continue_label = BlockLabel(state, term.continue_block); if (merge_label != 0 && continue_label != 0) { - state->builder.AddFunction({OpLoopMerge, merge_label, continue_label, LoopControlNone}); + state.builder.AddFunction({OpLoopMerge, merge_label, continue_label, LoopControlNone}); } return; } if (term.kind == CFG::TerminatorKind::ConditionalBranch && term.merge_block != UINT32_MAX) { - const auto merge_label = BlockLabel(*state, term.merge_block); + const auto merge_label = BlockLabel(state, term.merge_block); if (merge_label != 0) { - state->builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); + state.builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); } } } -void EmitReturn(EmitterState* state) { +void EmitReturn(EmitterState& state) { EmitKillIfPixelValidMaskInactive(state); - state->builder.AddFunction({OpReturn}); + state.builder.AddFunction({OpReturn}); } -void EmitTerminator(EmitterState* state, const CFG::Terminator& term) { +void EmitTerminator(EmitterState& state, const CFG::Terminator& term) { const auto condition = term.kind == CFG::TerminatorKind::ConditionalBranch ? EmitBranchCondition(state, term.condition) : 0; @@ -98,19 +98,19 @@ void EmitTerminator(EmitterState* state, const CFG::Terminator& term) { switch (term.kind) { case CFG::TerminatorKind::Branch: { - const auto label = BlockLabel(*state, term.true_block); + const auto label = BlockLabel(state, term.true_block); if (label != 0) { - state->builder.AddFunction({OpBranch, label}); + state.builder.AddFunction({OpBranch, label}); } else { EmitReturn(state); } break; } case CFG::TerminatorKind::ConditionalBranch: { - const auto true_label = BlockLabel(*state, term.true_block); - const auto false_label = BlockLabel(*state, term.false_block); + const auto true_label = BlockLabel(state, term.true_block); + const auto false_label = BlockLabel(state, term.false_block); if (true_label != 0 && false_label != 0) { - state->builder.AddFunction( + state.builder.AddFunction( {OpBranchConditional, condition, true_label, false_label}); } else { EmitReturn(state); @@ -122,10 +122,10 @@ void EmitTerminator(EmitterState* state, const CFG::Terminator& term) { } bool UserDataDwordIndex(const EmitterState& state, IR::Register reg, uint32_t& dword_index) { - if (state.program == nullptr || reg.file != IR::RegisterFile::Scalar) { + if (reg.file != IR::RegisterFile::Scalar) { return false; } - const auto& registers = state.program->bindings.user_data_registers; + const auto& registers = state.program.bindings.user_data_registers; const auto found = std::lower_bound(registers.begin(), registers.end(), reg.index); if (found != registers.end() && *found == reg.index) { dword_index = static_cast(found - registers.begin()); @@ -134,24 +134,24 @@ bool UserDataDwordIndex(const EmitterState& state, IR::Register reg, uint32_t& d return false; } -uint32_t EmitVsharpDwordLoad(EmitterState* state, uint32_t dword_index) { - if (state->push_constant_variable != 0) { - const auto pointer = state->builder.AllocateId(); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, state->ptr_push_constant_uint, pointer, - state->push_constant_variable, ConstantU32(state, 0), +uint32_t EmitVsharpDwordLoad(EmitterState& state, uint32_t dword_index) { + if (state.push_constant_variable != 0) { + const auto pointer = state.builder.AllocateId(); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, state.ptr_push_constant_uint, pointer, + state.push_constant_variable, ConstantU32(state, 0), ConstantU32(state, dword_index / 4u), ConstantU32(state, dword_index % 4u)}); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); return value; } - if (state->vsharp_storage_variable != 0) { - const auto pointer = state->builder.AllocateId(); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, state->ptr_storage_buffer_uint, pointer, - state->vsharp_storage_variable, ConstantU32(state, 0), + if (state.vsharp_storage_variable != 0) { + const auto pointer = state.builder.AllocateId(); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer_uint, pointer, + state.vsharp_storage_variable, ConstantU32(state, 0), ConstantU32(state, dword_index)}); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); return value; } return ConstantU32(state, 0); @@ -170,52 +170,52 @@ uint32_t InitialRegisterValue(const EmitterState& state, IR::Register reg) { return 0; } -uint32_t EmitInitialRegisterValue(EmitterState* state, IR::Register reg) { +uint32_t EmitInitialRegisterValue(EmitterState& state, IR::Register reg) { uint32_t dword_index = 0; - if (UserDataDwordIndex(*state, reg, dword_index)) { + if (UserDataDwordIndex(state, reg, dword_index)) { return EmitVsharpDwordLoad(state, dword_index); } - return ConstantU32(state, InitialRegisterValue(*state, reg)); + return ConstantU32(state, InitialRegisterValue(state, reg)); } -void EmitRegisterVariables(EmitterState* state) { - if (state->needs_function_lds) { - state->builder.AddFunction( - {OpVariable, state->ptr_workgroup_array, state->lds_variable, StorageClassFunction}); +void EmitRegisterVariables(EmitterState& state) { + if (state.needs_function_lds) { + state.builder.AddFunction( + {OpVariable, state.ptr_workgroup_array, state.lds_variable, StorageClassFunction}); } - for (const auto& binding: state->registers) { - state->builder.AddFunction( - {OpVariable, state->ptr_func_uint, binding.pointer_id, StorageClassFunction}); + for (const auto& binding: state.registers) { + state.builder.AddFunction( + {OpVariable, state.ptr_func_uint, binding.pointer_id, StorageClassFunction}); } - if (state->dispatcher_fallback) { - state->builder.AddFunction( - {OpVariable, state->ptr_func_uint, state->dispatch_pc_variable, StorageClassFunction}); + if (state.dispatcher_fallback) { + state.builder.AddFunction( + {OpVariable, state.ptr_func_uint, state.dispatch_pc_variable, StorageClassFunction}); } - if (state->pixel_valid_mask_variable != 0) { - state->builder.AddFunction({OpVariable, state->ptr_func_uint, - state->pixel_valid_mask_variable, StorageClassFunction}); - state->builder.AddFunction( - {OpStore, state->pixel_valid_mask_variable, ConstantU32(state, 1)}); + if (state.pixel_valid_mask_variable != 0) { + state.builder.AddFunction({OpVariable, state.ptr_func_uint, + state.pixel_valid_mask_variable, StorageClassFunction}); + state.builder.AddFunction( + {OpStore, state.pixel_valid_mask_variable, ConstantU32(state, 1)}); } - for (const auto& binding: state->registers) { - state->builder.AddFunction( + for (const auto& binding: state.registers) { + state.builder.AddFunction( {OpStore, binding.pointer_id, EmitInitialRegisterValue(state, binding.reg)}); } } -void EmitComputeInputRegisters(EmitterState* state) { - if (state->stage != ShaderType::Compute || state->compute_input_info == nullptr) { +void EmitComputeInputRegisters(EmitterState& state) { + if (state.stage != ShaderType::Compute || state.compute_input_info == nullptr) { return; } - const auto* cs = state->compute_input_info; + const auto* cs = state.compute_input_info; const auto thread_ids = cs->thread_ids_num > 0 ? std::min(static_cast(cs->thread_ids_num), 3u) : 0u; for (uint32_t i = 0; i < thread_ids; i++) { - const auto pointer = PointerForRegister(*state, {IR::RegisterFile::Vector, i}); + const auto pointer = PointerForRegister(state, {IR::RegisterFile::Vector, i}); if (pointer != 0) { - state->builder.AddFunction( + state.builder.AddFunction( {OpStore, pointer, EmitInputComponentU32(state, IR::StageInputKind::LocalInvocationId, i)}); } @@ -227,10 +227,10 @@ void EmitComputeInputRegisters(EmitterState* state) { continue; } const auto pointer = PointerForRegister( - *state, + state, {IR::RegisterFile::Scalar, static_cast(cs->workgroup_register) + reg_offset}); if (pointer != 0) { - state->builder.AddFunction( + state.builder.AddFunction( {OpStore, pointer, EmitInputComponentU32(state, IR::StageInputKind::WorkgroupId, i)}); } @@ -239,7 +239,7 @@ void EmitComputeInputRegisters(EmitterState* state) { if (cs->tg_size_en) { const auto pointer = PointerForRegister( - *state, + state, {IR::RegisterFile::Scalar, static_cast(cs->workgroup_register) + reg_offset}); if (pointer != 0) { const uint32_t wave_size = cs->wave_size != 0 ? cs->wave_size : 64u; @@ -250,66 +250,66 @@ void EmitComputeInputRegisters(EmitterState* state) { std::min((total_threads + wave_size - 1u) / wave_size, 0x3fu); const auto local_index = EmitLocalInvocationIndex(state); - const auto wave_id = state->builder.AllocateId(); - const auto wave_bits = state->builder.AllocateId(); - const auto is_first = state->builder.AllocateId(); - const auto first_bit = state->builder.AllocateId(); - const auto base = state->builder.AllocateId(); - const auto packed = state->builder.AllocateId(); - state->builder.AddFunction( - {OpUDiv, state->uint_type, wave_id, local_index, ConstantU32(state, wave_size)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, wave_bits, wave_id, ConstantU32(state, 20)}); - state->builder.AddFunction( - {OpIEqual, state->bool_type, is_first, wave_id, ConstantU32(state, 0)}); - state->builder.AddFunction({OpSelect, state->uint_type, first_bit, is_first, + const auto wave_id = state.builder.AllocateId(); + const auto wave_bits = state.builder.AllocateId(); + const auto is_first = state.builder.AllocateId(); + const auto first_bit = state.builder.AllocateId(); + const auto base = state.builder.AllocateId(); + const auto packed = state.builder.AllocateId(); + state.builder.AddFunction( + {OpUDiv, state.uint_type, wave_id, local_index, ConstantU32(state, wave_size)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, wave_bits, wave_id, ConstantU32(state, 20)}); + state.builder.AddFunction( + {OpIEqual, state.bool_type, is_first, wave_id, ConstantU32(state, 0)}); + state.builder.AddFunction({OpSelect, state.uint_type, first_bit, is_first, ConstantU32(state, 0x80000000u), ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpBitwiseOr, state->uint_type, base, wave_bits, ConstantU32(state, waves)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, packed, base, first_bit}); - state->builder.AddFunction({OpStore, pointer, packed}); + state.builder.AddFunction( + {OpBitwiseOr, state.uint_type, base, wave_bits, ConstantU32(state, waves)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, packed, base, first_bit}); + state.builder.AddFunction({OpStore, pointer, packed}); } } } -void EmitPixelFragCoordComponent(EmitterState* state, uint32_t component, uint32_t vgpr) { - const auto input = InputVariableForKind(*state, IR::StageInputKind::FragCoord); - const auto dst = PointerForRegister(*state, {IR::RegisterFile::Vector, vgpr}); +void EmitPixelFragCoordComponent(EmitterState& state, uint32_t component, uint32_t vgpr) { + const auto input = InputVariableForKind(state, IR::StageInputKind::FragCoord); + const auto dst = PointerForRegister(state, {IR::RegisterFile::Vector, vgpr}); if (input == 0 || dst == 0) { return; } - const auto pointer = state->builder.AllocateId(); - const auto value = state->builder.AllocateId(); - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction( - {OpAccessChain, state->ptr_input_float, pointer, input, ConstantU32(state, component)}); - state->builder.AddFunction({OpLoad, state->float_type, value, pointer}); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, value}); - state->builder.AddFunction({OpStore, dst, bits}); + const auto pointer = state.builder.AllocateId(); + const auto value = state.builder.AllocateId(); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction( + {OpAccessChain, state.ptr_input_float, pointer, input, ConstantU32(state, component)}); + state.builder.AddFunction({OpLoad, state.float_type, value, pointer}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, value}); + state.builder.AddFunction({OpStore, dst, bits}); } -void EmitPixelFrontFacingRegister(EmitterState* state, uint32_t vgpr) { - const auto input = InputVariableForKind(*state, IR::StageInputKind::FrontFacing); - const auto dst = PointerForRegister(*state, {IR::RegisterFile::Vector, vgpr}); +void EmitPixelFrontFacingRegister(EmitterState& state, uint32_t vgpr) { + const auto input = InputVariableForKind(state, IR::StageInputKind::FrontFacing); + const auto dst = PointerForRegister(state, {IR::RegisterFile::Vector, vgpr}); if (input == 0 || dst == 0) { return; } - const auto value = state->builder.AllocateId(); - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->bool_type, value, input}); - state->builder.AddFunction( - {OpSelect, state->uint_type, bits, value, ConstantU32(state, 1), ConstantU32(state, 0)}); - state->builder.AddFunction({OpStore, dst, bits}); + const auto value = state.builder.AllocateId(); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.bool_type, value, input}); + state.builder.AddFunction( + {OpSelect, state.uint_type, bits, value, ConstantU32(state, 1), ConstantU32(state, 0)}); + state.builder.AddFunction({OpStore, dst, bits}); } -void EmitPixelInputRegisters(EmitterState* state) { - if (state->stage != ShaderType::Pixel || state->pixel_input_info == nullptr) { +void EmitPixelInputRegisters(EmitterState& state) { + if (state.stage != ShaderType::Pixel || state.pixel_input_info == nullptr) { return; } - const auto* ps = state->pixel_input_info; + const auto* ps = state.pixel_input_info; uint32_t reg = ps->ps_system_input_base; if (ps->HasPositionInput()) { if (ps->ps_pos_x) { @@ -334,37 +334,37 @@ void EmitPixelInputRegisters(EmitterState* state) { } } -uint32_t EmitInputScalarU32(EmitterState* state, IR::StageInputKind kind) { - const auto variable = InputVariableForKind(*state, kind); +uint32_t EmitInputScalarU32(EmitterState& state, IR::StageInputKind kind) { + const auto variable = InputVariableForKind(state, kind); if (variable == 0) { return ConstantU32(state, 0); } - const auto raw = state->builder.AllocateId(); - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->int_type, raw, variable}); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, raw}); + const auto raw = state.builder.AllocateId(); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.int_type, raw, variable}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, raw}); return bits; } -void EmitVertexInputRegisters(EmitterState* state) { - if (state->stage != ShaderType::Vertex) { +void EmitVertexInputRegisters(EmitterState& state) { + if (state.stage != ShaderType::Vertex) { return; } - const auto vertex_index = PointerForRegister(*state, {IR::RegisterFile::Vector, 5}); + const auto vertex_index = PointerForRegister(state, {IR::RegisterFile::Vector, 5}); if (vertex_index != 0) { - state->builder.AddFunction( + state.builder.AddFunction( {OpStore, vertex_index, EmitInputScalarU32(state, IR::StageInputKind::VertexIndex)}); } - const auto instance_index = PointerForRegister(*state, {IR::RegisterFile::Vector, 8}); + const auto instance_index = PointerForRegister(state, {IR::RegisterFile::Vector, 8}); if (instance_index != 0) { - state->builder.AddFunction({OpStore, instance_index, + state.builder.AddFunction({OpStore, instance_index, EmitInputScalarU32(state, IR::StageInputKind::InstanceIndex)}); } } -void EmitInstruction(EmitterState* state, const IR::Instruction& inst) { +void EmitInstruction(EmitterState& state, const IR::Instruction& inst) { switch (inst.op) { case IR::Opcode::ControlNop: EmitControlNop(state, inst); break; case IR::Opcode::Waitcnt: EmitWaitcnt(state, inst); break; @@ -846,7 +846,7 @@ void EmitInstruction(EmitterState* state, const IR::Instruction& inst) { case IR::Opcode::ImageSample: EmitImageSample(state, inst); break; case IR::Opcode::ImageGather4: EmitImageGather4(state, inst); break; case IR::Opcode::Export: - if (ExportUsesPixelValidMask(*state, inst)) { + if (ExportUsesPixelValidMask(state, inst)) { EmitUpdatePixelValidMask(state); } EmitGuardedByExec(state, [&]() { EmitExport(state, inst); }); @@ -855,16 +855,16 @@ void EmitInstruction(EmitterState* state, const IR::Instruction& inst) { } } -uint32_t DispatcherTargetValue(EmitterState* state, uint32_t block_id) { - return BlockLabel(*state, block_id) != 0 ? block_id : UINT32_MAX; +uint32_t DispatcherTargetValue(EmitterState& state, uint32_t block_id) { + return BlockLabel(state, block_id) != 0 ? block_id : UINT32_MAX; } -void EmitDispatcherStoreTarget(EmitterState* state, uint32_t block_id) { - state->builder.AddFunction({OpStore, state->dispatch_pc_variable, +void EmitDispatcherStoreTarget(EmitterState& state, uint32_t block_id) { + state.builder.AddFunction({OpStore, state.dispatch_pc_variable, ConstantU32(state, DispatcherTargetValue(state, block_id))}); } -void EmitDispatcherExit(EmitterState* state); +void EmitDispatcherExit(EmitterState& state); bool RegisterForScalarCode(uint32_t code, IR::Register& reg) { if (code < 106u) { @@ -881,21 +881,21 @@ bool RegisterForScalarCode(uint32_t code, IR::Register& reg) { } } -bool EmitDispatcherLoadScalarCode(EmitterState* state, uint32_t code, uint32_t& value) { +bool EmitDispatcherLoadScalarCode(EmitterState& state, uint32_t code, uint32_t& value) { IR::Register reg; if (!RegisterForScalarCode(code, reg)) { return false; } - const auto pointer = PointerForRegister(*state, reg); + const auto pointer = PointerForRegister(state, reg); if (pointer == 0) { return false; } - value = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + value = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); return true; } -void EmitDispatcherStoreSelectorTarget(EmitterState* state, const CFG::Terminator& term) { +void EmitDispatcherStoreSelectorTarget(EmitterState& state, const CFG::Terminator& term) { if (term.indirect_selector_code == UINT32_MAX || term.indirect_selector_values.empty() || term.indirect_selector_values.size() != term.indirect_selector_targets.size()) { EmitDispatcherExit(state); @@ -910,21 +910,21 @@ void EmitDispatcherStoreSelectorTarget(EmitterState* state, const CFG::Terminato uint32_t selected = ConstantU32(state, UINT32_MAX); for (uint32_t i = 0; i < term.indirect_selector_values.size(); i++) { - const auto match = state->builder.AllocateId(); - state->builder.AddFunction({OpIEqual, state->bool_type, match, selector_value, + const auto match = state.builder.AllocateId(); + state.builder.AddFunction({OpIEqual, state.bool_type, match, selector_value, ConstantU32(state, term.indirect_selector_values[i])}); - const auto next = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->uint_type, next, match, + const auto next = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.uint_type, next, match, ConstantU32(state, DispatcherTargetValue(state, term.indirect_selector_targets[i])), selected}); selected = next; } - state->builder.AddFunction({OpStore, state->dispatch_pc_variable, selected}); - state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label}); + state.builder.AddFunction({OpStore, state.dispatch_pc_variable, selected}); + state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label}); } -void EmitDispatcherStoreIndirectTarget(EmitterState* state, const CFG::Terminator& term) { +void EmitDispatcherStoreIndirectTarget(EmitterState& state, const CFG::Terminator& term) { if (term.indirect_selector_code != UINT32_MAX) { EmitDispatcherStoreSelectorTarget(state, term); return; @@ -936,55 +936,55 @@ void EmitDispatcherStoreIndirectTarget(EmitterState* state, const CFG::Terminato } const auto pointer = - PointerForRegister(*state, IR::Register {IR::RegisterFile::Scalar, term.indirect_pc_sgpr}); + PointerForRegister(state, IR::Register {IR::RegisterFile::Scalar, term.indirect_pc_sgpr}); if (pointer == 0) { EmitDispatcherExit(state); return; } - const auto pc_value = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, pc_value, pointer}); + const auto pc_value = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, pc_value, pointer}); uint32_t selected = ConstantU32(state, UINT32_MAX); const auto count = std::min(term.indirect_target_pcs.size(), term.indirect_targets.size()); for (uint32_t i = 0; i < count; i++) { - const auto match = state->builder.AllocateId(); - state->builder.AddFunction({OpIEqual, state->bool_type, match, pc_value, + const auto match = state.builder.AllocateId(); + state.builder.AddFunction({OpIEqual, state.bool_type, match, pc_value, ConstantU32(state, term.indirect_target_pcs[i])}); - const auto next = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->uint_type, next, match, + const auto next = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.uint_type, next, match, ConstantU32(state, DispatcherTargetValue(state, term.indirect_targets[i])), selected}); selected = next; } - state->builder.AddFunction({OpStore, state->dispatch_pc_variable, selected}); - state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label}); + state.builder.AddFunction({OpStore, state.dispatch_pc_variable, selected}); + state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label}); } -void EmitDispatcherExit(EmitterState* state) { - state->builder.AddFunction( - {OpStore, state->dispatch_pc_variable, ConstantU32(state, UINT32_MAX)}); - state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label}); +void EmitDispatcherExit(EmitterState& state) { + state.builder.AddFunction( + {OpStore, state.dispatch_pc_variable, ConstantU32(state, UINT32_MAX)}); + state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label}); } -void EmitDispatcherTerminator(EmitterState* state, const CFG::Terminator& term) { +void EmitDispatcherTerminator(EmitterState& state, const CFG::Terminator& term) { switch (term.kind) { case CFG::TerminatorKind::Branch: - if (BlockLabel(*state, term.true_block) == 0) { + if (BlockLabel(state, term.true_block) == 0) { EmitDispatcherExit(state); return; } EmitDispatcherStoreTarget(state, term.true_block); - state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label}); + state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label}); return; case CFG::TerminatorKind::ConditionalBranch: { const auto condition = EmitBranchCondition(state, term.condition); - const auto selected = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->uint_type, selected, condition, + const auto selected = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.uint_type, selected, condition, ConstantU32(state, DispatcherTargetValue(state, term.true_block)), ConstantU32(state, DispatcherTargetValue(state, term.false_block))}); - state->builder.AddFunction({OpStore, state->dispatch_pc_variable, selected}); - state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label}); + state.builder.AddFunction({OpStore, state.dispatch_pc_variable, selected}); + state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label}); return; } case CFG::TerminatorKind::IndirectBranch: @@ -994,44 +994,44 @@ void EmitDispatcherTerminator(EmitterState* state, const CFG::Terminator& term) } } -void EmitDispatcherSwitch(EmitterState* state, const IR::Program& program) { - state->builder.AddFunction({OpLabel, state->dispatch_header_label}); - const auto pc_value = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, pc_value, state->dispatch_pc_variable}); - const auto done = state->builder.AllocateId(); - state->builder.AddFunction( - {OpIEqual, state->bool_type, done, pc_value, ConstantU32(state, UINT32_MAX)}); - state->builder.AddFunction({OpLoopMerge, state->dispatch_merge_label, - state->dispatch_continue_label, LoopControlNone}); - state->builder.AddFunction( - {OpBranchConditional, done, state->dispatch_merge_label, state->dispatch_select_label}); +void EmitDispatcherSwitch(EmitterState& state, const IR::Program& program) { + state.builder.AddFunction({OpLabel, state.dispatch_header_label}); + const auto pc_value = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, pc_value, state.dispatch_pc_variable}); + const auto done = state.builder.AllocateId(); + state.builder.AddFunction( + {OpIEqual, state.bool_type, done, pc_value, ConstantU32(state, UINT32_MAX)}); + state.builder.AddFunction({OpLoopMerge, state.dispatch_merge_label, + state.dispatch_continue_label, LoopControlNone}); + state.builder.AddFunction( + {OpBranchConditional, done, state.dispatch_merge_label, state.dispatch_select_label}); - state->builder.AddFunction({OpLabel, state->dispatch_select_label}); - state->builder.AddFunction( - {OpSelectionMerge, state->dispatch_after_switch_label, SelectionControlNone}); - std::vector switch_words = {OpSwitch, pc_value, state->dispatch_default_label}; + state.builder.AddFunction({OpLabel, state.dispatch_select_label}); + state.builder.AddFunction( + {OpSelectionMerge, state.dispatch_after_switch_label, SelectionControlNone}); + std::vector switch_words = {OpSwitch, pc_value, state.dispatch_default_label}; for (const auto& block: program.blocks) { - if (block.id >= state->reachable_blocks.size() || !state->reachable_blocks[block.id]) { + if (block.id >= state.reachable_blocks.size() || !state.reachable_blocks[block.id]) { continue; } - const auto label = BlockLabel(*state, block.id); + const auto label = BlockLabel(state, block.id); if (label != 0) { switch_words.push_back(block.id); switch_words.push_back(label); } } - state->builder.AddFunction(switch_words); + state.builder.AddFunction(switch_words); - state->builder.AddFunction({OpLabel, state->dispatch_default_label}); + state.builder.AddFunction({OpLabel, state.dispatch_default_label}); EmitDispatcherExit(state); } -void EmitDispatcherBlocks(EmitterState* state, const IR::Program& program) { +void EmitDispatcherBlocks(EmitterState& state, const IR::Program& program) { for (const auto& block: program.blocks) { - if (block.id >= state->reachable_blocks.size() || !state->reachable_blocks[block.id]) { + if (block.id >= state.reachable_blocks.size() || !state.reachable_blocks[block.id]) { continue; } - state->builder.AddFunction({OpLabel, BlockLabel(*state, block.id)}); + state.builder.AddFunction({OpLabel, BlockLabel(state, block.id)}); for (const auto& inst: block.instructions) { EmitInstruction(state, inst); } @@ -1039,57 +1039,57 @@ void EmitDispatcherBlocks(EmitterState* state, const IR::Program& program) { } } -void EmitDispatcherLoopTail(EmitterState* state) { - state->builder.AddFunction({OpLabel, state->dispatch_after_switch_label}); - state->builder.AddFunction({OpBranch, state->dispatch_continue_label}); - state->builder.AddFunction({OpLabel, state->dispatch_continue_label}); - state->builder.AddFunction({OpBranch, state->dispatch_header_label}); - state->builder.AddFunction({OpLabel, state->dispatch_merge_label}); +void EmitDispatcherLoopTail(EmitterState& state) { + state.builder.AddFunction({OpLabel, state.dispatch_after_switch_label}); + state.builder.AddFunction({OpBranch, state.dispatch_continue_label}); + state.builder.AddFunction({OpLabel, state.dispatch_continue_label}); + state.builder.AddFunction({OpBranch, state.dispatch_header_label}); + state.builder.AddFunction({OpLabel, state.dispatch_merge_label}); EmitReturn(state); } -void EmitDispatcherFunction(EmitterState* state, const IR::Program& program) { - state->builder.AddFunction({OpStore, state->dispatch_pc_variable, ConstantU32(state, 0)}); - state->builder.AddFunction({OpBranch, state->dispatch_header_label}); +void EmitDispatcherFunction(EmitterState& state, const IR::Program& program) { + state.builder.AddFunction({OpStore, state.dispatch_pc_variable, ConstantU32(state, 0)}); + state.builder.AddFunction({OpBranch, state.dispatch_header_label}); EmitDispatcherSwitch(state, program); EmitDispatcherBlocks(state, program); EmitDispatcherLoopTail(state); } -void EmitFunction(EmitterState* state, const IR::Program& program) { - state->builder.AddFunction( - {OpFunction, state->void_type, state->main_func, FunctionControlNone, state->func_type}); - state->builder.AddFunction({OpLabel, state->entry_label}); +void EmitFunction(EmitterState& state, const IR::Program& program) { + state.builder.AddFunction( + {OpFunction, state.void_type, state.main_func, FunctionControlNone, state.func_type}); + state.builder.AddFunction({OpLabel, state.entry_label}); EmitRegisterVariables(state); EmitComputeInputRegisters(state); EmitPixelInputRegisters(state); EmitVertexInputRegisters(state); - if (state->dispatcher_fallback) { + if (state.dispatcher_fallback) { EmitDispatcherFunction(state, program); - state->builder.AddFunction({OpFunctionEnd}); + state.builder.AddFunction({OpFunctionEnd}); return; } - const auto entry_block_label = BlockLabel(*state, 0); + const auto entry_block_label = BlockLabel(state, 0); if (entry_block_label != 0) { - state->builder.AddFunction({OpBranch, entry_block_label}); + state.builder.AddFunction({OpBranch, entry_block_label}); } else { EmitReturn(state); } for (const auto& block: program.blocks) { - if (block.id >= state->reachable_blocks.size() || !state->reachable_blocks[block.id]) { + if (block.id >= state.reachable_blocks.size() || !state.reachable_blocks[block.id]) { continue; } - state->builder.AddFunction({OpLabel, BlockLabel(*state, block.id)}); + state.builder.AddFunction({OpLabel, BlockLabel(state, block.id)}); for (const auto& inst: block.instructions) { EmitInstruction(state, inst); } EmitTerminator(state, block.terminator); } - state->builder.AddFunction({OpFunctionEnd}); + state.builder.AddFunction({OpFunctionEnd}); } } // namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterExport.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterExport.cpp index d3a2a2e4f..b8dd93069 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterExport.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterExport.cpp @@ -2,7 +2,7 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { -uint32_t EmitExportComponentF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitExportComponentF32(EmitterState& state, const IR::Instruction& inst, uint32_t component) { const bool enabled = ((inst.export_info.en >> component) & 1u) != 0; if (!enabled || component >= inst.src_count || component >= 4u) { @@ -11,7 +11,7 @@ uint32_t EmitExportComponentF32(EmitterState* state, const IR::Instruction& inst return EmitFloatLoad(state, inst.src[component]); } -uint32_t EmitExportVec4F32(EmitterState* state, const IR::Instruction& inst) { +uint32_t EmitExportVec4F32(EmitterState& state, const IR::Instruction& inst) { if (inst.export_info.compr) { uint32_t components[4] = { ConstantF32(state, 0u), @@ -22,21 +22,21 @@ uint32_t EmitExportVec4F32(EmitterState* state, const IR::Instruction& inst) { for (uint32_t pair_index = 0; pair_index < 2u && pair_index < inst.src_count; pair_index++) { const auto raw = EmitValueLoad(state, inst.src[pair_index]); - const auto unpacked = state->builder.AllocateId(); - state->builder.AddFunction({OpExtInst, state->vec2_float_type, unpacked, - state->glsl_std450, GlslUnpackHalf2x16, raw}); + const auto unpacked = state.builder.AllocateId(); + state.builder.AddFunction({OpExtInst, state.vec2_float_type, unpacked, + state.glsl_std450, GlslUnpackHalf2x16, raw}); for (uint32_t lane = 0; lane < 2u; lane++) { const auto component = pair_index * 2u + lane; if (((inst.export_info.en >> component) & 1u) == 0) { continue; } - components[component] = state->builder.AllocateId(); - state->builder.AddFunction( - {OpCompositeExtract, state->float_type, components[component], unpacked, lane}); + components[component] = state.builder.AllocateId(); + state.builder.AddFunction( + {OpCompositeExtract, state.float_type, components[component], unpacked, lane}); } } - const auto vec = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec4_float_type, vec, + const auto vec = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec4_float_type, vec, components[0], components[1], components[2], components[3]}); return vec; } @@ -45,24 +45,24 @@ uint32_t EmitExportVec4F32(EmitterState* state, const IR::Instruction& inst) { const auto y = EmitExportComponentF32(state, inst, 1); const auto z = EmitExportComponentF32(state, inst, 2); const auto w = EmitExportComponentF32(state, inst, 3); - const auto vec = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec4_float_type, vec, x, y, z, w}); + const auto vec = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec4_float_type, vec, x, y, z, w}); return vec; } -uint32_t ApplyMrtExportMapping(EmitterState* state, const IR::Instruction& inst, uint32_t value) { - if (inst.export_info.kind != IR::ExportTargetKind::Mrt || state->pixel_input_info == nullptr || - inst.export_info.index >= state->pixel_input_info->target_export_mapping.size()) { +uint32_t ApplyMrtExportMapping(EmitterState& state, const IR::Instruction& inst, uint32_t value) { + if (inst.export_info.kind != IR::ExportTargetKind::Mrt || state.pixel_input_info == nullptr || + inst.export_info.index >= state.pixel_input_info->target_export_mapping.size()) { return value; } - const auto mapping = state->pixel_input_info->target_export_mapping[inst.export_info.index]; + const auto mapping = state.pixel_input_info->target_export_mapping[inst.export_info.index]; if (mapping.IsIdentity()) { return value; } - const auto mapped = state->builder.AllocateId(); - state->builder.AddFunction({OpVectorShuffle, state->vec4_float_type, mapped, value, value, + const auto mapped = state.builder.AllocateId(); + state.builder.AddFunction({OpVectorShuffle, state.vec4_float_type, mapped, value, value, mapping.Map(0), mapping.Map(1), mapping.Map(2), mapping.Map(3)}); return mapped; } @@ -76,25 +76,25 @@ bool ExportWritesData(const IR::Instruction& inst) { } } -void EmitMrtZExport(EmitterState* state, const IR::Instruction& inst) { - if ((inst.export_info.en & 0x1u) != 0 && state->depth_variable != 0) { - state->builder.AddFunction( - {OpStore, state->depth_variable, EmitExportComponentF32(state, inst, 0)}); +void EmitMrtZExport(EmitterState& state, const IR::Instruction& inst) { + if ((inst.export_info.en & 0x1u) != 0 && state.depth_variable != 0) { + state.builder.AddFunction( + {OpStore, state.depth_variable, EmitExportComponentF32(state, inst, 0)}); } - if ((inst.export_info.en & 0x4u) != 0 && state->sample_mask_variable != 0) { + if ((inst.export_info.en & 0x4u) != 0 && state.sample_mask_variable != 0) { const auto raw = inst.src_count > 2u ? EmitValueLoad(state, inst.src[2]) : ConstantU32(state, 0); - const auto mask = state->builder.AllocateId(); - const auto ptr = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, mask, raw}); - state->builder.AddFunction({OpAccessChain, state->ptr_output_int, ptr, - state->sample_mask_variable, ConstantU32(state, 0)}); - state->builder.AddFunction({OpStore, ptr, mask}); + const auto mask = state.builder.AllocateId(); + const auto ptr = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, mask, raw}); + state.builder.AddFunction({OpAccessChain, state.ptr_output_int, ptr, + state.sample_mask_variable, ConstantU32(state, 0)}); + state.builder.AddFunction({OpStore, ptr, mask}); } } -void EmitExport(EmitterState* state, const IR::Instruction& inst) { +void EmitExport(EmitterState& state, const IR::Instruction& inst) { if (inst.export_info.kind == IR::ExportTargetKind::Null || inst.export_info.kind == IR::ExportTargetKind::Primitive) { return; @@ -109,62 +109,62 @@ void EmitExport(EmitterState* state, const IR::Instruction& inst) { return; } - const auto variable = OutputVariableForExport(*state, inst.export_info); + const auto variable = OutputVariableForExport(state, inst.export_info); if (variable == 0) { return; } const auto value = ApplyMrtExportMapping(state, inst, EmitExportVec4F32(state, inst)); if (inst.export_info.kind == IR::ExportTargetKind::Position) { - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, state->ptr_output_vec4_float, pointer, variable, + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, state.ptr_output_vec4_float, pointer, variable, ConstantU32(state, 0)}); - state->builder.AddFunction({OpStore, pointer, value}); + state.builder.AddFunction({OpStore, pointer, value}); return; } - state->builder.AddFunction({OpStore, variable, value}); + state.builder.AddFunction({OpStore, variable, value}); } bool ExportUsesPixelValidMask(const EmitterState& state, const IR::Instruction& inst) { return state.stage == ShaderType::Pixel && inst.export_info.vm && state.needs_pixel_valid_mask; } -void EmitKillIfBoolFalse(EmitterState* state, uint32_t active) { - const auto kill_label = state->builder.AllocateId(); - const auto merge_label = state->builder.AllocateId(); - const auto inactive = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalNot, state->bool_type, inactive, active}); - state->builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); - state->builder.AddFunction({OpBranchConditional, inactive, kill_label, merge_label}); - state->builder.AddFunction({OpLabel, kill_label}); - state->builder.AddFunction({OpKill}); - state->builder.AddFunction({OpLabel, merge_label}); +void EmitKillIfBoolFalse(EmitterState& state, uint32_t active) { + const auto kill_label = state.builder.AllocateId(); + const auto merge_label = state.builder.AllocateId(); + const auto inactive = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalNot, state.bool_type, inactive, active}); + state.builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); + state.builder.AddFunction({OpBranchConditional, inactive, kill_label, merge_label}); + state.builder.AddFunction({OpLabel, kill_label}); + state.builder.AddFunction({OpKill}); + state.builder.AddFunction({OpLabel, merge_label}); } -void EmitUpdatePixelValidMask(EmitterState* state) { - if (state->pixel_valid_mask_variable == 0) { +void EmitUpdatePixelValidMask(EmitterState& state) { + if (state.pixel_valid_mask_variable == 0) { return; } const auto active = EmitExecActiveBool(state); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->uint_type, value, active, ConstantU32(state, 1), ConstantU32(state, 0)}); - state->builder.AddFunction({OpStore, state->pixel_valid_mask_variable, value}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.uint_type, value, active, ConstantU32(state, 1), ConstantU32(state, 0)}); + state.builder.AddFunction({OpStore, state.pixel_valid_mask_variable, value}); } -void EmitKillIfPixelValidMaskInactive(EmitterState* state) { - if (state->pixel_valid_mask_variable == 0) { +void EmitKillIfPixelValidMaskInactive(EmitterState& state) { + if (state.pixel_valid_mask_variable == 0) { return; } - const auto mask_value = state->builder.AllocateId(); - const auto active = state->builder.AllocateId(); - state->builder.AddFunction( - {OpLoad, state->uint_type, mask_value, state->pixel_valid_mask_variable}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, active, mask_value, ConstantU32(state, 0)}); + const auto mask_value = state.builder.AllocateId(); + const auto active = state.builder.AllocateId(); + state.builder.AddFunction( + {OpLoad, state.uint_type, mask_value, state.pixel_valid_mask_variable}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, active, mask_value, ConstantU32(state, 0)}); EmitKillIfBoolFalse(state, active); } diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterFlowOps.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterFlowOps.cpp index e3afa8802..de875cd1f 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterFlowOps.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterFlowOps.cpp @@ -2,15 +2,15 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { -void EmitMoveU32(EmitterState* state, const IR::Instruction& inst) { +void EmitMoveU32(EmitterState& state, const IR::Instruction& inst) { const auto value = EmitValueLoad(state, inst.src[0]); EmitStoreU32(state, inst.dst, value); } -void EmitMoveF32Bits(EmitterState* state, const IR::Instruction& inst) { +void EmitMoveF32Bits(EmitterState& state, const IR::Instruction& inst) { const auto value = EmitFloatLoad(state, inst.src[0]); - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, value}); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, value}); EmitStoreU32(state, inst.dst, bits); } @@ -24,7 +24,7 @@ uint32_t MoveRelRegisterLimit(const EmitterState& state, IR::Register base) { return std::min(limit, 256u); } -void EmitMoveRelSourceU32(EmitterState* state, const IR::Instruction& inst) { +void EmitMoveRelSourceU32(EmitterState& state, const IR::Instruction& inst) { if (inst.src[0].kind != IR::OperandKind::Register || inst.src[0].reg.file != IR::RegisterFile::Vector) { EmitMoveU32(state, inst); @@ -34,20 +34,20 @@ void EmitMoveRelSourceU32(EmitterState* state, const IR::Instruction& inst) { const auto base_reg = inst.src[0].reg; const auto m0 = inst.src_count > 1u ? EmitValueLoad(state, inst.src[1]) : ConstantU32(state, 0); auto selected = EmitRegisterLoad(state, base_reg); - const auto limit = MoveRelRegisterLimit(*state, base_reg); + const auto limit = MoveRelRegisterLimit(state, base_reg); for (uint32_t reg = base_reg.index + 1u; reg < limit; reg++) { const auto candidate = EmitRegisterLoad(state, {IR::RegisterFile::Vector, reg}); - const auto match = state->builder.AllocateId(); - const auto next = state->builder.AllocateId(); - state->builder.AddFunction( - {OpIEqual, state->bool_type, match, m0, ConstantU32(state, reg - base_reg.index)}); - state->builder.AddFunction({OpSelect, state->uint_type, next, match, candidate, selected}); + const auto match = state.builder.AllocateId(); + const auto next = state.builder.AllocateId(); + state.builder.AddFunction( + {OpIEqual, state.bool_type, match, m0, ConstantU32(state, reg - base_reg.index)}); + state.builder.AddFunction({OpSelect, state.uint_type, next, match, candidate, selected}); selected = next; } EmitStoreU32(state, inst.dst, selected); } -void EmitMoveRelDestU32(EmitterState* state, const IR::Instruction& inst) { +void EmitMoveRelDestU32(EmitterState& state, const IR::Instruction& inst) { if (inst.dst.kind != IR::OperandKind::Register || inst.dst.reg.file != IR::RegisterFile::Vector) { EmitMoveU32(state, inst); @@ -58,27 +58,27 @@ void EmitMoveRelDestU32(EmitterState* state, const IR::Instruction& inst) { const auto value = EmitValueLoad(state, inst.src[0]); const auto m0 = inst.src_count > 1u ? EmitValueLoad(state, inst.src[1]) : ConstantU32(state, 0); const auto exec_active = EmitExecActiveBool(state); - const auto limit = MoveRelRegisterLimit(*state, base_reg); + const auto limit = MoveRelRegisterLimit(state, base_reg); for (uint32_t reg = base_reg.index; reg < limit; reg++) { - const auto pointer = PointerForRegister(*state, {IR::RegisterFile::Vector, reg}); + const auto pointer = PointerForRegister(state, {IR::RegisterFile::Vector, reg}); if (pointer == 0) { continue; } - const auto old_value = state->builder.AllocateId(); - const auto match = state->builder.AllocateId(); - const auto write = state->builder.AllocateId(); - const auto merged = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, old_value, pointer}); - state->builder.AddFunction( - {OpIEqual, state->bool_type, match, m0, ConstantU32(state, reg - base_reg.index)}); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, write, exec_active, match}); - state->builder.AddFunction({OpSelect, state->uint_type, merged, write, value, old_value}); - state->builder.AddFunction({OpStore, pointer, merged}); + const auto old_value = state.builder.AllocateId(); + const auto match = state.builder.AllocateId(); + const auto write = state.builder.AllocateId(); + const auto merged = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, old_value, pointer}); + state.builder.AddFunction( + {OpIEqual, state.bool_type, match, m0, ConstantU32(state, reg - base_reg.index)}); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, write, exec_active, match}); + state.builder.AddFunction({OpSelect, state.uint_type, merged, write, value, old_value}); + state.builder.AddFunction({OpStore, pointer, merged}); } } -void EmitMoveU64(EmitterState* state, const IR::Instruction& inst) { - if (state->per_invocation_masks && inst.dst.kind == IR::OperandKind::Register && +void EmitMoveU64(EmitterState& state, const IR::Instruction& inst) { + if (state.per_invocation_masks && inst.dst.kind == IR::OperandKind::Register && IsMaskRegisterFile(inst.dst.reg.file)) { EmitPerInvocationMask(state, inst.dst, EmitLaneMaskOperandActiveBool(state, inst.src[0])); return; @@ -89,28 +89,28 @@ void EmitMoveU64(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), high); } -uint32_t EmitWqmLaneU32(EmitterState* state, uint32_t src) { +uint32_t EmitWqmLaneU32(EmitterState& state, uint32_t src) { uint32_t ret = ConstantU32(state, 0); for (uint32_t i = 0; i < 8u; i++) { const auto mask = 0x0fu << (i * 4u); - const auto masked = state->builder.AllocateId(); - const auto non_zero = state->builder.AllocateId(); - const auto expanded = state->builder.AllocateId(); - const auto combined = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, masked, src, ConstantU32(state, mask)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, non_zero, masked, ConstantU32(state, 0)}); - state->builder.AddFunction({OpSelect, state->uint_type, expanded, non_zero, + const auto masked = state.builder.AllocateId(); + const auto non_zero = state.builder.AllocateId(); + const auto expanded = state.builder.AllocateId(); + const auto combined = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, masked, src, ConstantU32(state, mask)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, non_zero, masked, ConstantU32(state, 0)}); + state.builder.AddFunction({OpSelect, state.uint_type, expanded, non_zero, ConstantU32(state, mask), ConstantU32(state, 0)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, combined, ret, expanded}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, combined, ret, expanded}); ret = combined; } return ret; } -void EmitWqmB64(EmitterState* state, const IR::Instruction& inst) { - if (!state->per_invocation_masks && inst.dst.kind == IR::OperandKind::Register && +void EmitWqmB64(EmitterState& state, const IR::Instruction& inst) { + if (!state.per_invocation_masks && inst.dst.kind == IR::OperandKind::Register && inst.dst.reg.file == IR::RegisterFile::Scalar) { const auto low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto high = EmitSequentialValueLoad(state, inst.src[0], 1); @@ -120,44 +120,44 @@ void EmitWqmB64(EmitterState* state, const IR::Instruction& inst) { EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ret_high); return; } - const auto ballot = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformBallot, state->vec4_uint_type, ballot, + const auto ballot = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot, ConstantU32(state, ScopeSubgroup), EmitLaneMaskOperandActiveBool(state, inst.src[0])}); - const auto low = state->builder.AllocateId(); - const auto high = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, low, ballot, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, high, ballot, 1}); + const auto low = state.builder.AllocateId(); + const auto high = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, low, ballot, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, high, ballot, 1}); const auto wqm_low = EmitWqmLaneU32(state, low); const auto wqm_high = EmitWqmLaneU32(state, high); const auto lane = EmitSubgroupLocalInvocationId(state); - const auto high_half = state->builder.AllocateId(); - const auto mask = state->builder.AllocateId(); - const auto bit_index = state->builder.AllocateId(); - const auto bit = state->builder.AllocateId(); - const auto hit = state->builder.AllocateId(); - const auto active = state->builder.AllocateId(); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, high_half, lane, ConstantU32(state, 32)}); - state->builder.AddFunction({OpSelect, state->uint_type, mask, high_half, wqm_high, wqm_low}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, bit_index, lane, ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, bit, ConstantU32(state, 1), bit_index}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, hit, mask, bit}); - state->builder.AddFunction({OpINotEqual, state->bool_type, active, hit, ConstantU32(state, 0)}); - if (state->per_invocation_masks) { + const auto high_half = state.builder.AllocateId(); + const auto mask = state.builder.AllocateId(); + const auto bit_index = state.builder.AllocateId(); + const auto bit = state.builder.AllocateId(); + const auto hit = state.builder.AllocateId(); + const auto active = state.builder.AllocateId(); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, high_half, lane, ConstantU32(state, 32)}); + state.builder.AddFunction({OpSelect, state.uint_type, mask, high_half, wqm_high, wqm_low}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, bit_index, lane, ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), bit_index}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, hit, mask, bit}); + state.builder.AddFunction({OpINotEqual, state.bool_type, active, hit, ConstantU32(state, 0)}); + if (state.per_invocation_masks) { EmitPerInvocationMask(state, inst.dst, active); } else { - const auto result = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->uint_type, result, active, + const auto result = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.uint_type, result, active, ConstantU32(state, 1), ConstantU32(state, 0)}); EmitStoreU32(state, inst.dst, result); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, 1), ConstantU32(state, 0)); } } -void EmitSaveexecPerInvocation(EmitterState* state, const IR::Instruction& inst) { +void EmitSaveexecPerInvocation(EmitterState& state, const IR::Instruction& inst) { const auto old_exec = EmitExecActiveBool(state); const auto src = EmitLaneMaskOperandActiveBool(state, inst.src[0]); EmitPerInvocationMask(state, inst.dst, old_exec); @@ -179,8 +179,8 @@ void EmitSaveexecPerInvocation(EmitterState* state, const IR::Instruction& inst) EmitStoreSccBool(state, result); } -void EmitSaveexecB32(EmitterState* state, const IR::Instruction& inst) { - if (state->per_invocation_masks) { +void EmitSaveexecB32(EmitterState& state, const IR::Instruction& inst) { + if (state.per_invocation_masks) { EmitSaveexecPerInvocation(state, inst); return; } @@ -191,29 +191,29 @@ void EmitSaveexecB32(EmitterState* state, const IR::Instruction& inst) { uint32_t rhs_low = src_low; if (inst.saveexec_mode == IR::SaveexecMode::Andn1) { - rhs_low = state->builder.AllocateId(); - state->builder.AddFunction({OpNot, state->uint_type, rhs_low, src_low}); + rhs_low = state.builder.AllocateId(); + state.builder.AddFunction({OpNot, state.uint_type, rhs_low, src_low}); } - const auto new_low = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, new_low, rhs_low, old_low}); + const auto new_low = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, new_low, rhs_low, old_low}); EmitStoreU32(state, MakeRegisterOperand(IR::RegisterFile::Exec, 0), new_low); - if (state->wave_size == 32u) { + if (state.wave_size == 32u) { EmitStoreU32(state, MakeRegisterOperand(IR::RegisterFile::Exec, 1), ConstantU32(state, 0)); } - const auto cond = state->builder.AllocateId(); - const auto scc = state->builder.AllocateId(); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, cond, new_low, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, scc, cond, ConstantU32(state, 1), ConstantU32(state, 0)}); + const auto cond = state.builder.AllocateId(); + const auto scc = state.builder.AllocateId(); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, cond, new_low, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, scc, cond, ConstantU32(state, 1), ConstantU32(state, 0)}); EmitStoreU32(state, SccOperand(), scc); } -void EmitSaveexecB64(EmitterState* state, const IR::Instruction& inst) { - if (state->per_invocation_masks) { +void EmitSaveexecB64(EmitterState& state, const IR::Instruction& inst) { + if (state.per_invocation_masks) { EmitSaveexecPerInvocation(state, inst); return; } @@ -231,150 +231,150 @@ void EmitSaveexecB64(EmitterState* state, const IR::Instruction& inst) { uint32_t rhs_high = src_high; uint32_t opcode = OpBitwiseAnd; if (inst.saveexec_mode == IR::SaveexecMode::Andn1) { - rhs_low = state->builder.AllocateId(); - rhs_high = state->builder.AllocateId(); - state->builder.AddFunction({OpNot, state->uint_type, rhs_low, src_low}); - state->builder.AddFunction({OpNot, state->uint_type, rhs_high, src_high}); + rhs_low = state.builder.AllocateId(); + rhs_high = state.builder.AllocateId(); + state.builder.AddFunction({OpNot, state.uint_type, rhs_low, src_low}); + state.builder.AddFunction({OpNot, state.uint_type, rhs_high, src_high}); } if (inst.saveexec_mode == IR::SaveexecMode::Orn2) { - lhs_low = state->builder.AllocateId(); - lhs_high = state->builder.AllocateId(); - state->builder.AddFunction({OpNot, state->uint_type, lhs_low, old_low}); - state->builder.AddFunction({OpNot, state->uint_type, lhs_high, old_high}); + lhs_low = state.builder.AllocateId(); + lhs_high = state.builder.AllocateId(); + state.builder.AddFunction({OpNot, state.uint_type, lhs_low, old_low}); + state.builder.AddFunction({OpNot, state.uint_type, lhs_high, old_high}); opcode = OpBitwiseOr; } - const auto new_low = state->builder.AllocateId(); - const auto new_high = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, new_low, lhs_low, rhs_low}); - state->builder.AddFunction({opcode, state->uint_type, new_high, lhs_high, rhs_high}); + const auto new_low = state.builder.AllocateId(); + const auto new_high = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, new_low, lhs_low, rhs_low}); + state.builder.AddFunction({opcode, state.uint_type, new_high, lhs_high, rhs_high}); EmitStoreU32(state, MakeRegisterOperand(IR::RegisterFile::Exec, 0), new_low); EmitStoreU32(state, MakeRegisterOperand(IR::RegisterFile::Exec, 1), new_high); - const auto active_new_high = state->wave_size == 32u ? ConstantU32(state, 0) : new_high; - const auto mask = state->builder.AllocateId(); - const auto cond = state->builder.AllocateId(); - const auto scc = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, mask, new_low, active_new_high}); - state->builder.AddFunction({OpINotEqual, state->bool_type, cond, mask, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, scc, cond, ConstantU32(state, 1), ConstantU32(state, 0)}); + const auto active_new_high = state.wave_size == 32u ? ConstantU32(state, 0) : new_high; + const auto mask = state.builder.AllocateId(); + const auto cond = state.builder.AllocateId(); + const auto scc = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, mask, new_low, active_new_high}); + state.builder.AddFunction({OpINotEqual, state.bool_type, cond, mask, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, scc, cond, ConstantU32(state, 1), ConstantU32(state, 0)}); EmitStoreU32(state, SccOperand(), scc); } -void EmitReadFirstLaneU32(EmitterState* state, const IR::Instruction& inst) { +void EmitReadFirstLaneU32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); const auto active = EmitExecActiveBool(state); - const auto ballot = state->builder.AllocateId(); - const auto first_lane = state->builder.AllocateId(); - const auto first_value = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformBallot, state->vec4_uint_type, ballot, + const auto ballot = state.builder.AllocateId(); + const auto first_lane = state.builder.AllocateId(); + const auto first_value = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot, ConstantU32(state, ScopeSubgroup), active}); - state->builder.AddFunction({OpGroupNonUniformBallotFindLSB, state->uint_type, first_lane, + state.builder.AddFunction({OpGroupNonUniformBallotFindLSB, state.uint_type, first_lane, ConstantU32(state, ScopeSubgroup), ballot}); - state->builder.AddFunction({OpGroupNonUniformShuffle, state->uint_type, first_value, + state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, first_value, ConstantU32(state, ScopeSubgroup), src, first_lane}); EmitStoreU32(state, inst.dst, first_value); } -uint32_t EmitLaneIndex(EmitterState* state, const IR::Operand& operand) { - const auto lane = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, lane, EmitValueLoad(state, operand), +uint32_t EmitLaneIndex(EmitterState& state, const IR::Operand& operand) { + const auto lane = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, lane, EmitValueLoad(state, operand), ConstantU32(state, 63)}); return lane; } -void EmitReadLaneU32(EmitterState* state, const IR::Instruction& inst) { +void EmitReadLaneU32(EmitterState& state, const IR::Instruction& inst) { const auto src = EmitValueLoad(state, inst.src[0]); const auto lane = EmitLaneIndex(state, inst.src[1]); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformShuffle, state->uint_type, value, + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, value, ConstantU32(state, ScopeSubgroup), src, lane}); EmitStoreU32(state, inst.dst, value); } -void EmitWriteLaneU32(EmitterState* state, const IR::Instruction& inst) { +void EmitWriteLaneU32(EmitterState& state, const IR::Instruction& inst) { const auto value = EmitValueLoad(state, inst.src[0]); const auto lane = EmitLaneIndex(state, inst.src[1]); const auto subid = EmitSubgroupLocalInvocationId(state); - const auto hit = state->builder.AllocateId(); + const auto hit = state.builder.AllocateId(); const auto pointer = - inst.dst.kind == IR::OperandKind::Register ? PointerForRegister(*state, inst.dst.reg) : 0; - const auto old = pointer != 0 ? state->builder.AllocateId() : ConstantU32(state, 0); - const auto merged = state->builder.AllocateId(); + inst.dst.kind == IR::OperandKind::Register ? PointerForRegister(state, inst.dst.reg) : 0; + const auto old = pointer != 0 ? state.builder.AllocateId() : ConstantU32(state, 0); + const auto merged = state.builder.AllocateId(); if (pointer != 0) { - state->builder.AddFunction({OpLoad, state->uint_type, old, pointer}); + state.builder.AddFunction({OpLoad, state.uint_type, old, pointer}); } - state->builder.AddFunction({OpIEqual, state->bool_type, hit, subid, lane}); - state->builder.AddFunction({OpSelect, state->uint_type, merged, hit, value, old}); + state.builder.AddFunction({OpIEqual, state.bool_type, hit, subid, lane}); + state.builder.AddFunction({OpSelect, state.uint_type, merged, hit, value, old}); if (pointer != 0) { // RDNA2 V_WRITELANE_B32 ignores EXEC, unlike ordinary VGPR destination writes. - state->builder.AddFunction({OpStore, pointer, merged}); + state.builder.AddFunction({OpStore, pointer, merged}); } } -void EmitPermlaneB32(EmitterState* state, const IR::Instruction& inst, bool x16) { +void EmitPermlaneB32(EmitterState& state, const IR::Instruction& inst, bool x16) { const auto subid = EmitSubgroupLocalInvocationId(state); - const auto row = state->builder.AllocateId(); - const auto lane = state->builder.AllocateId(); - const auto lane8 = state->builder.AllocateId(); - const auto shift = state->builder.AllocateId(); - const auto upper = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); - const auto index0 = state->builder.AllocateId(); - const auto index1 = state->builder.AllocateId(); - const auto target = state->builder.AllocateId(); - const auto shuffled = state->builder.AllocateId(); + const auto row = state.builder.AllocateId(); + const auto lane = state.builder.AllocateId(); + const auto lane8 = state.builder.AllocateId(); + const auto shift = state.builder.AllocateId(); + const auto upper = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); + const auto index0 = state.builder.AllocateId(); + const auto index1 = state.builder.AllocateId(); + const auto target = state.builder.AllocateId(); + const auto shuffled = state.builder.AllocateId(); const auto value = EmitValueLoad(state, inst.src[0]); const auto src1 = EmitValueLoad(state, inst.src[1]); const auto src2 = EmitValueLoad(state, inst.src[2]); uint32_t row_value = row; - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, row, subid, ConstantU32(state, 0xfffffff0u)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, row, subid, ConstantU32(state, 0xfffffff0u)}); if (x16) { - row_value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseXor, state->uint_type, row_value, row, ConstantU32(state, 16)}); + row_value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseXor, state.uint_type, row_value, row, ConstantU32(state, 16)}); } - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, subid, ConstantU32(state, 15)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane8, lane, ConstantU32(state, 7)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shift, lane8, ConstantU32(state, 2)}); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, upper, lane, ConstantU32(state, 8)}); - state->builder.AddFunction({OpSelect, state->uint_type, selected, upper, src2, src1}); - state->builder.AddFunction({OpShiftRightLogical, state->uint_type, index0, selected, shift}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, index1, index0, ConstantU32(state, 15)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, target, row_value, index1}); - state->builder.AddFunction({OpGroupNonUniformShuffle, state->uint_type, shuffled, + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane8, lane, ConstantU32(state, 7)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shift, lane8, ConstantU32(state, 2)}); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, upper, lane, ConstantU32(state, 8)}); + state.builder.AddFunction({OpSelect, state.uint_type, selected, upper, src2, src1}); + state.builder.AddFunction({OpShiftRightLogical, state.uint_type, index0, selected, shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, index1, index0, ConstantU32(state, 15)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, row_value, index1}); + state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, shuffled, ConstantU32(state, ScopeSubgroup), value, target}); uint32_t ret = shuffled; if (!inst.dst.op_sel) { const auto source_active = EmitLaneIndexActiveBool(state, target); - ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, source_active, shuffled, ConstantU32(state, 0)}); + ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, source_active, shuffled, ConstantU32(state, 0)}); } EmitStoreU32(state, inst.dst, ret); } -void EmitControlNop(EmitterState* state, const IR::Instruction& inst) { +void EmitControlNop(EmitterState& state, const IR::Instruction& inst) { (void)state; (void)inst; } -void EmitWaitcnt(EmitterState* state, const IR::Instruction& inst) { +void EmitWaitcnt(EmitterState& state, const IR::Instruction& inst) { (void)state; (void)inst; } -void EmitBarrier(EmitterState* state, const IR::Instruction& inst) { +void EmitBarrier(EmitterState& state, const IR::Instruction& inst) { (void)inst; const auto semantics = MemorySemanticsAcquireRelease | MemorySemanticsWorkgroupMemory; - state->builder.AddFunction({OpControlBarrier, ConstantU32(state, ScopeWorkgroup), + state.builder.AddFunction({OpControlBarrier, ConstantU32(state, ScopeWorkgroup), ConstantU32(state, ScopeWorkgroup), ConstantU32(state, semantics)}); } diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterImageHelpers.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterImageHelpers.cpp index e361e3f80..000585b89 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterImageHelpers.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterImageHelpers.cpp @@ -33,25 +33,25 @@ ImageSampleLayout MakeImageSampleLayout(const IR::Instruction& inst, ImageViewKi return layout; } -uint32_t EmitImageCoordF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageCoordF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout, ImageViewKind view) { const auto x = EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord); const auto y = inst.memory.image_address_components > layout.coord + 1u ? EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord + 1u) : EmitZeroF32(state); - const auto coord = state->builder.AllocateId(); + const auto coord = state.builder.AllocateId(); if (ImageViewCoordinateComponents(view) == 3u) { const auto z = inst.memory.image_address_components > layout.coord + 2u ? EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord + 2u) : EmitZeroF32(state); - state->builder.AddFunction({OpCompositeConstruct, state->vec3_float_type, coord, x, y, z}); + state.builder.AddFunction({OpCompositeConstruct, state.vec3_float_type, coord, x, y, z}); } else { - state->builder.AddFunction({OpCompositeConstruct, state->vec2_float_type, coord, x, y}); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, coord, x, y}); } return coord; } -uint32_t EmitImageLodF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageLodF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout) { if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagLevelZero) || layout.lod == NoImageComponent || inst.memory.image_address_components <= layout.lod) { @@ -60,7 +60,7 @@ uint32_t EmitImageLodF32(EmitterState* state, const IR::Instruction& inst, return EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.lod); } -uint32_t EmitImageDrefF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageDrefF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout) { if (layout.dref == NoImageComponent || inst.memory.image_address_components <= layout.dref) { return EmitZeroF32(state); @@ -68,7 +68,7 @@ uint32_t EmitImageDrefF32(EmitterState* state, const IR::Instruction& inst, return EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.dref); } -uint32_t EmitImageBiasF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageBiasF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout) { if (layout.bias == NoImageComponent || inst.memory.image_address_components <= layout.bias) { return EmitZeroF32(state); @@ -76,7 +76,7 @@ uint32_t EmitImageBiasF32(EmitterState* state, const IR::Instruction& inst, return EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.bias); } -uint32_t EmitImageGradientF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageGradientF32(EmitterState& state, const IR::Instruction& inst, uint32_t first_component) { const auto x = inst.memory.image_address_components > first_component ? EmitImageAddressFloatLoad(state, inst, inst.src[0], first_component) @@ -84,37 +84,37 @@ uint32_t EmitImageGradientF32(EmitterState* state, const IR::Instruction& inst, const auto y = inst.memory.image_address_components > first_component + 1u ? EmitImageAddressFloatLoad(state, inst, inst.src[0], first_component + 1u) : EmitZeroF32(state); - const auto grad = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec2_float_type, grad, x, y}); + const auto grad = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, grad, x, y}); return grad; } -uint32_t EmitImagePackedOffset2I32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImagePackedOffset2I32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout) { if (layout.offset == NoImageComponent || inst.memory.image_address_components <= layout.offset) { const auto zero = ConstantI32(state, 0); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec2_int_type, ret, zero, zero}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_int_type, ret, zero, zero}); return ret; } const auto packed_bits = EmitImageAddressValueLoad(state, inst, inst.src[0], layout.offset); - const auto packed_i32 = state->builder.AllocateId(); - const auto offset_x = state->builder.AllocateId(); - const auto offset_y = state->builder.AllocateId(); - const auto offset = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, packed_i32, packed_bits}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, offset_x, packed_i32, + const auto packed_i32 = state.builder.AllocateId(); + const auto offset_x = state.builder.AllocateId(); + const auto offset_y = state.builder.AllocateId(); + const auto offset = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, packed_i32, packed_bits}); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, offset_x, packed_i32, ConstantI32(state, 0), ConstantI32(state, 6)}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, offset_y, packed_i32, + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, offset_y, packed_i32, ConstantI32(state, 8), ConstantI32(state, 6)}); - state->builder.AddFunction( - {OpCompositeConstruct, state->vec2_int_type, offset, offset_x, offset_y}); + state.builder.AddFunction( + {OpCompositeConstruct, state.vec2_int_type, offset, offset_x, offset_y}); return offset; } -uint32_t EmitImageOffsetCoordF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageOffsetCoordF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout, uint32_t sampled_image, uint32_t coord, ImageViewKind view) { if (!HasImageSampleFlag(inst, Decoder::ImageSampleFlagOffset)) { @@ -122,92 +122,92 @@ uint32_t EmitImageOffsetCoordF32(EmitterState* state, const IR::Instruction& ins } const auto offset_i32 = EmitImagePackedOffset2I32(state, inst, layout); - const auto offset_f32 = state->builder.AllocateId(); - const auto image = state->builder.AllocateId(); - const auto size_u32 = state->builder.AllocateId(); + const auto offset_f32 = state.builder.AllocateId(); + const auto image = state.builder.AllocateId(); + const auto size_u32 = state.builder.AllocateId(); const auto size_xy_u32 = - ImageViewCoordinateComponents(view) == 3u ? state->builder.AllocateId() : size_u32; - const auto size_f32 = state->builder.AllocateId(); - const auto normalized = state->builder.AllocateId(); - const auto adjusted = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertSToF, state->vec2_float_type, offset_f32, offset_i32}); - state->builder.AddFunction( - {OpImage, ImageViewImageType(*state, view, inst.memory.kind == IR::ResourceKind::ImageUint), + ImageViewCoordinateComponents(view) == 3u ? state.builder.AllocateId() : size_u32; + const auto size_f32 = state.builder.AllocateId(); + const auto normalized = state.builder.AllocateId(); + const auto adjusted = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertSToF, state.vec2_float_type, offset_f32, offset_i32}); + state.builder.AddFunction( + {OpImage, ImageViewImageType(state, view, inst.memory.kind == IR::ResourceKind::ImageUint), image, sampled_image}); - state->builder.AddFunction({OpImageQuerySizeLod, ImageViewSizeType(*state, view), size_u32, + state.builder.AddFunction({OpImageQuerySizeLod, ImageViewSizeType(state, view), size_u32, image, ConstantU32(state, 0)}); if (ImageViewCoordinateComponents(view) == 3u) { - const auto width = state->builder.AllocateId(); - const auto height = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, width, size_u32, 0}); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, height, size_u32, 1}); - state->builder.AddFunction( - {OpCompositeConstruct, state->vec2_uint_type, size_xy_u32, width, height}); + const auto width = state.builder.AllocateId(); + const auto height = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, width, size_u32, 0}); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, height, size_u32, 1}); + state.builder.AddFunction( + {OpCompositeConstruct, state.vec2_uint_type, size_xy_u32, width, height}); } - state->builder.AddFunction({OpConvertUToF, state->vec2_float_type, size_f32, size_xy_u32}); - state->builder.AddFunction({OpFDiv, state->vec2_float_type, normalized, offset_f32, size_f32}); + state.builder.AddFunction({OpConvertUToF, state.vec2_float_type, size_f32, size_xy_u32}); + state.builder.AddFunction({OpFDiv, state.vec2_float_type, normalized, offset_f32, size_f32}); if (ImageViewCoordinateComponents(view) == 2u) { - state->builder.AddFunction({OpFAdd, state->vec2_float_type, adjusted, coord, normalized}); + state.builder.AddFunction({OpFAdd, state.vec2_float_type, adjusted, coord, normalized}); return adjusted; } - const auto x = state->builder.AllocateId(); - const auto y = state->builder.AllocateId(); - const auto z = state->builder.AllocateId(); - const auto normalized_x = state->builder.AllocateId(); - const auto normalized_y = state->builder.AllocateId(); - const auto adjusted_x = state->builder.AllocateId(); - const auto adjusted_y = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->float_type, x, coord, 0}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, y, coord, 1}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, z, coord, 2}); - state->builder.AddFunction( - {OpCompositeExtract, state->float_type, normalized_x, normalized, 0}); - state->builder.AddFunction( - {OpCompositeExtract, state->float_type, normalized_y, normalized, 1}); - state->builder.AddFunction({OpFAdd, state->float_type, adjusted_x, x, normalized_x}); - state->builder.AddFunction({OpFAdd, state->float_type, adjusted_y, y, normalized_y}); - state->builder.AddFunction( - {OpCompositeConstruct, state->vec3_float_type, adjusted, adjusted_x, adjusted_y, z}); + const auto x = state.builder.AllocateId(); + const auto y = state.builder.AllocateId(); + const auto z = state.builder.AllocateId(); + const auto normalized_x = state.builder.AllocateId(); + const auto normalized_y = state.builder.AllocateId(); + const auto adjusted_x = state.builder.AllocateId(); + const auto adjusted_y = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.float_type, x, coord, 0}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, y, coord, 1}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, z, coord, 2}); + state.builder.AddFunction( + {OpCompositeExtract, state.float_type, normalized_x, normalized, 0}); + state.builder.AddFunction( + {OpCompositeExtract, state.float_type, normalized_y, normalized, 1}); + state.builder.AddFunction({OpFAdd, state.float_type, adjusted_x, x, normalized_x}); + state.builder.AddFunction({OpFAdd, state.float_type, adjusted_y, y, normalized_y}); + state.builder.AddFunction( + {OpCompositeConstruct, state.vec3_float_type, adjusted, adjusted_x, adjusted_y, z}); return adjusted; } -uint32_t EmitImageCoordU32(EmitterState* state, const IR::Instruction& inst, ImageViewKind view) { +uint32_t EmitImageCoordU32(EmitterState& state, const IR::Instruction& inst, ImageViewKind view) { const auto x = EmitImageAddressValueLoad(state, inst, inst.src[1], 0); const auto y = inst.memory.image_address_components > 1u ? EmitImageAddressValueLoad(state, inst, inst.src[1], 1) : ConstantU32(state, 0); - const auto coord = state->builder.AllocateId(); + const auto coord = state.builder.AllocateId(); if (ImageViewCoordinateComponents(view) == 3u) { const auto z = inst.memory.image_address_components > 2u ? EmitImageAddressValueLoad(state, inst, inst.src[1], 2) : ConstantU32(state, 0); - state->builder.AddFunction({OpCompositeConstruct, state->vec3_uint_type, coord, x, y, z}); + state.builder.AddFunction({OpCompositeConstruct, state.vec3_uint_type, coord, x, y, z}); } else { - state->builder.AddFunction({OpCompositeConstruct, state->vec2_uint_type, coord, x, y}); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_uint_type, coord, x, y}); } return coord; } -uint32_t EmitImageLoadCoordU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageLoadCoordU32(EmitterState& state, const IR::Instruction& inst, ImageViewKind view) { const auto x = EmitImageAddressValueLoad(state, inst, inst.src[0], 0); const auto y = inst.memory.image_address_components > 1u ? EmitImageAddressValueLoad(state, inst, inst.src[0], 1) : ConstantU32(state, 0); - const auto coord = state->builder.AllocateId(); + const auto coord = state.builder.AllocateId(); if (ImageViewCoordinateComponents(view) == 3u) { const auto z = inst.memory.image_address_components > 2u ? EmitImageAddressValueLoad(state, inst, inst.src[0], 2) : ConstantU32(state, 0); - state->builder.AddFunction({OpCompositeConstruct, state->vec3_uint_type, coord, x, y, z}); + state.builder.AddFunction({OpCompositeConstruct, state.vec3_uint_type, coord, x, y, z}); } else { - state->builder.AddFunction({OpCompositeConstruct, state->vec2_uint_type, coord, x, y}); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_uint_type, coord, x, y}); } return coord; } -uint32_t EmitImageMipLodU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageMipLodU32(EmitterState& state, const IR::Instruction& inst, const IR::Operand& address, ImageViewKind view) { if (!inst.memory.image_has_mip || inst.memory.image_address_components == 0u) { return ConstantU32(state, 0); @@ -219,20 +219,20 @@ uint32_t EmitImageMipLodU32(EmitterState* state, const IR::Instruction& inst, return EmitImageAddressValueLoad(state, inst, address, lod_component); } -uint32_t EmitImageQueryCoordF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageQueryCoordF32(EmitterState& state, const IR::Instruction& inst, ImageViewKind view) { const auto x = EmitImageAddressFloatLoad(state, inst, inst.src[0], 0); const auto y = inst.memory.image_address_components > 1u ? EmitImageAddressFloatLoad(state, inst, inst.src[0], 1) : EmitZeroF32(state); - const auto coord = state->builder.AllocateId(); + const auto coord = state.builder.AllocateId(); if (ImageViewCoordinateComponents(view) == 3u) { const auto z = inst.memory.image_address_components > 2u ? EmitImageAddressFloatLoad(state, inst, inst.src[0], 2) : EmitZeroF32(state); - state->builder.AddFunction({OpCompositeConstruct, state->vec3_float_type, coord, x, y, z}); + state.builder.AddFunction({OpCompositeConstruct, state.vec3_float_type, coord, x, y, z}); } else { - state->builder.AddFunction({OpCompositeConstruct, state->vec2_float_type, coord, x, y}); + state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, coord, x, y}); } return coord; } @@ -245,7 +245,7 @@ uint32_t DmaskComponentIndex(uint32_t dmask, uint32_t component) { return index; } -uint32_t EmitImageStoreComponentF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageStoreComponentF32(EmitterState& state, const IR::Instruction& inst, uint32_t component) { const auto dmask = inst.memory.dmask != 0 ? inst.memory.dmask : 1u; if (((dmask >> component) & 1u) == 0) { @@ -265,14 +265,14 @@ uint32_t InverseStorageSwizzleComponent(uint32_t swizzle, uint32_t component) { } uint32_t StorageImageSwizzle(const EmitterState& state, const IR::Instruction& inst) { - if (state.program == nullptr || inst.memory.resource >= state.program->info.images.size()) { + if (inst.memory.resource >= state.program.info.images.size()) { EXIT("storage image instruction has no specialized swizzle\n"); } - return state.program->info.images[inst.memory.resource].storage_swizzle; + return state.program.info.images[inst.memory.resource].storage_swizzle; } -uint32_t EmitImageStoreTexelF32(EmitterState* state, const IR::Instruction& inst) { - const auto swizzle = StorageImageSwizzle(*state, inst); +uint32_t EmitImageStoreTexelF32(EmitterState& state, const IR::Instruction& inst) { + const auto swizzle = StorageImageSwizzle(state, inst); const auto component_value = [&](uint32_t component) { const auto source = InverseStorageSwizzleComponent(swizzle, component); return source < 4u ? EmitImageStoreComponentF32(state, inst, source) : EmitZeroF32(state); @@ -281,12 +281,12 @@ uint32_t EmitImageStoreTexelF32(EmitterState* state, const IR::Instruction& inst const auto y = component_value(1); const auto z = component_value(2); const auto w = component_value(3); - const auto texel = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec4_float_type, texel, x, y, z, w}); + const auto texel = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec4_float_type, texel, x, y, z, w}); return texel; } -uint32_t EmitImageStoreComponentU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageStoreComponentU32(EmitterState& state, const IR::Instruction& inst, uint32_t component) { const auto dmask = inst.memory.dmask != 0 ? inst.memory.dmask : 1u; if (((dmask >> component) & 1u) == 0) { @@ -295,8 +295,8 @@ uint32_t EmitImageStoreComponentU32(EmitterState* state, const IR::Instruction& return EmitSequentialValueLoad(state, inst.src[0], DmaskComponentIndex(dmask, component)); } -uint32_t EmitImageStoreTexelU32(EmitterState* state, const IR::Instruction& inst) { - const auto swizzle = StorageImageSwizzle(*state, inst); +uint32_t EmitImageStoreTexelU32(EmitterState& state, const IR::Instruction& inst) { + const auto swizzle = StorageImageSwizzle(state, inst); const auto component_value = [&](uint32_t component) { const auto source = InverseStorageSwizzleComponent(swizzle, component); return source < 4u ? EmitImageStoreComponentU32(state, inst, source) @@ -306,8 +306,8 @@ uint32_t EmitImageStoreTexelU32(EmitterState* state, const IR::Instruction& inst const auto y = component_value(1); const auto z = component_value(2); const auto w = component_value(3); - const auto texel = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeConstruct, state->vec4_uint_type, texel, x, y, z, w}); + const auto texel = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeConstruct, state.vec4_uint_type, texel, x, y, z, w}); return texel; } diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterImageOps.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterImageOps.cpp index c776dff6d..9e0aa408c 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterImageOps.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterImageOps.cpp @@ -4,54 +4,54 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { namespace { -uint32_t ConstantVec2I32(EmitterState* state, int32_t x, int32_t y) { - const auto value = state->builder.AllocateId(); - state->builder.AddType({OpConstantComposite, state->vec2_int_type, value, ConstantI32(state, x), - ConstantI32(state, y)}); +uint32_t ConstantVec2I32(EmitterState& state, int32_t x, int32_t y) { + const auto value = state.builder.AllocateId(); + state.builder.AddType({OpConstantComposite, state.vec2_int_type, value, ConstantI32(state, x), + ConstantI32(state, y)}); return value; } -uint32_t ConstantImageGatherHorizontalOffsets(EmitterState* state) { +uint32_t ConstantImageGatherHorizontalOffsets(EmitterState& state) { const auto offset0 = ConstantVec2I32(state, -1, 0); const auto offset1 = ConstantVec2I32(state, 0, 0); const auto offset2 = ConstantVec2I32(state, 1, 0); const auto offset3 = ConstantVec2I32(state, 2, 0); - const auto type = state->builder.AllocateId(); - state->builder.AddType({OpTypeArray, type, state->vec2_int_type, ConstantU32(state, 4)}); - const auto value = state->builder.AllocateId(); - state->builder.AddType({OpConstantComposite, type, value, offset0, offset1, offset2, offset3}); + const auto type = state.builder.AllocateId(); + state.builder.AddType({OpTypeArray, type, state.vec2_int_type, ConstantU32(state, 4)}); + const auto value = state.builder.AllocateId(); + state.builder.AddType({OpConstantComposite, type, value, offset0, offset1, offset2, offset3}); return value; } -uint32_t LoadStorageImageDescriptorAtIndex(EmitterState* state, uint32_t resource, +uint32_t LoadStorageImageDescriptorAtIndex(EmitterState& state, uint32_t resource, uint32_t array_index, bool uint_image, ImageViewKind view) { uint32_t pointer_type = - uint_image ? state->ptr_uniform_storage_image_uint : state->ptr_uniform_storage_image; + uint_image ? state.ptr_uniform_storage_image_uint : state.ptr_uniform_storage_image; uint32_t variable = - uint_image ? state->storage_image_uint_variable : state->storage_image_variable; - uint32_t image_type = uint_image ? state->storage_image_uint_type : state->storage_image_type; + uint_image ? state.storage_image_uint_variable : state.storage_image_variable; + uint32_t image_type = uint_image ? state.storage_image_uint_type : state.storage_image_type; IR::DescriptorBindingKind kind = uint_image ? IR::DescriptorBindingKind::StorageUint2D : IR::DescriptorBindingKind::Storage2D; switch (view) { case ImageViewKind::Dim2D: break; case ImageViewKind::Dim2DArray: - pointer_type = uint_image ? state->ptr_uniform_storage_image_uint_2d_array - : state->ptr_uniform_storage_image_2d_array; - variable = uint_image ? state->storage_image_uint_2d_array_variable - : state->storage_image_2d_array_variable; - image_type = uint_image ? state->storage_image_uint_2d_array_type - : state->storage_image_2d_array_type; + pointer_type = uint_image ? state.ptr_uniform_storage_image_uint_2d_array + : state.ptr_uniform_storage_image_2d_array; + variable = uint_image ? state.storage_image_uint_2d_array_variable + : state.storage_image_2d_array_variable; + image_type = uint_image ? state.storage_image_uint_2d_array_type + : state.storage_image_2d_array_type; kind = uint_image ? IR::DescriptorBindingKind::StorageUint2DArray : IR::DescriptorBindingKind::Storage2DArray; break; case ImageViewKind::Dim3D: - pointer_type = uint_image ? state->ptr_uniform_storage_image_uint_3d - : state->ptr_uniform_storage_image_3d; - variable = uint_image ? state->storage_image_uint_3d_variable - : state->storage_image_3d_variable; + pointer_type = uint_image ? state.ptr_uniform_storage_image_uint_3d + : state.ptr_uniform_storage_image_3d; + variable = + uint_image ? state.storage_image_uint_3d_variable : state.storage_image_3d_variable; image_type = - uint_image ? state->storage_image_uint_3d_type : state->storage_image_3d_type; + uint_image ? state.storage_image_uint_3d_type : state.storage_image_3d_type; kind = uint_image ? IR::DescriptorBindingKind::StorageUint3D : IR::DescriptorBindingKind::Storage3D; break; @@ -59,50 +59,50 @@ uint32_t LoadStorageImageDescriptorAtIndex(EmitterState* state, uint32_t resourc const auto pointer = DescriptorElementPointer(state, pointer_type, variable, array_index, kind, resource, "storage image descriptor array was not emitted"); - const auto image = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, image_type, image, pointer}); + const auto image = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, image_type, image, pointer}); return image; } } // namespace -uint32_t EmitImageGetResinfoComponent(EmitterState* state, uint32_t image, uint32_t size, +uint32_t EmitImageGetResinfoComponent(EmitterState& state, uint32_t image, uint32_t size, uint32_t component_index, ImageViewKind view) { switch (component_index) { case 0: { - const auto width = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, width, size, 0}); + const auto width = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, width, size, 0}); return width; } case 1: { - const auto height = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, height, size, 1}); + const auto height = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, height, size, 1}); return height; } case 2: if (ImageViewCoordinateComponents(view) == 3u) { - const auto depth = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, depth, size, 2}); + const auto depth = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, depth, size, 2}); return depth; } return ConstantU32(state, 1); case 3: { - const auto levels = state->builder.AllocateId(); - state->builder.AddFunction({OpImageQueryLevels, state->uint_type, levels, image}); + const auto levels = state.builder.AllocateId(); + state.builder.AddFunction({OpImageQueryLevels, state.uint_type, levels, image}); return levels; } default: return ConstantU32(state, 0); } } -void EmitImageGetResinfo(EmitterState* state, const IR::Instruction& inst) { - const auto view = SampledImageViewKind(*state, inst.memory, inst.pc); +void EmitImageGetResinfo(EmitterState& state, const IR::Instruction& inst) { + const auto view = SampledImageViewKind(state, inst.memory, inst.pc); const auto image = LoadSampledImageDescriptor(state, inst.memory, inst.pc, view); const auto mip_level = EmitValueLoad(state, inst.src[0]); - const auto size = state->builder.AllocateId(); - state->builder.AddFunction( - {OpImageQuerySizeLod, ImageViewSizeType(*state, view), size, image, mip_level}); + const auto size = state.builder.AllocateId(); + state.builder.AddFunction( + {OpImageQuerySizeLod, ImageViewSizeType(state, view), size, image, mip_level}); const auto dmask = inst.memory.dmask != 0 ? inst.memory.dmask : 1u; uint32_t dst_index = 0; @@ -116,13 +116,13 @@ void EmitImageGetResinfo(EmitterState* state, const IR::Instruction& inst) { } } -void EmitImageGetLod(EmitterState* state, const IR::Instruction& inst) { - const auto view = SampledImageViewKind(*state, inst.memory, inst.pc); +void EmitImageGetLod(EmitterState& state, const IR::Instruction& inst) { + const auto view = SampledImageViewKind(state, inst.memory, inst.pc); const auto sampled_image = MakeSampledImage(state, inst.memory, inst.pc, view); - const auto lod = state->builder.AllocateId(); - state->builder.AddFunction({OpImageQueryLod, state->vec2_float_type, lod, sampled_image, - EmitImageQueryCoordF32(state, inst, view)}); + const auto lod = state.builder.AllocateId(); + state.builder.AddFunction({OpImageQueryLod, state.vec2_float_type, lod, sampled_image, + EmitImageQueryCoordF32(state, inst, view)}); const auto dmask = inst.memory.dmask != 0 ? inst.memory.dmask : 1u; uint32_t dst_index = 0; @@ -130,25 +130,25 @@ void EmitImageGetLod(EmitterState* state, const IR::Instruction& inst) { if (((dmask >> component_index) & 1u) == 0) { continue; } - const auto component = state->builder.AllocateId(); - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction( - {OpCompositeExtract, state->float_type, component, lod, component_index}); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, component}); + const auto component = state.builder.AllocateId(); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction( + {OpCompositeExtract, state.float_type, component, lod, component_index}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, component}); EmitStoreU32(state, OffsetRegisterOperand(inst.dst, dst_index++), bits); } } -void EmitImageLoad(EmitterState* state, const IR::Instruction& inst) { - const auto view = SampledImageViewKind(*state, inst.memory, inst.pc); +void EmitImageLoad(EmitterState& state, const IR::Instruction& inst) { + const auto view = SampledImageViewKind(state, inst.memory, inst.pc); const auto image = LoadSampledImageDescriptor(state, inst.memory, inst.pc, view); const bool integer = inst.memory.kind == IR::ResourceKind::ImageUint; - const auto color = state->builder.AllocateId(); - state->builder.AddFunction( - {OpImageFetch, integer ? state->vec4_uint_type : state->vec4_float_type, color, image, - EmitImageLoadCoordU32(state, inst, view), ImageOperandsLodMask, - EmitImageMipLodU32(state, inst, inst.src[0], view)}); + const auto color = state.builder.AllocateId(); + state.builder.AddFunction({OpImageFetch, integer ? state.vec4_uint_type : state.vec4_float_type, + color, image, EmitImageLoadCoordU32(state, inst, view), + ImageOperandsLodMask, + EmitImageMipLodU32(state, inst, inst.src[0], view)}); const auto dmask = inst.memory.dmask != 0 ? inst.memory.dmask : 1u; uint32_t dst_index = 0; @@ -156,23 +156,22 @@ void EmitImageLoad(EmitterState* state, const IR::Instruction& inst) { if (((dmask >> component_index) & 1u) == 0) { continue; } - const auto component = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, - integer ? state->uint_type : state->float_type, component, - color, component_index}); - const auto bits = integer ? component : state->builder.AllocateId(); + const auto component = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, integer ? state.uint_type : state.float_type, + component, color, component_index}); + const auto bits = integer ? component : state.builder.AllocateId(); if (!integer) { - state->builder.AddFunction({OpBitcast, state->uint_type, bits, component}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, component}); } EmitStoreU32(state, OffsetRegisterOperand(inst.dst, dst_index++), bits); } } -void EmitImageStore(EmitterState* state, const IR::Instruction& inst) { +void EmitImageStore(EmitterState& state, const IR::Instruction& inst) { const auto uint_image = inst.memory.kind == IR::ResourceKind::StorageImageUint; - const auto view = StorageImageViewKind(*state, inst.memory, uint_image, inst.pc); + const auto view = StorageImageViewKind(state, inst.memory, uint_image, inst.pc); const auto binding = ResourceForDescriptor( - *state, + state, uint_image ? (view == ImageViewKind::Dim2DArray ? IR::DescriptorBindingKind::StorageUint2DArray : view == ImageViewKind::Dim3D ? IR::DescriptorBindingKind::StorageUint3D @@ -184,16 +183,16 @@ void EmitImageStore(EmitterState* state, const IR::Instruction& inst) { const auto image = LoadStorageImageDescriptorAtIndex(state, inst.memory.resource, binding.array_index, uint_image, view); - state->builder.AddFunction( + state.builder.AddFunction( {OpImageWrite, image, EmitImageCoordU32(state, inst, view), uint_image ? EmitImageStoreTexelU32(state, inst) : EmitImageStoreTexelF32(state, inst)}); } -void EmitImageSampleResult(EmitterState* state, const IR::Instruction& inst, uint32_t sample, +void EmitImageSampleResult(EmitterState& state, const IR::Instruction& inst, uint32_t sample, bool dref, bool integer) { if (dref) { - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, sample}); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, sample}); for (uint32_t i = 0; i < inst.memory.data_dwords; i++) { EmitStoreU32(state, OffsetRegisterOperand(inst.dst, i), bits); } @@ -206,13 +205,12 @@ void EmitImageSampleResult(EmitterState* state, const IR::Instruction& inst, uin if (((dmask >> component_index) & 1u) == 0) { continue; } - const auto component = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, - integer ? state->uint_type : state->float_type, component, - sample, component_index}); - const auto bits = integer ? component : state->builder.AllocateId(); + const auto component = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, integer ? state.uint_type : state.float_type, + component, sample, component_index}); + const auto bits = integer ? component : state.builder.AllocateId(); if (!integer) { - state->builder.AddFunction({OpBitcast, state->uint_type, bits, component}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, component}); } EmitStoreU32(state, OffsetRegisterOperand(inst.dst, dst_index++), bits); } @@ -231,12 +229,9 @@ bool ImageSampleNeedsExplicitLod(const EmitterState& state, const IR::Instructio return state.stage != ShaderType::Pixel; } -void AddImageSampleOperands(EmitterState* state, const IR::Instruction& inst, +void AddImageSampleOperands(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout, bool explicit_lod, - std::vector* words) { - if (words == nullptr) { - return; - } + std::vector& words) { uint32_t mask = 0; std::vector operands; @@ -255,8 +250,8 @@ void AddImageSampleOperands(EmitterState* state, const IR::Instruction& inst, operands.push_back(EmitImageBiasF32(state, inst, layout)); } if (mask != 0) { - words->push_back(mask); - words->insert(words->end(), operands.begin(), operands.end()); + words.push_back(mask); + words.insert(words.end(), operands.begin(), operands.end()); } } @@ -270,20 +265,20 @@ uint32_t ImageSampleOpcode(const EmitterState& state, const IR::Instruction& ins return dref ? OpImageSampleDrefImplicitLod : OpImageSampleImplicitLod; } -void EmitImageSample(EmitterState* state, const IR::Instruction& inst) { - const auto view = SampledImageViewKind(*state, inst.memory, inst.pc); +void EmitImageSample(EmitterState& state, const IR::Instruction& inst) { + const auto view = SampledImageViewKind(state, inst.memory, inst.pc); const auto sampled_image = MakeSampledImage(state, inst.memory, inst.pc, view); const auto layout = MakeImageSampleLayout(inst, view); const auto base_coord = EmitImageCoordF32(state, inst, layout, view); - const auto sample = state->builder.AllocateId(); + const auto sample = state.builder.AllocateId(); const auto dref = HasImageSampleFlag(inst, Decoder::ImageSampleFlagCompare); const bool integer = inst.memory.kind == IR::ResourceKind::ImageUint; - const auto result_type = dref ? state->float_type - : integer ? state->vec4_uint_type - : state->vec4_float_type; - const auto explicit_lod = ImageSampleNeedsExplicitLod(*state, inst); - const auto opcode = ImageSampleOpcode(*state, inst); + const auto result_type = dref ? state.float_type + : integer ? state.vec4_uint_type + : state.vec4_float_type; + const auto explicit_lod = ImageSampleNeedsExplicitLod(state, inst); + const auto opcode = ImageSampleOpcode(state, inst); const auto coord = EmitImageOffsetCoordF32(state, inst, layout, sampled_image, base_coord, view); @@ -291,8 +286,8 @@ void EmitImageSample(EmitterState* state, const IR::Instruction& inst) { if (dref) { words.push_back(EmitImageDrefF32(state, inst, layout)); } - AddImageSampleOperands(state, inst, layout, explicit_lod, &words); - state->builder.AddFunction(words); + AddImageSampleOperands(state, inst, layout, explicit_lod, words); + state.builder.AddFunction(words); EmitImageSampleResult(state, inst, sample, dref, integer); } @@ -305,35 +300,32 @@ uint32_t ImageGatherComponent(uint32_t dmask) { } } -void AddImageGatherOperands(EmitterState* state, const IR::Instruction& inst, - const ImageSampleLayout& layout, std::vector* words) { - if (words == nullptr) { - return; - } +void AddImageGatherOperands(EmitterState& state, const IR::Instruction& inst, + const ImageSampleLayout& layout, std::vector& words) { if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagGatherHorizontal)) { - words->push_back(ImageOperandsConstOffsetsMask); - words->push_back(ConstantImageGatherHorizontalOffsets(state)); + words.push_back(ImageOperandsConstOffsetsMask); + words.push_back(ConstantImageGatherHorizontalOffsets(state)); return; } if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagOffset)) { - words->push_back(ImageOperandsOffsetMask); - words->push_back(EmitImagePackedOffset2I32(state, inst, layout)); + words.push_back(ImageOperandsOffsetMask); + words.push_back(EmitImagePackedOffset2I32(state, inst, layout)); } } -void EmitImageGather4(EmitterState* state, const IR::Instruction& inst) { - const auto view = SampledImageViewKind(*state, inst.memory, inst.pc); +void EmitImageGather4(EmitterState& state, const IR::Instruction& inst) { + const auto view = SampledImageViewKind(state, inst.memory, inst.pc); const auto sampled_image = MakeSampledImage(state, inst.memory, inst.pc, view); const auto layout = MakeImageSampleLayout(inst, view); const auto coord = EmitImageCoordF32(state, inst, layout, view); - const auto texels = state->builder.AllocateId(); + const auto texels = state.builder.AllocateId(); const auto dref = HasImageSampleFlag(inst, Decoder::ImageSampleFlagCompare); const bool integer = inst.memory.kind == IR::ResourceKind::ImageUint; - const auto result_type = integer ? state->vec4_uint_type : state->vec4_float_type; + const auto result_type = integer ? state.vec4_uint_type : state.vec4_float_type; std::vector words = dref ? std::vector {OpImageDrefGather, - state->vec4_float_type, + state.vec4_float_type, texels, sampled_image, coord, @@ -342,17 +334,16 @@ void EmitImageGather4(EmitterState* state, const IR::Instruction& inst) { OpImageGather, result_type, texels, sampled_image, coord, ConstantU32(state, ImageGatherComponent(inst.memory.dmask))}; - AddImageGatherOperands(state, inst, layout, &words); - state->builder.AddFunction(words); + AddImageGatherOperands(state, inst, layout, words); + state.builder.AddFunction(words); for (uint32_t i = 0; i < inst.memory.data_dwords; i++) { - const auto component = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, - integer ? state->uint_type : state->float_type, component, - texels, i}); - const auto bits = integer ? component : state->builder.AllocateId(); + const auto component = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, integer ? state.uint_type : state.float_type, + component, texels, i}); + const auto bits = integer ? component : state.builder.AllocateId(); if (!integer) { - state->builder.AddFunction({OpBitcast, state->uint_type, bits, component}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, component}); } EmitStoreU32(state, OffsetRegisterOperand(inst.dst, i), bits); } diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterInternal.h b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterInternal.h index 9a3190d72..1494e27c2 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterInternal.h +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterInternal.h @@ -298,9 +298,12 @@ struct SampledImageDescriptors { }; struct EmitterState { + EmitterState(const IR::Program& program_, const IR::ResourceSnapshot& resources_) + : program(program_), resources(resources_) {} + Builder builder; - const IR::Program* program = nullptr; - const IR::ResourceSnapshot* resources = nullptr; + const IR::Program& program; + const IR::ResourceSnapshot& resources; const ShaderVertexInputInfo* vertex_input_info = nullptr; const ShaderPixelInputInfo* pixel_input_info = nullptr; const ShaderComputeInputInfo* compute_input_info = nullptr; @@ -544,7 +547,7 @@ uint32_t VertexParameterInputPointerType(const EmitterState& state, VertexInputS void SetError(std::string* error, const char* message); -void CollectRegister(std::vector* registers, IR::Register reg); +void CollectRegister(std::vector& registers, IR::Register reg); IR::Operand MakeRegisterOperand(IR::RegisterFile file, uint32_t index); @@ -560,25 +563,25 @@ bool IsSccOperand(const IR::Operand& operand); bool IsCompareOpcode(IR::Opcode op); -void CollectMaskStateRegisters(std::vector* registers); +void CollectMaskStateRegisters(std::vector& registers); -void CollectSequentialRegisters(std::vector* registers, const IR::Operand& base, +void CollectSequentialRegisters(std::vector& registers, const IR::Operand& base, uint32_t count); uint32_t MaxCollectedVectorRegisterEnd(const std::vector& registers); void CollectMoveRelSourceRegisters(const IR::Program& program, - std::vector* registers); + std::vector& registers); bool IsPairDwordOpcode(IR::Opcode op); uint32_t PairDwordSourceCount(IR::Opcode op, uint32_t src_count); -void CollectRegisters(const IR::Program& program, std::vector* registers); +void CollectRegisters(const IR::Program& program, std::vector& registers); bool HasOutput(const std::vector& outputs, IR::StageOutputKind kind, uint32_t index); -void CopyProgramInputsAndOutputs(EmitterState* state, const IR::Program& program); +void CopyProgramInputsAndOutputs(EmitterState& state, const IR::Program& program); uint32_t OutputVariableForExport(const EmitterState& state, const IR::ExportInfo& exp); @@ -604,13 +607,13 @@ bool ProgramNeedsSubgroupLocalInvocationId(const IR::Program& program); uint32_t PointerForRegister(const EmitterState& state, IR::Register reg); -uint32_t ConstantU32(EmitterState* state, uint32_t value); +uint32_t ConstantU32(EmitterState& state, uint32_t value); -void EmitStoreU32(EmitterState* state, const IR::Operand& dst, uint32_t value); +void EmitStoreU32(EmitterState& state, const IR::Operand& dst, uint32_t value); -uint32_t EmitSubgroupLocalInvocationId(EmitterState* state); +uint32_t EmitSubgroupLocalInvocationId(EmitterState& state); -uint32_t EmitLaneIndexActiveBool(EmitterState* state, uint32_t lane); +uint32_t EmitLaneIndexActiveBool(EmitterState& state, uint32_t lane); [[noreturn]] void ExitDescriptorBindingFailure(const EmitterState& state, IR::DescriptorBindingKind kind, uint32_t resource, @@ -619,7 +622,7 @@ uint32_t EmitLaneIndexActiveBool(EmitterState* state, uint32_t lane); DescriptorResourceBinding ResourceForDescriptor(const EmitterState& state, IR::DescriptorBindingKind kind, uint32_t resource); -uint32_t DescriptorElementPointer(EmitterState* state, uint32_t result_ptr_type, +uint32_t DescriptorElementPointer(EmitterState& state, uint32_t result_ptr_type, uint32_t variable_id, uint32_t array_index, IR::DescriptorBindingKind kind, uint32_t resource, const char* variable_name); @@ -635,207 +638,207 @@ uint32_t ImageViewSampledImageType(const EmitterState& state, ImageViewKind view uint32_t ImageViewSizeType(const EmitterState& state, ImageViewKind view); -uint32_t LoadSampledImageDescriptor(EmitterState* state, const IR::MemoryInfo& mem, uint32_t use_pc, +uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, ImageViewKind view); -uint32_t LoadSamplerDescriptor(EmitterState* state, uint32_t sampler, uint32_t use_pc); +uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler, uint32_t use_pc); -uint32_t MakeSampledImage(EmitterState* state, const IR::MemoryInfo& mem, uint32_t use_pc, +uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, ImageViewKind view); ImageViewKind StorageImageViewKind(const EmitterState& state, const IR::MemoryInfo& mem, bool uint_image, uint32_t use_pc); -uint32_t StorageImageDescriptorPointer(EmitterState* state, uint32_t resource, bool uint_image, +uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource, bool uint_image, uint32_t use_pc = UINT32_MAX, ImageViewKind view = ImageViewKind::Dim2D); -uint32_t LoadStorageImageDescriptor(EmitterState* state, uint32_t resource, bool uint_image, +uint32_t LoadStorageImageDescriptor(EmitterState& state, uint32_t resource, bool uint_image, uint32_t use_pc, ImageViewKind view = ImageViewKind::Dim2D); uint32_t ExecutionModelForStage(ShaderType stage); -uint32_t ConstantU32(EmitterState* state, uint32_t value); +uint32_t ConstantU32(EmitterState& state, uint32_t value); -uint32_t ConstantI32(EmitterState* state, int32_t value); +uint32_t ConstantI32(EmitterState& state, int32_t value); -uint32_t ConstantF32(EmitterState* state, uint32_t bits); +uint32_t ConstantF32(EmitterState& state, uint32_t bits); uint32_t FloatBits(float value); -uint32_t ConstantF32Value(EmitterState* state, float value); +uint32_t ConstantF32Value(EmitterState& state, float value); -void AllocateInputVariables(EmitterState* state); +void AllocateInputVariables(EmitterState& state); -void AllocateOutputVariables(EmitterState* state); +void AllocateOutputVariables(EmitterState& state); uint32_t BuiltInForInput(IR::StageInputKind kind); -void AddInputAnnotationsAndNames(EmitterState* state); +void AddInputAnnotationsAndNames(EmitterState& state); -void AddOutputAnnotationsAndNames(EmitterState* state); +void AddOutputAnnotationsAndNames(EmitterState& state); -void DecorateDescriptor(EmitterState* state, uint32_t variable, const char* name, uint32_t set, +void DecorateDescriptor(EmitterState& state, uint32_t variable, const char* name, uint32_t set, uint32_t binding); -void AddDescriptorAnnotationsAndNames(EmitterState* state); +void AddDescriptorAnnotationsAndNames(EmitterState& state); -void EmitHeaderAndTypes(EmitterState* state); +void EmitHeaderAndTypes(EmitterState& state); -void AllocateRegisterVariables(EmitterState* state); +void AllocateRegisterVariables(EmitterState& state); -void AllocateDescriptorVariables(EmitterState* state); +void AllocateDescriptorVariables(EmitterState& state); bool SdwaSelectorOffsetWidth(uint32_t sel, uint32_t& offset, uint32_t& width); -uint32_t EmitSdwaExtractU32(EmitterState* state, const IR::Operand& operand, uint32_t value); +uint32_t EmitSdwaExtractU32(EmitterState& state, const IR::Operand& operand, uint32_t value); -uint32_t EmitTrueBool(EmitterState* state); +uint32_t EmitTrueBool(EmitterState& state); -DppTargetLane EmitDppQuadPermTargetLane(EmitterState* state, uint32_t subid, uint32_t control); +DppTargetLane EmitDppQuadPermTargetLane(EmitterState& state, uint32_t subid, uint32_t control); -DppTargetLane EmitDppRowShiftTargetLane(EmitterState* state, uint32_t subid, uint32_t amount, +DppTargetLane EmitDppRowShiftTargetLane(EmitterState& state, uint32_t subid, uint32_t amount, bool left); -DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState* state, uint32_t subid, uint32_t amount); +DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState& state, uint32_t subid, uint32_t amount); -DppTargetLane EmitDppMirrorTargetLane(EmitterState* state, uint32_t subid, bool half_row); +DppTargetLane EmitDppMirrorTargetLane(EmitterState& state, uint32_t subid, bool half_row); -DppTargetLane EmitDppTargetLane(EmitterState* state, uint32_t control); +DppTargetLane EmitDppTargetLane(EmitterState& state, uint32_t control); -uint32_t EmitDppValueU32(EmitterState* state, const IR::Operand& operand, uint32_t value); +uint32_t EmitDppValueU32(EmitterState& state, const IR::Operand& operand, uint32_t value); -uint32_t EmitValueLoad(EmitterState* state, const IR::Operand& operand); +uint32_t EmitValueLoad(EmitterState& state, const IR::Operand& operand); -uint32_t EmitRegisterLoad(EmitterState* state, IR::Register reg); +uint32_t EmitRegisterLoad(EmitterState& state, IR::Register reg); -uint32_t WaveMaskHighLoad(EmitterState* state, IR::RegisterFile file); +uint32_t WaveMaskHighLoad(EmitterState& state, IR::RegisterFile file); -uint32_t EmitLaneMaskPartU32(EmitterState* state, uint32_t part); +uint32_t EmitLaneMaskPartU32(EmitterState& state, uint32_t part); -uint32_t EmitThreadMaskBelowPartU32(EmitterState* state, uint32_t part); +uint32_t EmitThreadMaskBelowPartU32(EmitterState& state, uint32_t part); -uint32_t EmitMaskActiveBool(EmitterState* state, IR::RegisterFile file); +uint32_t EmitMaskActiveBool(EmitterState& state, IR::RegisterFile file); -uint32_t EmitMaskZeroBool(EmitterState* state, IR::RegisterFile file, bool zero); +uint32_t EmitMaskZeroBool(EmitterState& state, IR::RegisterFile file, bool zero); -uint32_t EmitMaskSummaryZeroBool(EmitterState* state, IR::RegisterFile file, bool zero); +uint32_t EmitMaskSummaryZeroBool(EmitterState& state, IR::RegisterFile file, bool zero); -uint32_t EmitExecActiveBool(EmitterState* state); +uint32_t EmitExecActiveBool(EmitterState& state); -uint32_t EmitConditionBool(EmitterState* state, const IR::Operand& operand); +uint32_t EmitConditionBool(EmitterState& state, const IR::Operand& operand); -uint32_t EmitSubgroupLocalInvocationId(EmitterState* state); +uint32_t EmitSubgroupLocalInvocationId(EmitterState& state); uint32_t InputVariableForKind(const EmitterState& state, IR::StageInputKind kind); uint32_t InputVariableForParameter(const EmitterState& state, uint32_t location); -uint32_t EmitInputComponentU32(EmitterState* state, IR::StageInputKind kind, uint32_t component); +uint32_t EmitInputComponentU32(EmitterState& state, IR::StageInputKind kind, uint32_t component); -uint32_t EmitLocalInvocationIndex(EmitterState* state); +uint32_t EmitLocalInvocationIndex(EmitterState& state); -void EmitLoadInputF32(EmitterState* state, const IR::Instruction& inst); +void EmitLoadInputF32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitSccBool(EmitterState* state, bool non_zero); +uint32_t EmitSccBool(EmitterState& state, bool non_zero); -uint32_t EmitFloatLoad(EmitterState* state, const IR::Operand& operand); +uint32_t EmitFloatLoad(EmitterState& state, const IR::Operand& operand); -uint32_t ApplyResultModifiersF32(EmitterState* state, uint32_t value, const IR::Operand& dst); +uint32_t ApplyResultModifiersF32(EmitterState& state, uint32_t value, const IR::Operand& dst); -uint32_t EmitMixF32Load(EmitterState* state, const IR::Operand& operand); +uint32_t EmitMixF32Load(EmitterState& state, const IR::Operand& operand); IR::Operand OffsetRegisterOperand(const IR::Operand& operand, uint32_t offset); -uint32_t EmitLaneMaskOperandActiveBool(EmitterState* state, const IR::Operand& operand); +uint32_t EmitLaneMaskOperandActiveBool(EmitterState& state, const IR::Operand& operand); -uint32_t EmitBallotLaneActiveBool(EmitterState* state, uint32_t ballot, uint32_t lane); +uint32_t EmitBallotLaneActiveBool(EmitterState& state, uint32_t ballot, uint32_t lane); -uint32_t EmitLaneIndexActiveBool(EmitterState* state, uint32_t lane); +uint32_t EmitLaneIndexActiveBool(EmitterState& state, uint32_t lane); -uint32_t EmitSubgroupLaneActiveBool(EmitterState* state, uint32_t lane); +uint32_t EmitSubgroupLaneActiveBool(EmitterState& state, uint32_t lane); -uint32_t EmitSequentialValueLoad(EmitterState* state, const IR::Operand& operand, uint32_t offset); +uint32_t EmitSequentialValueLoad(EmitterState& state, const IR::Operand& operand, uint32_t offset); -uint32_t EmitSequentialFloatLoad(EmitterState* state, const IR::Operand& operand, uint32_t offset); +uint32_t EmitSequentialFloatLoad(EmitterState& state, const IR::Operand& operand, uint32_t offset); uint32_t ImageAddressHalfComponent(const IR::Instruction& inst, uint32_t component); IR::Operand ImageAddressOperand(const IR::Instruction& inst, const IR::Operand& base, uint32_t component); -uint32_t EmitImageAddressValueLoad(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageAddressValueLoad(EmitterState& state, const IR::Instruction& inst, const IR::Operand& base, uint32_t component); -uint32_t EmitImageAddressFloatLoad(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageAddressFloatLoad(EmitterState& state, const IR::Instruction& inst, const IR::Operand& base, uint32_t component); -uint32_t EmitZeroF32(EmitterState* state); +uint32_t EmitZeroF32(EmitterState& state); bool HasImageSampleFlag(const IR::Instruction& inst, uint32_t flag); ImageSampleLayout MakeImageSampleLayout(const IR::Instruction& inst, ImageViewKind view); -uint32_t EmitImageCoordF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageCoordF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout, ImageViewKind view); -uint32_t EmitImageLodF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageLodF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout); -uint32_t EmitImageDrefF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageDrefF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout); -uint32_t EmitImageBiasF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageBiasF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout); -uint32_t EmitImageGradientF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageGradientF32(EmitterState& state, const IR::Instruction& inst, uint32_t first_component); -uint32_t EmitImagePackedOffset2I32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImagePackedOffset2I32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout); -uint32_t EmitImageOffsetCoordF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageOffsetCoordF32(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout, uint32_t sampled_image, uint32_t coord, ImageViewKind view); -uint32_t EmitImageCoordU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageCoordU32(EmitterState& state, const IR::Instruction& inst, ImageViewKind view = ImageViewKind::Dim2D); -uint32_t EmitImageLoadCoordU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageLoadCoordU32(EmitterState& state, const IR::Instruction& inst, ImageViewKind view); -uint32_t EmitImageMipLodU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageMipLodU32(EmitterState& state, const IR::Instruction& inst, const IR::Operand& address, ImageViewKind view); -uint32_t EmitImageQueryCoordF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageQueryCoordF32(EmitterState& state, const IR::Instruction& inst, ImageViewKind view); uint32_t DmaskComponentIndex(uint32_t dmask, uint32_t component); -uint32_t EmitImageStoreComponentF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageStoreComponentF32(EmitterState& state, const IR::Instruction& inst, uint32_t component); -uint32_t EmitImageStoreTexelF32(EmitterState* state, const IR::Instruction& inst); +uint32_t EmitImageStoreTexelF32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitImageStoreTexelU32(EmitterState* state, const IR::Instruction& inst); +uint32_t EmitImageStoreTexelU32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitDppWriteActiveBool(EmitterState* state, const IR::Operand& dst); +uint32_t EmitDppWriteActiveBool(EmitterState& state, const IR::Operand& dst); -uint32_t EmitSdwaDestinationMerge(EmitterState* state, uint32_t pointer, const IR::Operand& dst, +uint32_t EmitSdwaDestinationMerge(EmitterState& state, uint32_t pointer, const IR::Operand& dst, uint32_t value); -void EmitStoreU32(EmitterState* state, const IR::Operand& dst, uint32_t value); +void EmitStoreU32(EmitterState& state, const IR::Operand& dst, uint32_t value); -uint32_t EmitAddU32(EmitterState* state, uint32_t lhs, uint32_t rhs); +uint32_t EmitAddU32(EmitterState& state, uint32_t lhs, uint32_t rhs); -uint32_t EmitBinaryU32(EmitterState* state, uint32_t opcode, uint32_t lhs, uint32_t rhs); +uint32_t EmitBinaryU32(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs); -uint32_t EmitNotEqualZeroBool(EmitterState* state, uint32_t value); +uint32_t EmitNotEqualZeroBool(EmitterState& state, uint32_t value); -uint32_t EmitSelectU32Value(EmitterState* state, uint32_t condition, uint32_t true_value, +uint32_t EmitSelectU32Value(EmitterState& state, uint32_t condition, uint32_t true_value, uint32_t false_value); -uint32_t EmitByteAddress(EmitterState* state, const IR::Instruction& inst, uint32_t first_src, +uint32_t EmitByteAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count); uint32_t StorageBufferPackedStride(const EmitterState& state, const IR::MemoryInfo& mem, @@ -845,67 +848,67 @@ uint32_t StorageBufferFormat(const EmitterState& state, const IR::MemoryInfo& me bool ShouldApplyBufferAddTid(const IR::Instruction& inst); -uint32_t EmitBufferIndexWithAddTid(EmitterState* state, const IR::Instruction& inst, uint32_t index, +uint32_t EmitBufferIndexWithAddTid(EmitterState& state, const IR::Instruction& inst, uint32_t index, uint32_t packed); -uint32_t EmitOptionalLogicalAndBool(EmitterState* state, uint32_t lhs, uint32_t rhs); +uint32_t EmitOptionalLogicalAndBool(EmitterState& state, uint32_t lhs, uint32_t rhs); bool IsStorageBufferMemoryKind(IR::ResourceKind kind); -uint32_t EmitBufferAddressFromParts(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst, uint32_t index, uint32_t offset, uint32_t soffset); -uint32_t EmitBufferByteAddress(EmitterState* state, const IR::Instruction& inst, uint32_t first_src, +uint32_t EmitBufferByteAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count); -uint32_t EmitMemoryByteAddress(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitMemoryByteAddress(EmitterState& state, const IR::Instruction& inst, const IR::MemoryInfo& mem, uint32_t first_src, uint32_t src_count); -uint32_t EmitDwordIndex(EmitterState* state, const IR::Instruction& inst, uint32_t first_src, +uint32_t EmitDwordIndex(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count); -uint32_t EmitMemoryDwordIndex(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitMemoryDwordIndex(EmitterState& state, const IR::Instruction& inst, const IR::MemoryInfo& mem, uint32_t first_src, uint32_t src_count); -DescriptorResourceBinding StorageBufferBindingForMemory(EmitterState* state, +DescriptorResourceBinding StorageBufferBindingForMemory(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc); -uint32_t EmitStorageBufferObjectPointer(EmitterState* state, const IR::MemoryInfo& mem, +uint32_t EmitStorageBufferObjectPointer(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc); -uint32_t EmitStorageBufferElementInBounds(EmitterState* state, const IR::MemoryInfo& mem, +uint32_t EmitStorageBufferElementInBounds(EmitterState& state, const IR::MemoryInfo& mem, uint32_t index, uint32_t use_pc); -uint32_t EmitStorageBufferElementPointer(EmitterState* state, const IR::MemoryInfo& mem, +uint32_t EmitStorageBufferElementPointer(EmitterState& state, const IR::MemoryInfo& mem, uint32_t index, uint32_t use_pc); -uint32_t EmitLdsElementPointer(EmitterState* state, uint32_t index); +uint32_t EmitLdsElementPointer(EmitterState& state, uint32_t index); -uint32_t EmitGdsElementInBounds(EmitterState* state, uint32_t index); +uint32_t EmitGdsElementInBounds(EmitterState& state, uint32_t index); -uint32_t EmitGdsElementPointer(EmitterState* state, uint32_t index); +uint32_t EmitGdsElementPointer(EmitterState& state, uint32_t index); -uint32_t EmitMemoryElementPointer(EmitterState* state, const IR::MemoryInfo& mem, uint32_t index, +uint32_t EmitMemoryElementPointer(EmitterState& state, const IR::MemoryInfo& mem, uint32_t index, uint32_t use_pc); -uint32_t EmitMemoryLoadDwordValueU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitMemoryLoadDwordValueU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count); -void EmitMemoryLoadU32(EmitterState* state, const IR::Instruction& inst, IR::ResourceKind kind, +void EmitMemoryLoadU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count); -uint32_t EmitMemoryLoadSubDwordValueU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitMemoryLoadSubDwordValueU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count, uint32_t data_bits, bool sign_extend); -void EmitMemoryLoadSubDwordU32(EmitterState* state, const IR::Instruction& inst, +void EmitMemoryLoadSubDwordU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count, uint32_t data_bits, bool sign_extend); -void EmitMemoryStoreU32(EmitterState* state, const IR::Instruction& inst, IR::ResourceKind kind, +void EmitMemoryStoreU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count); -void EmitMemoryStoreSubDwordU32(EmitterState* state, const IR::Instruction& inst, +void EmitMemoryStoreSubDwordU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count, uint32_t data_bits); @@ -919,638 +922,638 @@ Prospero::BufferFormat FormattedBufferFormat(const EmitterState& state, IR::Instruction WithFormatComponentByteOffset(const IR::Instruction& inst, Prospero::BufferFormat format); -uint32_t EmitTBufferBitcastF32ToU32(EmitterState* state, uint32_t value); +uint32_t EmitTBufferBitcastF32ToU32(EmitterState& state, uint32_t value); -uint32_t EmitTBufferBitcastU32ToF32(EmitterState* state, uint32_t value); +uint32_t EmitTBufferBitcastU32ToF32(EmitterState& state, uint32_t value); -uint32_t EmitTBufferBitcastU32ToI32(EmitterState* state, uint32_t value); +uint32_t EmitTBufferBitcastU32ToI32(EmitterState& state, uint32_t value); -uint32_t EmitTBufferCompareU32Constant(EmitterState* state, uint32_t opcode, uint32_t value, +uint32_t EmitTBufferCompareU32Constant(EmitterState& state, uint32_t opcode, uint32_t value, uint32_t constant); -uint32_t EmitTBufferSelectF32(EmitterState* state, uint32_t condition, uint32_t true_value, +uint32_t EmitTBufferSelectF32(EmitterState& state, uint32_t condition, uint32_t true_value, uint32_t false_value); bool IsSignedFormatComponent(Format::ComponentType type); -uint32_t EmitExtractFormatFieldU32(EmitterState* state, uint32_t raw_word, uint32_t offset, +uint32_t EmitExtractFormatFieldU32(EmitterState& state, uint32_t raw_word, uint32_t offset, uint32_t bits, bool sign_extend); -uint32_t EmitHalfToF32Bits(EmitterState* state, uint32_t raw); +uint32_t EmitHalfToF32Bits(EmitterState& state, uint32_t raw); -uint32_t EmitUFloatToF32Bits(EmitterState* state, uint32_t raw, uint32_t bits); +uint32_t EmitUFloatToF32Bits(EmitterState& state, uint32_t raw, uint32_t bits); -uint32_t EmitFormatRawComponent(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitFormatRawComponent(EmitterState& state, const IR::Instruction& inst, const Format::BufferFormatInfo& info); -uint32_t NormalizeFormatComponent(EmitterState* state, const Format::BufferFormatInfo& info, +uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferFormatInfo& info, uint32_t component, uint32_t raw); -uint32_t UnpackTBufferFormat(EmitterState* state, const IR::Instruction& inst, +uint32_t UnpackTBufferFormat(EmitterState& state, const IR::Instruction& inst, const Format::BufferFormatInfo& info); -bool EmitTypedTBufferLoad(EmitterState* state, const IR::Instruction& inst, +bool EmitTypedTBufferLoad(EmitterState& state, const IR::Instruction& inst, const Format::BufferFormatInfo& info); -bool EmitFormattedBufferLoad(EmitterState* state, const IR::Instruction& inst); +bool EmitFormattedBufferLoad(EmitterState& state, const IR::Instruction& inst); uint32_t FormattedBufferDwordStoreComponentCount(Prospero::BufferFormat format, uint32_t opcode_components); -bool EmitBufferIntegerFormatStore(EmitterState* state, const IR::Instruction& inst); +bool EmitBufferIntegerFormatStore(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitAtomicPointer(EmitterState* state, const IR::Instruction& inst); +uint32_t EmitAtomicPointer(EmitterState& state, const IR::Instruction& inst); -void EmitDeviceAtomicMemoryBarrier(EmitterState* state); +void EmitDeviceAtomicMemoryBarrier(EmitterState& state); -void EmitAtomicU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitAtomicU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitSLoadDword(EmitterState* state, const IR::Instruction& inst); +void EmitSLoadDword(EmitterState& state, const IR::Instruction& inst); -void EmitLoadSrtDword(EmitterState* state, const IR::Instruction& inst); +void EmitLoadSrtDword(EmitterState& state, const IR::Instruction& inst); -void EmitBufferLoadUbyte(EmitterState* state, const IR::Instruction& inst); +void EmitBufferLoadUbyte(EmitterState& state, const IR::Instruction& inst); -void EmitBufferLoadSbyte(EmitterState* state, const IR::Instruction& inst); +void EmitBufferLoadSbyte(EmitterState& state, const IR::Instruction& inst); -void EmitBufferLoadUshort(EmitterState* state, const IR::Instruction& inst); +void EmitBufferLoadUshort(EmitterState& state, const IR::Instruction& inst); -void EmitBufferLoadSshort(EmitterState* state, const IR::Instruction& inst); +void EmitBufferLoadSshort(EmitterState& state, const IR::Instruction& inst); -void EmitBufferLoadDword(EmitterState* state, const IR::Instruction& inst); +void EmitBufferLoadDword(EmitterState& state, const IR::Instruction& inst); -void EmitBufferStoreDword(EmitterState* state, const IR::Instruction& inst); +void EmitBufferStoreDword(EmitterState& state, const IR::Instruction& inst); -void EmitFlatLoadUbyte(EmitterState* state, const IR::Instruction& inst); +void EmitFlatLoadUbyte(EmitterState& state, const IR::Instruction& inst); -void EmitFlatLoadSbyte(EmitterState* state, const IR::Instruction& inst); +void EmitFlatLoadSbyte(EmitterState& state, const IR::Instruction& inst); -void EmitFlatLoadUshort(EmitterState* state, const IR::Instruction& inst); +void EmitFlatLoadUshort(EmitterState& state, const IR::Instruction& inst); -void EmitFlatLoadSshort(EmitterState* state, const IR::Instruction& inst); +void EmitFlatLoadSshort(EmitterState& state, const IR::Instruction& inst); -void EmitFlatLoadDword(EmitterState* state, const IR::Instruction& inst); +void EmitFlatLoadDword(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitDsAddtidDwordIndex(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitDsAddtidDwordIndex(EmitterState& state, const IR::Instruction& inst, uint32_t m0_src_index); -void EmitDsWriteAddtidB32(EmitterState* state, const IR::Instruction& inst); +void EmitDsWriteAddtidB32(EmitterState& state, const IR::Instruction& inst); -void EmitDsReadAddtidB32(EmitterState* state, const IR::Instruction& inst); +void EmitDsReadAddtidB32(EmitterState& state, const IR::Instruction& inst); -void EmitDsAppendConsume(EmitterState* state, const IR::Instruction& inst, uint32_t atomic_opcode); +void EmitDsAppendConsume(EmitterState& state, const IR::Instruction& inst, uint32_t atomic_opcode); -void EmitDsFloatMinMaxF32(EmitterState* state, const IR::Instruction& inst, bool max_value); +void EmitDsFloatMinMaxF32(EmitterState& state, const IR::Instruction& inst, bool max_value); -uint32_t EmitDsSwizzleTargetLane(EmitterState* state, uint32_t subid, uint32_t control); +uint32_t EmitDsSwizzleTargetLane(EmitterState& state, uint32_t subid, uint32_t control); -void EmitDsSwizzleB32(EmitterState* state, const IR::Instruction& inst); +void EmitDsSwizzleB32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitImageGetResinfoComponent(EmitterState* state, uint32_t image, uint32_t size, +uint32_t EmitImageGetResinfoComponent(EmitterState& state, uint32_t image, uint32_t size, uint32_t component_index); -void EmitImageGetResinfo(EmitterState* state, const IR::Instruction& inst); +void EmitImageGetResinfo(EmitterState& state, const IR::Instruction& inst); -void EmitImageGetLod(EmitterState* state, const IR::Instruction& inst); +void EmitImageGetLod(EmitterState& state, const IR::Instruction& inst); -void EmitImageLoad(EmitterState* state, const IR::Instruction& inst); +void EmitImageLoad(EmitterState& state, const IR::Instruction& inst); -void EmitImageStore(EmitterState* state, const IR::Instruction& inst); +void EmitImageStore(EmitterState& state, const IR::Instruction& inst); -void EmitImageSampleResult(EmitterState* state, const IR::Instruction& inst, uint32_t sample, +void EmitImageSampleResult(EmitterState& state, const IR::Instruction& inst, uint32_t sample, bool dref); bool ImageSampleNeedsExplicitLod(const EmitterState& state, const IR::Instruction& inst); -void AddImageSampleOperands(EmitterState* state, const IR::Instruction& inst, +void AddImageSampleOperands(EmitterState& state, const IR::Instruction& inst, const ImageSampleLayout& layout, bool explicit_lod, - std::vector* words); + std::vector& words); uint32_t ImageSampleOpcode(const EmitterState& state, const IR::Instruction& inst); -void EmitImageSample(EmitterState* state, const IR::Instruction& inst); +void EmitImageSample(EmitterState& state, const IR::Instruction& inst); uint32_t ImageGatherComponent(uint32_t dmask); -void EmitImageGather4(EmitterState* state, const IR::Instruction& inst); +void EmitImageGather4(EmitterState& state, const IR::Instruction& inst); -void EmitMoveU32(EmitterState* state, const IR::Instruction& inst); +void EmitMoveU32(EmitterState& state, const IR::Instruction& inst); -void EmitMoveF32Bits(EmitterState* state, const IR::Instruction& inst); +void EmitMoveF32Bits(EmitterState& state, const IR::Instruction& inst); uint32_t MoveRelRegisterLimit(const EmitterState& state, IR::Register base); -void EmitMoveRelSourceU32(EmitterState* state, const IR::Instruction& inst); +void EmitMoveRelSourceU32(EmitterState& state, const IR::Instruction& inst); -void EmitMoveRelDestU32(EmitterState* state, const IR::Instruction& inst); +void EmitMoveRelDestU32(EmitterState& state, const IR::Instruction& inst); -void EmitMoveU64(EmitterState* state, const IR::Instruction& inst); +void EmitMoveU64(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitWqmLaneU32(EmitterState* state, uint32_t src); +uint32_t EmitWqmLaneU32(EmitterState& state, uint32_t src); -void EmitWqmB64(EmitterState* state, const IR::Instruction& inst); +void EmitWqmB64(EmitterState& state, const IR::Instruction& inst); -void EmitSaveexecB32(EmitterState* state, const IR::Instruction& inst); +void EmitSaveexecB32(EmitterState& state, const IR::Instruction& inst); -void EmitSaveexecB64(EmitterState* state, const IR::Instruction& inst); +void EmitSaveexecB64(EmitterState& state, const IR::Instruction& inst); -void EmitReadFirstLaneU32(EmitterState* state, const IR::Instruction& inst); +void EmitReadFirstLaneU32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitLaneIndex(EmitterState* state, const IR::Operand& operand); +uint32_t EmitLaneIndex(EmitterState& state, const IR::Operand& operand); -void EmitReadLaneU32(EmitterState* state, const IR::Instruction& inst); +void EmitReadLaneU32(EmitterState& state, const IR::Instruction& inst); -void EmitWriteLaneU32(EmitterState* state, const IR::Instruction& inst); +void EmitWriteLaneU32(EmitterState& state, const IR::Instruction& inst); -void EmitPermlaneB32(EmitterState* state, const IR::Instruction& inst, bool x16); +void EmitPermlaneB32(EmitterState& state, const IR::Instruction& inst, bool x16); -void EmitControlNop(EmitterState* state, const IR::Instruction& inst); +void EmitControlNop(EmitterState& state, const IR::Instruction& inst); -void EmitWaitcnt(EmitterState* state, const IR::Instruction& inst); +void EmitWaitcnt(EmitterState& state, const IR::Instruction& inst); -void EmitBarrier(EmitterState* state, const IR::Instruction& inst); +void EmitBarrier(EmitterState& state, const IR::Instruction& inst); -void EmitAbsI32(EmitterState* state, const IR::Instruction& inst); +void EmitAbsI32(EmitterState& state, const IR::Instruction& inst); -void EmitUnaryU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitUnaryU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitUnaryU64(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitUnaryU64(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitFindLsbU32(EmitterState* state, const IR::Instruction& inst); +void EmitFindLsbU32(EmitterState& state, const IR::Instruction& inst); -void EmitFindMsbFromHighU32(EmitterState* state, const IR::Instruction& inst); +void EmitFindMsbFromHighU32(EmitterState& state, const IR::Instruction& inst); -void EmitFindMsbFromHighU64(EmitterState* state, const IR::Instruction& inst); +void EmitFindMsbFromHighU64(EmitterState& state, const IR::Instruction& inst); -void EmitBitCountU64(EmitterState* state, const IR::Instruction& inst); +void EmitBitCountU64(EmitterState& state, const IR::Instruction& inst); -void EmitBitCountU32(EmitterState* state, const IR::Instruction& inst); +void EmitBitCountU32(EmitterState& state, const IR::Instruction& inst); -void EmitBitCountAddU32(EmitterState* state, const IR::Instruction& inst); +void EmitBitCountAddU32(EmitterState& state, const IR::Instruction& inst); -void EmitBinaryU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitBinaryNotRhsU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryNotRhsU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitBinaryThenNotU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryThenNotU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitMaskedBitCountU32(EmitterState* state, const IR::Instruction& inst, uint32_t exec_index); +void EmitMaskedBitCountU32(EmitterState& state, const IR::Instruction& inst, uint32_t exec_index); -uint32_t EmitMask5U32(EmitterState* state, uint32_t value); +uint32_t EmitMask5U32(EmitterState& state, uint32_t value); -void EmitChainedBinaryU32(EmitterState* state, const IR::Instruction& inst, uint32_t first_op, +void EmitChainedBinaryU32(EmitterState& state, const IR::Instruction& inst, uint32_t first_op, uint32_t second_op, bool mask_first_rhs = false, bool mask_second_rhs = false); -void EmitBinaryU64(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryU64(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitBinaryNotRhsU64(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryNotRhsU64(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitBinaryThenNotU64(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryThenNotU64(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitSelectU64(EmitterState* state, const IR::Instruction& inst); +void EmitSelectU64(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitSelectValueU32(EmitterState* state, uint32_t cond, uint32_t true_value, +uint32_t EmitSelectValueU32(EmitterState& state, uint32_t cond, uint32_t true_value, uint32_t false_value); -void EmitStoreSccBool(EmitterState* state, uint32_t cond); +void EmitStoreSccBool(EmitterState& state, uint32_t cond); -uint32_t EmitAndConstant(EmitterState* state, uint32_t value, uint32_t mask); +uint32_t EmitAndConstant(EmitterState& state, uint32_t value, uint32_t mask); -void EmitShiftLeftLogicalU64Values(EmitterState* state, uint32_t low, uint32_t high, uint32_t shift, - uint32_t* out_low, uint32_t* out_high); +void EmitShiftLeftLogicalU64Values(EmitterState& state, uint32_t low, uint32_t high, uint32_t shift, + uint32_t& out_low, uint32_t& out_high); -void EmitShiftLeftLogicalU64(EmitterState* state, const IR::Instruction& inst); +void EmitShiftLeftLogicalU64(EmitterState& state, const IR::Instruction& inst); -void EmitShiftRightLogicalU64Values(EmitterState* state, uint32_t low, uint32_t high, - uint32_t shift, uint32_t* out_low, uint32_t* out_high); +void EmitShiftRightLogicalU64Values(EmitterState& state, uint32_t low, uint32_t high, + uint32_t shift, uint32_t& out_low, uint32_t& out_high); -void EmitShiftRightLogicalU64(EmitterState* state, const IR::Instruction& inst); +void EmitShiftRightLogicalU64(EmitterState& state, const IR::Instruction& inst); -void EmitAdd3U32(EmitterState* state, const IR::Instruction& inst); +void EmitAdd3U32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitAndConstant(EmitterState* state, uint32_t value, uint32_t mask); +uint32_t EmitAndConstant(EmitterState& state, uint32_t value, uint32_t mask); -void EmitShiftU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitShiftU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -uint32_t EmitU16LaneBits(EmitterState* state, const IR::Operand& operand, bool high_lane, +uint32_t EmitU16LaneBits(EmitterState& state, const IR::Operand& operand, bool high_lane, bool sign_extend = false); -void EmitShiftU16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode, +void EmitShiftU16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode, bool arithmetic); -void EmitBinaryU16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryU16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitMinMaxU16(EmitterState* state, const IR::Instruction& inst, bool signed_value, +void EmitMinMaxU16(EmitterState& state, const IR::Instruction& inst, bool signed_value, bool max_value); -uint32_t EmitXorConstant(EmitterState* state, uint32_t value, uint32_t mask); +uint32_t EmitXorConstant(EmitterState& state, uint32_t value, uint32_t mask); -AddCarryResult EmitAddCarryValues(EmitterState* state, uint32_t lhs, uint32_t rhs, +AddCarryResult EmitAddCarryValues(EmitterState& state, uint32_t lhs, uint32_t rhs, uint32_t carry_in); -void EmitLaneMaskPairFromBool(EmitterState* state, const IR::Operand& dst, uint32_t value_bool); +void EmitLaneMaskPairFromBool(EmitterState& state, const IR::Operand& dst, uint32_t value_bool); -void EmitPerInvocationMask(EmitterState* state, const IR::Operand& dst, uint32_t value_bool); +void EmitPerInvocationMask(EmitterState& state, const IR::Operand& dst, uint32_t value_bool); -void EmitIAddCarryU32(EmitterState* state, const IR::Instruction& inst); +void EmitIAddCarryU32(EmitterState& state, const IR::Instruction& inst); -void EmitISubBorrowU32(EmitterState* state, const IR::Instruction& inst); +void EmitISubBorrowU32(EmitterState& state, const IR::Instruction& inst); -void EmitScalarAddCarryU32(EmitterState* state, const IR::Instruction& inst); +void EmitScalarAddCarryU32(EmitterState& state, const IR::Instruction& inst); -void EmitScalarSubBorrowU32(EmitterState* state, const IR::Instruction& inst); +void EmitScalarSubBorrowU32(EmitterState& state, const IR::Instruction& inst); -void EmitScalarSubBorrowCarryU32(EmitterState* state, const IR::Instruction& inst); +void EmitScalarSubBorrowCarryU32(EmitterState& state, const IR::Instruction& inst); -void EmitBitClearU32(EmitterState* state, const IR::Instruction& inst); +void EmitBitClearU32(EmitterState& state, const IR::Instruction& inst); -void EmitBitSetU32(EmitterState* state, const IR::Instruction& inst); +void EmitBitSetU32(EmitterState& state, const IR::Instruction& inst); -void EmitUMadU64U32(EmitterState* state, const IR::Instruction& inst); +void EmitUMadU64U32(EmitterState& state, const IR::Instruction& inst); -void EmitScalarSignedOverflowI32(EmitterState* state, const IR::Instruction& inst, bool subtract); +void EmitScalarSignedOverflowI32(EmitterState& state, const IR::Instruction& inst, bool subtract); -void EmitScalarShiftLeftAddCarryU32(EmitterState* state, const IR::Instruction& inst); +void EmitScalarShiftLeftAddCarryU32(EmitterState& state, const IR::Instruction& inst); -void EmitMulU24U32(EmitterState* state, const IR::Instruction& inst); +void EmitMulU24U32(EmitterState& state, const IR::Instruction& inst); -void EmitMulI24U32(EmitterState* state, const IR::Instruction& inst); +void EmitMulI24U32(EmitterState& state, const IR::Instruction& inst); -void EmitMulHighU32(EmitterState* state, const IR::Instruction& inst); +void EmitMulHighU32(EmitterState& state, const IR::Instruction& inst); -void EmitMulHighI32(EmitterState* state, const IR::Instruction& inst); +void EmitMulHighI32(EmitterState& state, const IR::Instruction& inst); -void EmitMadU32U24(EmitterState* state, const IR::Instruction& inst); +void EmitMadU32U24(EmitterState& state, const IR::Instruction& inst); -void EmitMadI32I24(EmitterState* state, const IR::Instruction& inst); +void EmitMadI32I24(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitShiftLeftConstant(EmitterState* state, uint32_t value, uint32_t shift); +uint32_t EmitShiftLeftConstant(EmitterState& state, uint32_t value, uint32_t shift); -uint32_t EmitShiftRightConstant(EmitterState* state, uint32_t value, uint32_t shift); +uint32_t EmitShiftRightConstant(EmitterState& state, uint32_t value, uint32_t shift); -uint32_t EmitOrU32(EmitterState* state, uint32_t lhs, uint32_t rhs); +uint32_t EmitOrU32(EmitterState& state, uint32_t lhs, uint32_t rhs); -uint32_t EmitBitReplicateHalfU32(EmitterState* state, uint32_t value); +uint32_t EmitBitReplicateHalfU32(EmitterState& state, uint32_t value); -void EmitBitReplicateB64B32(EmitterState* state, const IR::Instruction& inst); +void EmitBitReplicateB64B32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitBitFieldExtractConstant(EmitterState* state, uint32_t value, uint32_t offset, +uint32_t EmitBitFieldExtractConstant(EmitterState& state, uint32_t value, uint32_t offset, uint32_t count); -uint32_t EmitRightAlignedMaskU32(EmitterState* state, uint32_t count); +uint32_t EmitRightAlignedMaskU32(EmitterState& state, uint32_t count); -void EmitBitFieldMaskU32(EmitterState* state, const IR::Instruction& inst); +void EmitBitFieldMaskU32(EmitterState& state, const IR::Instruction& inst); -void EmitRightAlignedMaskU64(EmitterState* state, uint32_t count, uint32_t* out_low, - uint32_t* out_high); +void EmitRightAlignedMaskU64(EmitterState& state, uint32_t count, uint32_t& out_low, + uint32_t& out_high); -void EmitBitFieldMaskU64(EmitterState* state, const IR::Instruction& inst); +void EmitBitFieldMaskU64(EmitterState& state, const IR::Instruction& inst); -void EmitBitFieldExtractU64(EmitterState* state, const IR::Instruction& inst); +void EmitBitFieldExtractU64(EmitterState& state, const IR::Instruction& inst); -void EmitBitFieldExtractU32(EmitterState* state, const IR::Instruction& inst); +void EmitBitFieldExtractU32(EmitterState& state, const IR::Instruction& inst); -void EmitBitFieldExtract3U32(EmitterState* state, const IR::Instruction& inst, bool signed_value); +void EmitBitFieldExtract3U32(EmitterState& state, const IR::Instruction& inst, bool signed_value); -void EmitBitFieldInsertSelectU32(EmitterState* state, const IR::Instruction& inst); +void EmitBitFieldInsertSelectU32(EmitterState& state, const IR::Instruction& inst); -void EmitAlignBitU32(EmitterState* state, const IR::Instruction& inst); +void EmitAlignBitU32(EmitterState& state, const IR::Instruction& inst); -void EmitSelectU32(EmitterState* state, const IR::Instruction& inst); +void EmitSelectU32(EmitterState& state, const IR::Instruction& inst); -void EmitSelectMaskU32(EmitterState* state, const IR::Instruction& inst); +void EmitSelectMaskU32(EmitterState& state, const IR::Instruction& inst); -void EmitSelectF32Bits(EmitterState* state, const IR::Instruction& inst); +void EmitSelectF32Bits(EmitterState& state, const IR::Instruction& inst); -void EmitSelectMaskF32Bits(EmitterState* state, const IR::Instruction& inst); +void EmitSelectMaskF32Bits(EmitterState& state, const IR::Instruction& inst); -void EmitPackU16(EmitterState* state, const IR::Instruction& inst, bool high_src0, bool high_src1); +void EmitPackU16(EmitterState& state, const IR::Instruction& inst, bool high_src0, bool high_src1); -void EmitPackU8F32(EmitterState* state, const IR::Instruction& inst); +void EmitPackU8F32(EmitterState& state, const IR::Instruction& inst); -void EmitBinaryF32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryF32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitLdexpF32(EmitterState* state, const IR::Instruction& inst); +void EmitLdexpF32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitCompareU32Constant(EmitterState* state, uint32_t opcode, uint32_t value, +uint32_t EmitCompareU32Constant(EmitterState& state, uint32_t opcode, uint32_t value, uint32_t constant); -uint32_t EmitSubConstantMinusU32(EmitterState* state, uint32_t constant, uint32_t value); +uint32_t EmitSubConstantMinusU32(EmitterState& state, uint32_t constant, uint32_t value); -uint32_t EmitF32ToF16RtzBits(EmitterState* state, uint32_t f32); +uint32_t EmitF32ToF16RtzBits(EmitterState& state, uint32_t f32); -void EmitPackF32ToF16Rtz(EmitterState* state, const IR::Instruction& inst); +void EmitPackF32ToF16Rtz(EmitterState& state, const IR::Instruction& inst); -void EmitPackNormalizedF32(EmitterState* state, const IR::Instruction& inst, uint32_t ext_inst); +void EmitPackNormalizedF32(EmitterState& state, const IR::Instruction& inst, uint32_t ext_inst); -uint32_t EmitMinMaxU32Value(EmitterState* state, uint32_t lhs, uint32_t rhs, bool max_value); +uint32_t EmitMinMaxU32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value); -void EmitMinMaxU32(EmitterState* state, const IR::Instruction& inst, bool max_value); +void EmitMinMaxU32(EmitterState& state, const IR::Instruction& inst, bool max_value); -void EmitSadU32(EmitterState* state, const IR::Instruction& inst); +void EmitSadU32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitMinMaxI32Value(EmitterState* state, uint32_t lhs, uint32_t rhs, bool max_value); +uint32_t EmitMinMaxI32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value); -void EmitMinMaxI32(EmitterState* state, const IR::Instruction& inst, bool max_value); +void EmitMinMaxI32(EmitterState& state, const IR::Instruction& inst, bool max_value); -void EmitMinMax3U32(EmitterState* state, const IR::Instruction& inst, bool signed_value, +void EmitMinMax3U32(EmitterState& state, const IR::Instruction& inst, bool signed_value, bool max_value); -void EmitMed3U32(EmitterState* state, const IR::Instruction& inst, bool signed_value); +void EmitMed3U32(EmitterState& state, const IR::Instruction& inst, bool signed_value); -uint32_t EmitBitcastF32ToU32(EmitterState* state, uint32_t value); +uint32_t EmitBitcastF32ToU32(EmitterState& state, uint32_t value); -uint32_t EmitBitcastU32ToF32(EmitterState* state, uint32_t value); +uint32_t EmitBitcastU32ToF32(EmitterState& state, uint32_t value); -uint32_t EmitAndU32(EmitterState* state, uint32_t lhs, uint32_t rhs); +uint32_t EmitAndU32(EmitterState& state, uint32_t lhs, uint32_t rhs); -uint32_t EmitLogicalAndBool(EmitterState* state, uint32_t lhs, uint32_t rhs); +uint32_t EmitLogicalAndBool(EmitterState& state, uint32_t lhs, uint32_t rhs); -uint32_t EmitLogicalOrBool(EmitterState* state, uint32_t lhs, uint32_t rhs); +uint32_t EmitLogicalOrBool(EmitterState& state, uint32_t lhs, uint32_t rhs); -uint32_t EmitLogicalNotBool(EmitterState* state, uint32_t value); +uint32_t EmitLogicalNotBool(EmitterState& state, uint32_t value); -F32Class EmitClassifyF32(EmitterState* state, uint32_t value); +F32Class EmitClassifyF32(EmitterState& state, uint32_t value); -uint32_t EmitClassMaskBitMatch(EmitterState* state, uint32_t mask, uint32_t bit, +uint32_t EmitClassMaskBitMatch(EmitterState& state, uint32_t mask, uint32_t bit, uint32_t class_match); -uint32_t EmitClassMaskF32(EmitterState* state, uint32_t value, uint32_t mask); +uint32_t EmitClassMaskF32(EmitterState& state, uint32_t value, uint32_t mask); -uint32_t EmitMinMaxF32Value(EmitterState* state, uint32_t lhs, uint32_t rhs, bool max_value); +uint32_t EmitMinMaxF32Value(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value); -void EmitMinMaxF32(EmitterState* state, const IR::Instruction& inst, bool max_value); +void EmitMinMaxF32(EmitterState& state, const IR::Instruction& inst, bool max_value); -void EmitCompareResult(EmitterState* state, const IR::Operand& dst, uint32_t cond); +void EmitCompareResult(EmitterState& state, const IR::Operand& dst, uint32_t cond); -void EmitCompareU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitCompareU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitCompareU16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitCompareU16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitCompareI16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitCompareI16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitBitCompareB32(EmitterState* state, const IR::Instruction& inst, bool bit_set); +void EmitBitCompareB32(EmitterState& state, const IR::Instruction& inst, bool bit_set); -void EmitCompareNeU64(EmitterState* state, const IR::Instruction& inst); +void EmitCompareNeU64(EmitterState& state, const IR::Instruction& inst); -void EmitCompareConstant(EmitterState* state, const IR::Instruction& inst, bool value); +void EmitCompareConstant(EmitterState& state, const IR::Instruction& inst, bool value); -void EmitCompareMaskU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitCompareMaskU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitCompareF32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitCompareF32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitCompareOrderedF32(EmitterState* state, const IR::Instruction& inst, bool ordered); +void EmitCompareOrderedF32(EmitterState& state, const IR::Instruction& inst, bool ordered); -void EmitCompareClassF32(EmitterState* state, const IR::Instruction& inst); +void EmitCompareClassF32(EmitterState& state, const IR::Instruction& inst); -void EmitCompareMaskF32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitCompareMaskF32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitConvertU32ToF32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertU32ToF32(EmitterState& state, const IR::Instruction& inst); -void EmitConvertI32ToF32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertI32ToF32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitTruncF32Value(EmitterState* state, uint32_t value); +uint32_t EmitTruncF32Value(EmitterState& state, uint32_t value); -void EmitConvertF32ToU32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertF32ToU32(EmitterState& state, const IR::Instruction& inst); -void EmitConvertF32ToI32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertF32ToI32(EmitterState& state, const IR::Instruction& inst); -void EmitConvertF32ToF16(EmitterState* state, const IR::Instruction& inst); +void EmitConvertF32ToF16(EmitterState& state, const IR::Instruction& inst); -void EmitConvertF16ToF32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertF16ToF32(EmitterState& state, const IR::Instruction& inst); -void EmitConvertU16ToF16(EmitterState* state, const IR::Instruction& inst); +void EmitConvertU16ToF16(EmitterState& state, const IR::Instruction& inst); -void EmitConvertF16ToU16(EmitterState* state, const IR::Instruction& inst); +void EmitConvertF16ToU16(EmitterState& state, const IR::Instruction& inst); -void EmitConvertI16ToF16(EmitterState* state, const IR::Instruction& inst); +void EmitConvertI16ToF16(EmitterState& state, const IR::Instruction& inst); -void EmitConvertF16ToI16(EmitterState* state, const IR::Instruction& inst); +void EmitConvertF16ToI16(EmitterState& state, const IR::Instruction& inst); -void EmitConvertRoundPlusInfF32ToI32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertRoundPlusInfF32ToI32(EmitterState& state, const IR::Instruction& inst); -void EmitConvertFloorF32ToI32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertFloorF32ToI32(EmitterState& state, const IR::Instruction& inst); -void EmitConvertI4ToOffsetF32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertI4ToOffsetF32(EmitterState& state, const IR::Instruction& inst); -void EmitConvertByteU32ToF32(EmitterState* state, const IR::Instruction& inst); +void EmitConvertByteU32ToF32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitFlushF32DenormToSignedZero(EmitterState* state, uint32_t value); +uint32_t EmitFlushF32DenormToSignedZero(EmitterState& state, uint32_t value); -void EmitRcpF32(EmitterState* state, const IR::Instruction& inst); +void EmitRcpF32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitTrigCycleF32(EmitterState* state, uint32_t src, bool preserve_signed_zero); +uint32_t EmitTrigCycleF32(EmitterState& state, uint32_t src, bool preserve_signed_zero); -void EmitFloatExtInst(EmitterState* state, const IR::Instruction& inst, uint32_t ext_inst, +void EmitFloatExtInst(EmitterState& state, const IR::Instruction& inst, uint32_t ext_inst, bool scale_by_two_pi = false, bool flush_denorm = false); -void EmitMadF32(EmitterState* state, const IR::Instruction& inst); +void EmitMadF32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitFNegateValue(EmitterState* state, uint32_t value); +uint32_t EmitFNegateValue(EmitterState& state, uint32_t value); -uint32_t EmitFAbsValue(EmitterState* state, uint32_t value); +uint32_t EmitFAbsValue(EmitterState& state, uint32_t value); -uint32_t EmitFCompareValue(EmitterState* state, uint32_t opcode, uint32_t lhs, uint32_t rhs); +uint32_t EmitFCompareValue(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs); -uint32_t EmitLogicalAndValue(EmitterState* state, uint32_t lhs, uint32_t rhs); +uint32_t EmitLogicalAndValue(EmitterState& state, uint32_t lhs, uint32_t rhs); -uint32_t EmitFSelectValue(EmitterState* state, uint32_t cond, uint32_t true_value, +uint32_t EmitFSelectValue(EmitterState& state, uint32_t cond, uint32_t true_value, uint32_t false_value); -uint32_t EmitFMulConstant(EmitterState* state, uint32_t value, uint32_t bits); +uint32_t EmitFMulConstant(EmitterState& state, uint32_t value, uint32_t bits); -CubeF32Values EmitCubeF32Values(EmitterState* state, const IR::Instruction& inst); +CubeF32Values EmitCubeF32Values(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitCubeIdF32(EmitterState* state, const CubeF32Values& cube); +uint32_t EmitCubeIdF32(EmitterState& state, const CubeF32Values& cube); -uint32_t EmitCubeScF32(EmitterState* state, const CubeF32Values& cube); +uint32_t EmitCubeScF32(EmitterState& state, const CubeF32Values& cube); -uint32_t EmitCubeTcF32(EmitterState* state, const CubeF32Values& cube); +uint32_t EmitCubeTcF32(EmitterState& state, const CubeF32Values& cube); -uint32_t EmitCubeMaF32(EmitterState* state, const CubeF32Values& cube); +uint32_t EmitCubeMaF32(EmitterState& state, const CubeF32Values& cube); -void EmitCubeF32(EmitterState* state, const IR::Instruction& inst); +void EmitCubeF32(EmitterState& state, const IR::Instruction& inst); -void EmitDot2AccF32F16(EmitterState* state, const IR::Instruction& inst); +void EmitDot2AccF32F16(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitPackedF16Lane(EmitterState* state, const IR::Operand& operand, bool high_lane); +uint32_t EmitPackedF16Lane(EmitterState& state, const IR::Operand& operand, bool high_lane); -void EmitCompareF16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitCompareF16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -uint32_t EmitPackedF16LaneBits(EmitterState* state, const IR::Operand& operand, bool high_lane); +uint32_t EmitPackedF16LaneBits(EmitterState& state, const IR::Operand& operand, bool high_lane); -uint32_t EmitF16BitsToF32(EmitterState* state, uint32_t bits); +uint32_t EmitF16BitsToF32(EmitterState& state, uint32_t bits); -uint32_t EmitPackLowF32ToF16Bits(EmitterState* state, uint32_t value); +uint32_t EmitPackLowF32ToF16Bits(EmitterState& state, uint32_t value); -void EmitPackB32F16(EmitterState* state, const IR::Instruction& inst); +void EmitPackB32F16(EmitterState& state, const IR::Instruction& inst); -F16Class EmitClassifyF16Bits(EmitterState* state, uint32_t value); +F16Class EmitClassifyF16Bits(EmitterState& state, uint32_t value); -uint32_t EmitNegativeNumericF16Bool(EmitterState* state, const F16Class& cls); +uint32_t EmitNegativeNumericF16Bool(EmitterState& state, const F16Class& cls); -uint32_t EmitRcpF16Bits(EmitterState* state, uint32_t bits); +uint32_t EmitRcpF16Bits(EmitterState& state, uint32_t bits); -uint32_t EmitSqrtF16Bits(EmitterState* state, uint32_t bits); +uint32_t EmitSqrtF16Bits(EmitterState& state, uint32_t bits); -uint32_t EmitRsqF16Bits(EmitterState* state, uint32_t bits); +uint32_t EmitRsqF16Bits(EmitterState& state, uint32_t bits); -uint32_t EmitLog2F16Bits(EmitterState* state, uint32_t bits); +uint32_t EmitLog2F16Bits(EmitterState& state, uint32_t bits); -uint32_t EmitExp2F16Bits(EmitterState* state, uint32_t bits); +uint32_t EmitExp2F16Bits(EmitterState& state, uint32_t bits); -void EmitSpecialF16(EmitterState* state, const IR::Instruction& inst); +void EmitSpecialF16(EmitterState& state, const IR::Instruction& inst); -void EmitBinaryF16(EmitterState* state, const IR::Instruction& inst, uint32_t opcode); +void EmitBinaryF16(EmitterState& state, const IR::Instruction& inst, uint32_t opcode); -void EmitFmaF16(EmitterState* state, const IR::Instruction& inst); +void EmitFmaF16(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitMinMaxF16Bits(EmitterState* state, uint32_t lhs, uint32_t rhs, bool max_value); +uint32_t EmitMinMaxF16Bits(EmitterState& state, uint32_t lhs, uint32_t rhs, bool max_value); -void EmitMinMaxF16(EmitterState* state, const IR::Instruction& inst, bool max_value); +void EmitMinMaxF16(EmitterState& state, const IR::Instruction& inst, bool max_value); -uint32_t EmitMinMax3F16Bits(EmitterState* state, uint32_t src0, uint32_t src1, uint32_t src2, +uint32_t EmitMinMax3F16Bits(EmitterState& state, uint32_t src0, uint32_t src1, uint32_t src2, bool max_value); -void EmitMinMax3F16(EmitterState* state, const IR::Instruction& inst, bool max_value); +void EmitMinMax3F16(EmitterState& state, const IR::Instruction& inst, bool max_value); -uint32_t EmitF16BitsEqualBool(EmitterState* state, uint32_t lhs, uint32_t rhs); +uint32_t EmitF16BitsEqualBool(EmitterState& state, uint32_t lhs, uint32_t rhs); -uint32_t EmitAnyNanF16Bool(EmitterState* state, uint32_t src0, uint32_t src1, uint32_t src2); +uint32_t EmitAnyNanF16Bool(EmitterState& state, uint32_t src0, uint32_t src1, uint32_t src2); -void EmitMed3F16(EmitterState* state, const IR::Instruction& inst); +void EmitMed3F16(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitPackedMinMaxF16(EmitterState* state, const IR::Instruction& inst, bool max_value); +uint32_t EmitPackedMinMaxF16(EmitterState& state, const IR::Instruction& inst, bool max_value); -uint32_t EmitPackedF16BinaryLane(EmitterState* state, const IR::Instruction& inst, bool high_lane, +uint32_t EmitPackedF16BinaryLane(EmitterState& state, const IR::Instruction& inst, bool high_lane, uint32_t opcode); -uint32_t EmitPackedF16FmaLane(EmitterState* state, const IR::Instruction& inst, bool high_lane); +uint32_t EmitPackedF16FmaLane(EmitterState& state, const IR::Instruction& inst, bool high_lane); -void EmitPackedF16(EmitterState* state, const IR::Instruction& inst); +void EmitPackedF16(EmitterState& state, const IR::Instruction& inst); -void EmitPackedInteger16(EmitterState* state, const IR::Instruction& inst); +void EmitPackedInteger16(EmitterState& state, const IR::Instruction& inst); -void EmitMadMixF16(EmitterState* state, const IR::Instruction& inst); +void EmitMadMixF16(EmitterState& state, const IR::Instruction& inst); -void EmitMinMax3F32(EmitterState* state, const IR::Instruction& inst, bool max_value); +void EmitMinMax3F32(EmitterState& state, const IR::Instruction& inst, bool max_value); -void EmitMed3F32(EmitterState* state, const IR::Instruction& inst); +void EmitMed3F32(EmitterState& state, const IR::Instruction& inst); -uint32_t EmitExportComponentF32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitExportComponentF32(EmitterState& state, const IR::Instruction& inst, uint32_t component); -uint32_t EmitExportVec4F32(EmitterState* state, const IR::Instruction& inst); +uint32_t EmitExportVec4F32(EmitterState& state, const IR::Instruction& inst); bool ExportWritesData(const IR::Instruction& inst); -void EmitExport(EmitterState* state, const IR::Instruction& inst); +void EmitExport(EmitterState& state, const IR::Instruction& inst); bool ExportUsesPixelValidMask(const EmitterState& state, const IR::Instruction& inst); -void EmitKillIfBoolFalse(EmitterState* state, uint32_t active); +void EmitKillIfBoolFalse(EmitterState& state, uint32_t active); -void EmitUpdatePixelValidMask(EmitterState* state); +void EmitUpdatePixelValidMask(EmitterState& state); -void EmitKillIfPixelValidMaskInactive(EmitterState* state); +void EmitKillIfPixelValidMaskInactive(EmitterState& state); -void ComputeReachableBlocks(EmitterState* state, const IR::Program& program); +void ComputeReachableBlocks(EmitterState& state, const IR::Program& program); -void AllocateBlockLabels(EmitterState* state, const IR::Program& program); +void AllocateBlockLabels(EmitterState& state, const IR::Program& program); -void AllocateDispatcherState(EmitterState* state, const IR::Program& program); +void AllocateDispatcherState(EmitterState& state, const IR::Program& program); uint32_t BlockLabel(const EmitterState& state, uint32_t block_id); -uint32_t EmitBranchCondition(EmitterState* state, CFG::BranchCondition condition); +uint32_t EmitBranchCondition(EmitterState& state, CFG::BranchCondition condition); -void EmitStructuredPrefix(EmitterState* state, const CFG::Terminator& term); +void EmitStructuredPrefix(EmitterState& state, const CFG::Terminator& term); -void EmitReturn(EmitterState* state); +void EmitReturn(EmitterState& state); -void EmitTerminator(EmitterState* state, const CFG::Terminator& term); +void EmitTerminator(EmitterState& state, const CFG::Terminator& term); uint32_t InitialRegisterValue(const EmitterState& state, IR::Register reg); -void EmitRegisterVariables(EmitterState* state); +void EmitRegisterVariables(EmitterState& state); -void EmitComputeInputRegisters(EmitterState* state); +void EmitComputeInputRegisters(EmitterState& state); -void EmitPixelInputRegisters(EmitterState* state); +void EmitPixelInputRegisters(EmitterState& state); -void EmitInstruction(EmitterState* state, const IR::Instruction& inst); +void EmitInstruction(EmitterState& state, const IR::Instruction& inst); -uint32_t DispatcherTargetValue(EmitterState* state, uint32_t block_id); +uint32_t DispatcherTargetValue(EmitterState& state, uint32_t block_id); -void EmitDispatcherStoreTarget(EmitterState* state, uint32_t block_id); +void EmitDispatcherStoreTarget(EmitterState& state, uint32_t block_id); -void EmitDispatcherExit(EmitterState* state); +void EmitDispatcherExit(EmitterState& state); -void EmitDispatcherTerminator(EmitterState* state, const CFG::Terminator& term); +void EmitDispatcherTerminator(EmitterState& state, const CFG::Terminator& term); -void EmitDispatcherSwitch(EmitterState* state, const IR::Program& program); +void EmitDispatcherSwitch(EmitterState& state, const IR::Program& program); -void EmitDispatcherBlocks(EmitterState* state, const IR::Program& program); +void EmitDispatcherBlocks(EmitterState& state, const IR::Program& program); -void EmitDispatcherLoopTail(EmitterState* state); +void EmitDispatcherLoopTail(EmitterState& state); -void EmitDispatcherFunction(EmitterState* state, const IR::Program& program); +void EmitDispatcherFunction(EmitterState& state, const IR::Program& program); -void EmitFunction(EmitterState* state, const IR::Program& program); +void EmitFunction(EmitterState& state, const IR::Program& program); // These templates accept local lambdas from several emitter translation units. template -void EmitIfCondition(EmitterState* state, uint32_t condition, Fn&& fn) { +void EmitIfCondition(EmitterState& state, uint32_t condition, Fn&& fn) { if (condition == 0) { fn(); return; } - const auto then_label = state->builder.AllocateId(); - const auto merge_label = state->builder.AllocateId(); - state->builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); - state->builder.AddFunction({OpBranchConditional, condition, then_label, merge_label}); - state->builder.AddFunction({OpLabel, then_label}); + const auto then_label = state.builder.AllocateId(); + const auto merge_label = state.builder.AllocateId(); + state.builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); + state.builder.AddFunction({OpBranchConditional, condition, then_label, merge_label}); + state.builder.AddFunction({OpLabel, then_label}); fn(); - state->builder.AddFunction({OpBranch, merge_label}); - state->builder.AddFunction({OpLabel, merge_label}); + state.builder.AddFunction({OpBranch, merge_label}); + state.builder.AddFunction({OpLabel, merge_label}); } template -uint32_t EmitValueOrZeroIfCondition(EmitterState* state, uint32_t condition, Fn&& fn) { +uint32_t EmitValueOrZeroIfCondition(EmitterState& state, uint32_t condition, Fn&& fn) { if (condition == 0) { return fn(); } - const auto then_label = state->builder.AllocateId(); - const auto else_label = state->builder.AllocateId(); - const auto merge_label = state->builder.AllocateId(); - state->builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); - state->builder.AddFunction({OpBranchConditional, condition, then_label, else_label}); - state->builder.AddFunction({OpLabel, then_label}); + const auto then_label = state.builder.AllocateId(); + const auto else_label = state.builder.AllocateId(); + const auto merge_label = state.builder.AllocateId(); + state.builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); + state.builder.AddFunction({OpBranchConditional, condition, then_label, else_label}); + state.builder.AddFunction({OpLabel, then_label}); const auto then_value = fn(); - state->builder.AddFunction({OpBranch, merge_label}); - state->builder.AddFunction({OpLabel, else_label}); - state->builder.AddFunction({OpBranch, merge_label}); - state->builder.AddFunction({OpLabel, merge_label}); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpPhi, state->uint_type, value, then_value, then_label, - ConstantU32(state, 0), else_label}); + state.builder.AddFunction({OpBranch, merge_label}); + state.builder.AddFunction({OpLabel, else_label}); + state.builder.AddFunction({OpBranch, merge_label}); + state.builder.AddFunction({OpLabel, merge_label}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpPhi, state.uint_type, value, then_value, then_label, ConstantU32(state, 0), else_label}); return value; } template -void EmitGuardedByExec(EmitterState* state, Fn&& fn) { - const auto then_label = state->builder.AllocateId(); - const auto merge_label = state->builder.AllocateId(); +void EmitGuardedByExec(EmitterState& state, Fn&& fn) { + const auto then_label = state.builder.AllocateId(); + const auto merge_label = state.builder.AllocateId(); const auto condition = EmitExecActiveBool(state); - state->builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); - state->builder.AddFunction({OpBranchConditional, condition, then_label, merge_label}); - state->builder.AddFunction({OpLabel, then_label}); + state.builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone}); + state.builder.AddFunction({OpBranchConditional, condition, then_label, merge_label}); + state.builder.AddFunction({OpLabel, then_label}); fn(); - state->builder.AddFunction({OpBranch, merge_label}); - state->builder.AddFunction({OpLabel, merge_label}); + state.builder.AddFunction({OpBranch, merge_label}); + state.builder.AddFunction({OpLabel, merge_label}); } } // namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterMemory.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterMemory.cpp index 1ed9a4f57..4a46dd199 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterMemory.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterMemory.cpp @@ -2,61 +2,61 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { -uint32_t EmitDppWriteActiveBool(EmitterState* state, const IR::Operand& dst) { +uint32_t EmitDppWriteActiveBool(EmitterState& state, const IR::Operand& dst) { const auto exec_active = EmitExecActiveBool(state); if (!dst.dpp) { return exec_active; } const auto subid = EmitSubgroupLocalInvocationId(state); - const auto bank_shift = state->builder.AllocateId(); - const auto row_shift = state->builder.AllocateId(); - const auto bank = state->builder.AllocateId(); - const auto row = state->builder.AllocateId(); - const auto bank_bit = state->builder.AllocateId(); - const auto row_bit = state->builder.AllocateId(); - const auto bank_hit = state->builder.AllocateId(); - const auto row_hit = state->builder.AllocateId(); - const auto bank_active = state->builder.AllocateId(); - const auto row_active = state->builder.AllocateId(); - const auto dpp_active = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); + const auto bank_shift = state.builder.AllocateId(); + const auto row_shift = state.builder.AllocateId(); + const auto bank = state.builder.AllocateId(); + const auto row = state.builder.AllocateId(); + const auto bank_bit = state.builder.AllocateId(); + const auto row_bit = state.builder.AllocateId(); + const auto bank_hit = state.builder.AllocateId(); + const auto row_hit = state.builder.AllocateId(); + const auto bank_active = state.builder.AllocateId(); + const auto row_active = state.builder.AllocateId(); + const auto dpp_active = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, bank_shift, subid, ConstantU32(state, 2)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, bank, bank_shift, ConstantU32(state, 3)}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, row_shift, subid, ConstantU32(state, 4)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, row, row_shift, ConstantU32(state, 3)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, bank_bit, ConstantU32(state, 1), bank}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, row_bit, ConstantU32(state, 1), row}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, bank_hit, + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, bank_shift, subid, ConstantU32(state, 2)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, bank, bank_shift, ConstantU32(state, 3)}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, row_shift, subid, ConstantU32(state, 4)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, row, row_shift, ConstantU32(state, 3)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, bank_bit, ConstantU32(state, 1), bank}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, row_bit, ConstantU32(state, 1), row}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, bank_hit, ConstantU32(state, dst.dpp_bank_mask), bank_bit}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, row_hit, ConstantU32(state, dst.dpp_row_mask), row_bit}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, bank_active, bank_hit, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, row_active, row_hit, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpLogicalAnd, state->bool_type, dpp_active, bank_active, row_active}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, row_hit, ConstantU32(state, dst.dpp_row_mask), row_bit}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, bank_active, bank_hit, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, row_active, row_hit, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpLogicalAnd, state.bool_type, dpp_active, bank_active, row_active}); uint32_t write_active = dpp_active; if (!dst.dpp_bound_ctrl) { const auto target = EmitDppTargetLane(state, dst.dpp_ctrl); - const auto bounded = state->builder.AllocateId(); - state->builder.AddFunction( - {OpLogicalAnd, state->bool_type, bounded, write_active, target.valid}); + const auto bounded = state.builder.AllocateId(); + state.builder.AddFunction( + {OpLogicalAnd, state.bool_type, bounded, write_active, target.valid}); write_active = bounded; } - state->builder.AddFunction({OpLogicalAnd, state->bool_type, ret, exec_active, write_active}); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, ret, exec_active, write_active}); return ret; } -uint32_t EmitSdwaDestinationMerge(EmitterState* state, uint32_t pointer, const IR::Operand& dst, +uint32_t EmitSdwaDestinationMerge(EmitterState& state, uint32_t pointer, const IR::Operand& dst, uint32_t value) { if (dst.sdwa_sel == 6u) { return value; @@ -70,73 +70,73 @@ uint32_t EmitSdwaDestinationMerge(EmitterState* state, uint32_t pointer, const I const auto value_mask = width == 16u ? 0x0000ffffu : 0x000000ffu; const auto field_mask = value_mask << offset; - const auto part = state->builder.AllocateId(); - const auto shifted = offset != 0u ? state->builder.AllocateId() : part; - const auto old_value = state->builder.AllocateId(); - const auto kept = state->builder.AllocateId(); - const auto merged = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, part, value, ConstantU32(state, value_mask)}); + const auto part = state.builder.AllocateId(); + const auto shifted = offset != 0u ? state.builder.AllocateId() : part; + const auto old_value = state.builder.AllocateId(); + const auto kept = state.builder.AllocateId(); + const auto merged = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, part, value, ConstantU32(state, value_mask)}); if (offset != 0u) { - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shifted, part, ConstantU32(state, offset)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shifted, part, ConstantU32(state, offset)}); } - state->builder.AddFunction({OpLoad, state->uint_type, old_value, pointer}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, kept, old_value, ConstantU32(state, ~field_mask)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, merged, kept, shifted}); + state.builder.AddFunction({OpLoad, state.uint_type, old_value, pointer}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, kept, old_value, ConstantU32(state, ~field_mask)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, merged, kept, shifted}); return merged; } -void EmitStoreU32(EmitterState* state, const IR::Operand& dst, uint32_t value) { +void EmitStoreU32(EmitterState& state, const IR::Operand& dst, uint32_t value) { if (dst.kind != IR::OperandKind::Register) { return; } - const auto pointer = PointerForRegister(*state, dst.reg); + const auto pointer = PointerForRegister(state, dst.reg); if (pointer != 0) { const auto store_value = EmitSdwaDestinationMerge(state, pointer, dst, value); const auto wave_value = - IsInactiveWave32ExecHigh(*state, dst.reg) ? ConstantU32(state, 0) : store_value; + IsInactiveWave32ExecHigh(state, dst.reg) ? ConstantU32(state, 0) : store_value; if (dst.reg.file == IR::RegisterFile::Vector) { - const auto old_value = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, old_value, pointer}); - state->builder.AddFunction({OpSelect, state->uint_type, selected, + const auto old_value = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, old_value, pointer}); + state.builder.AddFunction({OpSelect, state.uint_type, selected, EmitDppWriteActiveBool(state, dst), wave_value, old_value}); - state->builder.AddFunction({OpStore, pointer, selected}); + state.builder.AddFunction({OpStore, pointer, selected}); return; } - state->builder.AddFunction({OpStore, pointer, wave_value}); + state.builder.AddFunction({OpStore, pointer, wave_value}); } } -uint32_t EmitAddU32(EmitterState* state, uint32_t lhs, uint32_t rhs) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpIAdd, state->uint_type, ret, lhs, rhs}); +uint32_t EmitAddU32(EmitterState& state, uint32_t lhs, uint32_t rhs) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpIAdd, state.uint_type, ret, lhs, rhs}); return ret; } -uint32_t EmitBinaryU32(EmitterState* state, uint32_t opcode, uint32_t lhs, uint32_t rhs) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, ret, lhs, rhs}); +uint32_t EmitBinaryU32(EmitterState& state, uint32_t opcode, uint32_t lhs, uint32_t rhs) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, ret, lhs, rhs}); return ret; } -uint32_t EmitNotEqualZeroBool(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpINotEqual, state->bool_type, ret, value, ConstantU32(state, 0)}); +uint32_t EmitNotEqualZeroBool(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpINotEqual, state.bool_type, ret, value, ConstantU32(state, 0)}); return ret; } -uint32_t EmitSelectU32Value(EmitterState* state, uint32_t condition, uint32_t true_value, +uint32_t EmitSelectU32Value(EmitterState& state, uint32_t condition, uint32_t true_value, uint32_t false_value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, condition, true_value, false_value}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, condition, true_value, false_value}); return ret; } -uint32_t EmitByteAddress(EmitterState* state, const IR::Instruction& inst, uint32_t first_src, +uint32_t EmitByteAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count) { uint32_t address = ConstantU32(state, inst.memory.offset); for (uint32_t i = 0; i < src_count; i++) { @@ -148,21 +148,21 @@ uint32_t EmitByteAddress(EmitterState* state, const IR::Instruction& inst, uint3 uint32_t StorageBufferPackedStride(const EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc) { (void)use_pc; - if (mem.resource >= state.program->info.buffers.size()) { + if (mem.resource >= state.program.info.buffers.size()) { ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::Buffers, mem.resource, "buffer specialization is missing"); } - return state.program->info.buffers[mem.resource].packed_stride; + return state.program.info.buffers[mem.resource].packed_stride; } uint32_t StorageBufferFormat(const EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc) { (void)use_pc; - if (mem.resource >= state.program->info.buffers.size()) { + if (mem.resource >= state.program.info.buffers.size()) { ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::Buffers, mem.resource, "buffer specialization is missing"); } - return state.program->info.buffers[mem.resource].descriptor_format; + return state.program.info.buffers[mem.resource].descriptor_format; } bool ShouldApplyBufferAddTid(const IR::Instruction& inst) { @@ -170,7 +170,7 @@ bool ShouldApplyBufferAddTid(const IR::Instruction& inst) { !inst.memory.typed && inst.op == IR::Opcode::BufferStoreDword; } -uint32_t EmitBufferIndexWithAddTid(EmitterState* state, const IR::Instruction& inst, uint32_t index, +uint32_t EmitBufferIndexWithAddTid(EmitterState& state, const IR::Instruction& inst, uint32_t index, uint32_t packed) { if (!ShouldApplyBufferAddTid(inst)) { return index; @@ -187,15 +187,15 @@ uint32_t EmitBufferIndexWithAddTid(EmitterState* state, const IR::Instruction& i return EmitSelectU32Value(state, add_tid, tid_index, index); } -uint32_t EmitOptionalLogicalAndBool(EmitterState* state, uint32_t lhs, uint32_t rhs) { +uint32_t EmitOptionalLogicalAndBool(EmitterState& state, uint32_t lhs, uint32_t rhs) { if (lhs == 0) { return rhs; } if (rhs == 0) { return lhs; } - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, ret, lhs, rhs}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, ret, lhs, rhs}); return ret; } @@ -210,10 +210,10 @@ bool IsStorageBufferMemoryKind(IR::ResourceKind kind) { } } -uint32_t EmitBufferAddressFromParts(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst, uint32_t index, uint32_t offset, uint32_t soffset) { const auto& mem = inst.memory; - const auto packed = ConstantU32(state, StorageBufferPackedStride(*state, mem, inst.pc)); + const auto packed = ConstantU32(state, StorageBufferPackedStride(state, mem, inst.pc)); const auto address_index = EmitBufferIndexWithAddTid(state, inst, index, packed); const auto stride = EmitBinaryU32(state, OpBitwiseAnd, packed, ConstantU32(state, 0x3fffu)); const auto swizzle_bit = @@ -222,9 +222,9 @@ uint32_t EmitBufferAddressFromParts(EmitterState* state, const IR::Instruction& ConstantU32(state, 1)); const auto stride_nonzero = EmitNotEqualZeroBool(state, stride); const auto swizzle_nonzero = EmitNotEqualZeroBool(state, swizzle_bit); - const auto use_swizzle = state->builder.AllocateId(); - state->builder.AddFunction( - {OpLogicalAnd, state->bool_type, use_swizzle, swizzle_nonzero, stride_nonzero}); + const auto use_swizzle = state.builder.AllocateId(); + state.builder.AddFunction( + {OpLogicalAnd, state.bool_type, use_swizzle, swizzle_nonzero, stride_nonzero}); const auto index_stride_enum = EmitBinaryU32(state, OpBitwiseAnd, @@ -255,7 +255,7 @@ uint32_t EmitBufferAddressFromParts(EmitterState* state, const IR::Instruction& return EmitAddU32(state, buffer_offset, soffset); } -uint32_t EmitBufferByteAddress(EmitterState* state, const IR::Instruction& inst, uint32_t first_src, +uint32_t EmitBufferByteAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count) { const auto end = first_src + src_count; auto cursor = first_src; @@ -283,10 +283,10 @@ bool IsFlatMemoryKind(IR::ResourceKind kind) { kind == IR::ResourceKind::Scratch; } -uint32_t EmitRelativeAddress(EmitterState* state, const IR::Instruction& inst, uint32_t first_src, +uint32_t EmitRelativeAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count, bool vector_only = true, bool align_components = false) { - const auto delta = state->program->info.addresses[inst.memory.resource].specialized_base; + const auto delta = state.program.info.addresses[inst.memory.resource].specialized_base; auto immediate = static_cast(inst.memory.offset); if (align_components) { immediate = static_cast(static_cast(immediate) & ~3u); @@ -303,63 +303,63 @@ uint32_t EmitRelativeAddress(EmitterState* state, const IR::Instruction& inst, u value = EmitBinaryU32(state, OpBitwiseAnd, value, ConstantU32(state, ~3u)); } const auto next = EmitAddU32(state, low, value); - const auto carry = state->builder.AllocateId(); - state->builder.AddFunction({OpULessThan, state->bool_type, carry, next, low}); + const auto carry = state.builder.AllocateId(); + state.builder.AddFunction({OpULessThan, state.bool_type, carry, next, low}); high = EmitAddU32( state, high, EmitSelectU32Value(state, carry, ConstantU32(state, 1), ConstantU32(state, 0))); low = next; } } - const auto valid = state->builder.AllocateId(); - state->builder.AddFunction({OpIEqual, state->bool_type, valid, high, ConstantU32(state, 0)}); + const auto valid = state.builder.AllocateId(); + state.builder.AddFunction({OpIEqual, state.bool_type, valid, high, ConstantU32(state, 0)}); return EmitSelectU32Value(state, valid, low, ConstantU32(state, UINT32_MAX)); } -uint32_t EmitFlatVirtualAddress(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitFlatVirtualAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count) { - if (state->resources == nullptr || inst.memory.resource >= state->resources->addresses.size() || + if (inst.memory.resource >= state.resources.addresses.size() || src_count < 2) { - ExitDescriptorBindingFailure(*state, IR::DescriptorBindingKind::AddressMemory, + ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::AddressMemory, inst.memory.resource, "flat address snapshot is missing"); } const auto low0 = EmitValueLoad(state, inst.src[first_src]); const auto high0 = EmitValueLoad(state, inst.src[first_src + 1u]); const auto immediate = ConstantU32(state, inst.memory.offset); const auto low = EmitAddU32(state, low0, immediate); - const auto carry_bool = state->builder.AllocateId(); - state->builder.AddFunction({OpULessThan, state->bool_type, carry_bool, low, low0}); + const auto carry_bool = state.builder.AllocateId(); + state.builder.AddFunction({OpULessThan, state.bool_type, carry_bool, low, low0}); const auto carry = EmitSelectU32Value(state, carry_bool, ConstantU32(state, 1), ConstantU32(state, 0)); const auto immediate_high = ConstantU32(state, (inst.memory.offset & 0x80000000u) != 0 ? UINT32_MAX : 0u); const auto high = EmitAddU32(state, EmitAddU32(state, high0, immediate_high), carry); - const auto base = state->program->info.addresses[inst.memory.resource].specialized_base; + const auto base = state.program.info.addresses[inst.memory.resource].specialized_base; const auto base_low = static_cast(base); const auto base_high = static_cast(base >> 32u); const auto relative_low = EmitBinaryU32(state, OpISub, low, ConstantU32(state, base_low)); - const auto borrow_bool = state->builder.AllocateId(); - state->builder.AddFunction( - {OpULessThan, state->bool_type, borrow_bool, low, ConstantU32(state, base_low)}); + const auto borrow_bool = state.builder.AllocateId(); + state.builder.AddFunction( + {OpULessThan, state.bool_type, borrow_bool, low, ConstantU32(state, base_low)}); const auto borrow = EmitSelectU32Value(state, borrow_bool, ConstantU32(state, 1), ConstantU32(state, 0)); const auto relative_high = EmitBinaryU32( state, OpISub, EmitBinaryU32(state, OpISub, high, ConstantU32(state, base_high)), borrow); - const auto valid = state->builder.AllocateId(); - state->builder.AddFunction( - {OpIEqual, state->bool_type, valid, relative_high, ConstantU32(state, 0)}); + const auto valid = state.builder.AllocateId(); + state.builder.AddFunction( + {OpIEqual, state.bool_type, valid, relative_high, ConstantU32(state, 0)}); return EmitSelectU32Value(state, valid, relative_low, ConstantU32(state, UINT32_MAX)); } -uint32_t EmitMemoryByteAddress(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitMemoryByteAddress(EmitterState& state, const IR::Instruction& inst, const IR::MemoryInfo& mem, uint32_t first_src, uint32_t src_count) { if (mem.kind == IR::ResourceKind::Buffer) { return EmitBufferByteAddress(state, inst, first_src, src_count); } if (mem.kind == IR::ResourceKind::Flat || ((mem.kind == IR::ResourceKind::Global || mem.kind == IR::ResourceKind::Scratch) && - state->program->info.addresses[mem.resource].source == IR::ScalarProvenance::Unknown)) { + state.program.info.addresses[mem.resource].source == IR::ScalarProvenance::Unknown)) { return EmitFlatVirtualAddress(state, inst, first_src, src_count); } if (mem.kind == IR::ResourceKind::Global || mem.kind == IR::ResourceKind::Scratch) { @@ -368,108 +368,108 @@ uint32_t EmitMemoryByteAddress(EmitterState* state, const IR::Instruction& inst, return EmitByteAddress(state, inst, first_src, src_count); } -uint32_t EmitDwordIndex(EmitterState* state, const IR::Instruction& inst, uint32_t first_src, +uint32_t EmitDwordIndex(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count) { const auto address = EmitByteAddress(state, inst, first_src, src_count); - const auto index = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, index, address, ConstantU32(state, 2)}); + const auto index = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, index, address, ConstantU32(state, 2)}); return index; } -uint32_t EmitMemoryDwordIndex(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitMemoryDwordIndex(EmitterState& state, const IR::Instruction& inst, const IR::MemoryInfo& mem, uint32_t first_src, uint32_t src_count) { const auto address = EmitMemoryByteAddress(state, inst, mem, first_src, src_count); - const auto index = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, index, address, ConstantU32(state, 2)}); + const auto index = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, index, address, ConstantU32(state, 2)}); return index; } DescriptorResourceBinding -StorageBufferBindingForMemory(EmitterState* state, const IR::MemoryInfo& mem, uint32_t use_pc) { +StorageBufferBindingForMemory(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc) { (void)use_pc; const auto binding = - ResourceForDescriptor(*state, IR::DescriptorBindingKind::Buffers, mem.resource); - if (state->storage_buffer_variable == 0) { - ExitDescriptorBindingFailure(*state, IR::DescriptorBindingKind::Buffers, mem.resource, + ResourceForDescriptor(state, IR::DescriptorBindingKind::Buffers, mem.resource); + if (state.storage_buffer_variable == 0) { + ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::Buffers, mem.resource, "storage buffer descriptor array was not emitted"); } return binding; } -uint32_t EmitStorageBufferObjectPointer(EmitterState* state, const IR::MemoryInfo& mem, +uint32_t EmitStorageBufferObjectPointer(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc) { if (IsFlatMemoryKind(mem.kind)) { - if (state->address_memory_variable == 0) { - ExitDescriptorBindingFailure(*state, IR::DescriptorBindingKind::AddressMemory, + if (state.address_memory_variable == 0) { + ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::AddressMemory, mem.resource, "address memory binding was not emitted"); } const auto binding = - ResourceForDescriptor(*state, IR::DescriptorBindingKind::AddressMemory, mem.resource); - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, state->ptr_storage_buffer, pointer, - state->address_memory_variable, + ResourceForDescriptor(state, IR::DescriptorBindingKind::AddressMemory, mem.resource); + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer, pointer, + state.address_memory_variable, ConstantU32(state, binding.array_index)}); return pointer; } const auto binding = StorageBufferBindingForMemory(state, mem, use_pc); - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, state->ptr_storage_buffer, pointer, - state->storage_buffer_variable, + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer, pointer, + state.storage_buffer_variable, ConstantU32(state, binding.array_index)}); return pointer; } -uint32_t EmitStorageBufferElementInBounds(EmitterState* state, const IR::MemoryInfo& mem, +uint32_t EmitStorageBufferElementInBounds(EmitterState& state, const IR::MemoryInfo& mem, uint32_t index, uint32_t use_pc) { const auto object = EmitStorageBufferObjectPointer(state, mem, use_pc); - const auto length = state->builder.AllocateId(); - const auto in_bounds = state->builder.AllocateId(); - state->builder.AddFunction({OpArrayLength, state->uint_type, length, object, 0}); - state->builder.AddFunction({OpULessThan, state->bool_type, in_bounds, index, length}); + const auto length = state.builder.AllocateId(); + const auto in_bounds = state.builder.AllocateId(); + state.builder.AddFunction({OpArrayLength, state.uint_type, length, object, 0}); + state.builder.AddFunction({OpULessThan, state.bool_type, in_bounds, index, length}); return in_bounds; } -uint32_t EmitStorageBufferElementPointer(EmitterState* state, const IR::MemoryInfo& mem, +uint32_t EmitStorageBufferElementPointer(EmitterState& state, const IR::MemoryInfo& mem, uint32_t index, uint32_t use_pc) { if (IsFlatMemoryKind(mem.kind)) { - if (state->address_memory_variable == 0) { - ExitDescriptorBindingFailure(*state, IR::DescriptorBindingKind::AddressMemory, + if (state.address_memory_variable == 0) { + ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::AddressMemory, mem.resource, "address memory binding was not emitted"); } const auto binding = - ResourceForDescriptor(*state, IR::DescriptorBindingKind::AddressMemory, mem.resource); - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction( - {OpAccessChain, state->ptr_storage_buffer_uint, pointer, state->address_memory_variable, + ResourceForDescriptor(state, IR::DescriptorBindingKind::AddressMemory, mem.resource); + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction( + {OpAccessChain, state.ptr_storage_buffer_uint, pointer, state.address_memory_variable, ConstantU32(state, binding.array_index), ConstantU32(state, 0), index}); return pointer; } const auto binding = StorageBufferBindingForMemory(state, mem, use_pc); - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction( - {OpAccessChain, state->ptr_storage_buffer_uint, pointer, state->storage_buffer_variable, + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction( + {OpAccessChain, state.ptr_storage_buffer_uint, pointer, state.storage_buffer_variable, ConstantU32(state, binding.array_index), ConstantU32(state, 0), index}); return pointer; } -uint32_t EmitLdsElementPointer(EmitterState* state, uint32_t index) { - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction( - {OpAccessChain, state->ptr_workgroup_uint, pointer, state->lds_variable, index}); +uint32_t EmitLdsElementPointer(EmitterState& state, uint32_t index) { + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction( + {OpAccessChain, state.ptr_workgroup_uint, pointer, state.lds_variable, index}); return pointer; } -uint32_t EmitLdsElementInBounds(EmitterState* state, uint32_t index) { - const auto in_bounds = state->builder.AllocateId(); - const auto dwords = state->needs_function_lds ? 8192u : 1024u; - state->builder.AddFunction( - {OpULessThan, state->bool_type, in_bounds, index, ConstantU32(state, dwords)}); +uint32_t EmitLdsElementInBounds(EmitterState& state, uint32_t index) { + const auto in_bounds = state.builder.AllocateId(); + const auto dwords = state.needs_function_lds ? 8192u : 1024u; + state.builder.AddFunction( + {OpULessThan, state.bool_type, in_bounds, index, ConstantU32(state, dwords)}); return in_bounds; } -uint32_t EmitMemoryElementPointer(EmitterState* state, const IR::MemoryInfo& mem, uint32_t index, +uint32_t EmitMemoryElementPointer(EmitterState& state, const IR::MemoryInfo& mem, uint32_t index, uint32_t use_pc) { if (mem.kind == IR::ResourceKind::Lds) { return EmitLdsElementPointer(state, index); @@ -480,15 +480,15 @@ uint32_t EmitMemoryElementPointer(EmitterState* state, const IR::MemoryInfo& mem return EmitStorageBufferElementPointer(state, mem, index, use_pc); } -uint32_t EmitMemoryLoadDwordValueU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitMemoryLoadDwordValueU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count) { auto mem = inst.memory; mem.kind = kind; const auto index = EmitMemoryDwordIndex(state, inst, mem, first_src, src_count); auto LoadFromPointer = [&](uint32_t pointer) { - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); return value; }; if (mem.kind == IR::ResourceKind::Lds) { @@ -509,13 +509,13 @@ uint32_t EmitMemoryLoadDwordValueU32(EmitterState* state, const IR::Instruction& return ConstantU32(state, 0); } -void EmitMemoryLoadU32(EmitterState* state, const IR::Instruction& inst, IR::ResourceKind kind, +void EmitMemoryLoadU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count) { const auto value = EmitMemoryLoadDwordValueU32(state, inst, kind, first_src, src_count); EmitStoreU32(state, inst.dst, value); } -void EmitMemoryLoadDwordsU32(EmitterState* state, const IR::Instruction& inst, +void EmitMemoryLoadDwordsU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count) { const auto count = std::max(1u, inst.memory.data_dwords); if (count == 1u) { @@ -538,37 +538,37 @@ void EmitMemoryLoadDwordsU32(EmitterState* state, const IR::Instruction& inst, } } -uint32_t EmitMemoryLoadSubDwordValueU32(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitMemoryLoadSubDwordValueU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count, uint32_t data_bits, bool sign_extend) { auto mem = inst.memory; mem.kind = kind; const auto address = EmitMemoryByteAddress(state, inst, mem, first_src, src_count); - const auto index = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, index, address, ConstantU32(state, 2)}); + const auto index = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, index, address, ConstantU32(state, 2)}); auto LoadFromPointer = [&](uint32_t pointer) { - const auto word = state->builder.AllocateId(); - const auto byte_in_word = state->builder.AllocateId(); - const auto shift = state->builder.AllocateId(); - const auto shifted = state->builder.AllocateId(); - const auto masked = state->builder.AllocateId(); - const auto value = sign_extend ? state->builder.AllocateId() : masked; + const auto word = state.builder.AllocateId(); + const auto byte_in_word = state.builder.AllocateId(); + const auto shift = state.builder.AllocateId(); + const auto shifted = state.builder.AllocateId(); + const auto masked = state.builder.AllocateId(); + const auto value = sign_extend ? state.builder.AllocateId() : masked; const auto mask = data_bits == 8u ? 0xffu : 0xffffu; - state->builder.AddFunction({OpLoad, state->uint_type, word, pointer}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, byte_in_word, address, ConstantU32(state, 3)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shift, byte_in_word, ConstantU32(state, 3)}); - state->builder.AddFunction({OpShiftRightLogical, state->uint_type, shifted, word, shift}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, masked, shifted, ConstantU32(state, mask)}); + state.builder.AddFunction({OpLoad, state.uint_type, word, pointer}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, byte_in_word, address, ConstantU32(state, 3)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shift, byte_in_word, ConstantU32(state, 3)}); + state.builder.AddFunction({OpShiftRightLogical, state.uint_type, shifted, word, shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, masked, shifted, ConstantU32(state, mask)}); if (sign_extend) { - const auto left = state->builder.AllocateId(); + const auto left = state.builder.AllocateId(); const auto sign_shift = 32u - data_bits; - state->builder.AddFunction({OpShiftLeftLogical, state->uint_type, left, masked, + state.builder.AddFunction({OpShiftLeftLogical, state.uint_type, left, masked, ConstantU32(state, sign_shift)}); - state->builder.AddFunction({OpShiftRightArithmetic, state->uint_type, value, left, + state.builder.AddFunction({OpShiftRightArithmetic, state.uint_type, value, left, ConstantU32(state, sign_shift)}); } return value; @@ -591,7 +591,7 @@ uint32_t EmitMemoryLoadSubDwordValueU32(EmitterState* state, const IR::Instructi return ConstantU32(state, 0); } -void EmitMemoryLoadSubDwordU32(EmitterState* state, const IR::Instruction& inst, +void EmitMemoryLoadSubDwordU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count, uint32_t data_bits, bool sign_extend) { const auto value = EmitMemoryLoadSubDwordValueU32(state, inst, kind, first_src, src_count, @@ -599,7 +599,7 @@ void EmitMemoryLoadSubDwordU32(EmitterState* state, const IR::Instruction& inst, EmitStoreU32(state, inst.dst, value); } -void EmitMemoryStoreU32(EmitterState* state, const IR::Instruction& inst, IR::ResourceKind kind, +void EmitMemoryStoreU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count) { auto store_inst = inst; store_inst.memory.kind = kind; @@ -616,50 +616,50 @@ void EmitMemoryStoreU32(EmitterState* state, const IR::Instruction& inst, IR::Re } EmitIfCondition(state, in_bounds, [&]() { const auto pointer = EmitMemoryElementPointer(state, store_inst.memory, index, inst.pc); - state->builder.AddFunction({OpStore, pointer, value}); + state.builder.AddFunction({OpStore, pointer, value}); }); } template -void EmitAtomicUpdateU32(EmitterState* state, uint32_t pointer, IR::ResourceKind kind, +void EmitAtomicUpdateU32(EmitterState& state, uint32_t pointer, IR::ResourceKind kind, Fn&& desired_value) { const auto scope = kind == IR::ResourceKind::Lds ? ScopeWorkgroup : ScopeDevice; const auto memory = kind == IR::ResourceKind::Lds ? MemorySemanticsWorkgroupMemory : MemorySemanticsUniformMemory; - const auto preheader = state->builder.AllocateId(); - const auto header = state->builder.AllocateId(); - const auto continue_label = state->builder.AllocateId(); - const auto merge = state->builder.AllocateId(); - const auto initial = state->builder.AllocateId(); - const auto observed = state->builder.AllocateId(); - const auto exchanged = state->builder.AllocateId(); + const auto preheader = state.builder.AllocateId(); + const auto header = state.builder.AllocateId(); + const auto continue_label = state.builder.AllocateId(); + const auto merge = state.builder.AllocateId(); + const auto initial = state.builder.AllocateId(); + const auto observed = state.builder.AllocateId(); + const auto exchanged = state.builder.AllocateId(); - state->builder.AddFunction({OpBranch, preheader}); - state->builder.AddFunction({OpLabel, preheader}); - state->builder.AddFunction({OpAtomicLoad, state->uint_type, initial, pointer, + state.builder.AddFunction({OpBranch, preheader}); + state.builder.AddFunction({OpLabel, preheader}); + state.builder.AddFunction({OpAtomicLoad, state.uint_type, initial, pointer, ConstantU32(state, scope), ConstantU32(state, MemorySemanticsNone)}); - state->builder.AddFunction({OpBranch, header}); - state->builder.AddFunction({OpLabel, header}); - state->builder.AddFunction( - {OpPhi, state->uint_type, observed, initial, preheader, exchanged, continue_label}); + state.builder.AddFunction({OpBranch, header}); + state.builder.AddFunction({OpLabel, header}); + state.builder.AddFunction( + {OpPhi, state.uint_type, observed, initial, preheader, exchanged, continue_label}); const auto desired = desired_value(observed); - state->builder.AddFunction({OpAtomicCompareExchange, state->uint_type, exchanged, pointer, + state.builder.AddFunction({OpAtomicCompareExchange, state.uint_type, exchanged, pointer, ConstantU32(state, scope), ConstantU32(state, MemorySemanticsNone), ConstantU32(state, MemorySemanticsNone), desired, observed}); - const auto success = state->builder.AllocateId(); - state->builder.AddFunction({OpIEqual, state->bool_type, success, exchanged, observed}); - state->builder.AddFunction({OpLoopMerge, merge, continue_label, LoopControlNone}); - state->builder.AddFunction({OpBranchConditional, success, merge, continue_label}); - state->builder.AddFunction({OpLabel, continue_label}); - state->builder.AddFunction({OpBranch, header}); - state->builder.AddFunction({OpLabel, merge}); + const auto success = state.builder.AllocateId(); + state.builder.AddFunction({OpIEqual, state.bool_type, success, exchanged, observed}); + state.builder.AddFunction({OpLoopMerge, merge, continue_label, LoopControlNone}); + state.builder.AddFunction({OpBranchConditional, success, merge, continue_label}); + state.builder.AddFunction({OpLabel, continue_label}); + state.builder.AddFunction({OpBranch, header}); + state.builder.AddFunction({OpLabel, merge}); const auto semantics = MemorySemanticsAcquireRelease | memory; - state->builder.AddFunction( + state.builder.AddFunction( {OpMemoryBarrier, ConstantU32(state, scope), ConstantU32(state, semantics)}); } -void EmitMemoryStoreSubDwordU32(EmitterState* state, const IR::Instruction& inst, +void EmitMemoryStoreSubDwordU32(EmitterState& state, const IR::Instruction& inst, IR::ResourceKind kind, uint32_t first_src, uint32_t src_count, uint32_t data_bits) { auto store_inst = inst; @@ -667,9 +667,9 @@ void EmitMemoryStoreSubDwordU32(EmitterState* state, const IR::Instruction& inst uint32_t in_bounds = 0; const auto address = EmitMemoryByteAddress(state, store_inst, store_inst.memory, first_src, src_count); - const auto index = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, index, address, ConstantU32(state, 2)}); + const auto index = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, index, address, ConstantU32(state, 2)}); if (IsStorageBufferMemoryKind(store_inst.memory.kind)) { in_bounds = EmitOptionalLogicalAndBool( state, in_bounds, @@ -680,39 +680,39 @@ void EmitMemoryStoreSubDwordU32(EmitterState* state, const IR::Instruction& inst EmitIfCondition(state, in_bounds, [&]() { const auto pointer = EmitMemoryElementPointer(state, store_inst.memory, index, inst.pc); const auto value = EmitValueLoad(state, inst.src[0]); - const auto byte_in_word = state->builder.AllocateId(); - const auto shift = state->builder.AllocateId(); - const auto field_mask = state->builder.AllocateId(); - const auto value_masked = state->builder.AllocateId(); - const auto value_shifted = state->builder.AllocateId(); + const auto byte_in_word = state.builder.AllocateId(); + const auto shift = state.builder.AllocateId(); + const auto field_mask = state.builder.AllocateId(); + const auto value_masked = state.builder.AllocateId(); + const auto value_shifted = state.builder.AllocateId(); const auto mask = data_bits == 8u ? 0xffu : 0xffffu; - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, byte_in_word, address, ConstantU32(state, 3)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shift, byte_in_word, ConstantU32(state, 3)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, field_mask, ConstantU32(state, mask), shift}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, value_masked, value, ConstantU32(state, mask)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, value_shifted, value_masked, shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, byte_in_word, address, ConstantU32(state, 3)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shift, byte_in_word, ConstantU32(state, 3)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, field_mask, ConstantU32(state, mask), shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, value_masked, value, ConstantU32(state, mask)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, value_shifted, value_masked, shift}); auto Merge = [&](uint32_t word) { - const auto inverted = state->builder.AllocateId(); - const auto cleared = state->builder.AllocateId(); - const auto merged = state->builder.AllocateId(); - state->builder.AddFunction({OpNot, state->uint_type, inverted, field_mask}); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, cleared, word, inverted}); - state->builder.AddFunction( - {OpBitwiseOr, state->uint_type, merged, cleared, value_shifted}); + const auto inverted = state.builder.AllocateId(); + const auto cleared = state.builder.AllocateId(); + const auto merged = state.builder.AllocateId(); + state.builder.AddFunction({OpNot, state.uint_type, inverted, field_mask}); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, cleared, word, inverted}); + state.builder.AddFunction( + {OpBitwiseOr, state.uint_type, merged, cleared, value_shifted}); return merged; }; if (store_inst.memory.kind == IR::ResourceKind::Lds || store_inst.memory.kind == IR::ResourceKind::Gds) { EmitAtomicUpdateU32(state, pointer, store_inst.memory.kind, Merge); } else { - const auto word = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, word, pointer}); - state->builder.AddFunction({OpStore, pointer, Merge(word)}); + const auto word = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, word, pointer}); + state.builder.AddFunction({OpStore, pointer, Merge(word)}); } }); } @@ -750,37 +750,37 @@ IR::Instruction WithFormatComponentByteOffset(const IR::Instruction& inst, return rebased; } -uint32_t EmitTBufferBitcastF32ToU32(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, ret, value}); +uint32_t EmitTBufferBitcastF32ToU32(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, ret, value}); return ret; } -uint32_t EmitTBufferBitcastU32ToF32(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->float_type, ret, value}); +uint32_t EmitTBufferBitcastU32ToF32(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.float_type, ret, value}); return ret; } -uint32_t EmitTBufferBitcastU32ToI32(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, ret, value}); +uint32_t EmitTBufferBitcastU32ToI32(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, ret, value}); return ret; } -uint32_t EmitTBufferCompareU32Constant(EmitterState* state, uint32_t opcode, uint32_t value, +uint32_t EmitTBufferCompareU32Constant(EmitterState& state, uint32_t opcode, uint32_t value, uint32_t constant) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {opcode, state->bool_type, ret, value, ConstantU32(state, constant)}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {opcode, state.bool_type, ret, value, ConstantU32(state, constant)}); return ret; } -uint32_t EmitTBufferSelectF32(EmitterState* state, uint32_t condition, uint32_t true_value, +uint32_t EmitTBufferSelectF32(EmitterState& state, uint32_t condition, uint32_t true_value, uint32_t false_value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->float_type, ret, condition, true_value, false_value}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.float_type, ret, condition, true_value, false_value}); return ret; } @@ -789,7 +789,7 @@ bool IsSignedFormatComponent(Format::ComponentType type) { type == Format::ComponentType::Sscaled; } -uint32_t EmitExtractFormatFieldU32(EmitterState* state, uint32_t raw_word, uint32_t offset, +uint32_t EmitExtractFormatFieldU32(EmitterState& state, uint32_t raw_word, uint32_t offset, uint32_t bits, bool sign_extend) { if (bits == 32u && offset == 0u) { return raw_word; @@ -797,30 +797,30 @@ uint32_t EmitExtractFormatFieldU32(EmitterState* state, uint32_t raw_word, uint3 if (sign_extend) { const auto signed_word = EmitTBufferBitcastU32ToI32(state, raw_word); - const auto extracted = state->builder.AllocateId(); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, extracted, signed_word, + const auto extracted = state.builder.AllocateId(); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, extracted, signed_word, ConstantU32(state, offset), ConstantU32(state, bits)}); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, ret, extracted}); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, ret, extracted}); return ret; } - const auto extracted = state->builder.AllocateId(); - state->builder.AddFunction({OpBitFieldUExtract, state->uint_type, extracted, raw_word, + const auto extracted = state.builder.AllocateId(); + state.builder.AddFunction({OpBitFieldUExtract, state.uint_type, extracted, raw_word, ConstantU32(state, offset), ConstantU32(state, bits)}); return extracted; } -uint32_t EmitHalfToF32Bits(EmitterState* state, uint32_t raw) { - const auto unpacked = state->builder.AllocateId(); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->vec2_float_type, unpacked, state->glsl_std450, GlslUnpackHalf2x16, raw}); - state->builder.AddFunction({OpCompositeExtract, state->float_type, value, unpacked, 0}); +uint32_t EmitHalfToF32Bits(EmitterState& state, uint32_t raw) { + const auto unpacked = state.builder.AllocateId(); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, raw}); + state.builder.AddFunction({OpCompositeExtract, state.float_type, value, unpacked, 0}); return EmitTBufferBitcastF32ToU32(state, value); } -uint32_t EmitUFloatToF32Bits(EmitterState* state, uint32_t raw, uint32_t bits) { +uint32_t EmitUFloatToF32Bits(EmitterState& state, uint32_t raw, uint32_t bits) { const auto mantissa_bits = bits == 11u ? 6u : 5u; const auto mantissa_mask = (1u << mantissa_bits) - 1u; const auto mantissa = @@ -842,11 +842,11 @@ uint32_t EmitUFloatToF32Bits(EmitterState* state, uint32_t raw, uint32_t bits) { EmitBinaryU32(state, OpBitwiseOr, ConstantU32(state, 0x7f800000u), mantissa_bits_32); const auto special = EmitTBufferBitcastU32ToF32(state, special_bits); - const auto mantissa_f32 = state->builder.AllocateId(); - const auto subnormal = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertUToF, state->float_type, mantissa_f32, mantissa}); - state->builder.AddFunction( - {OpFMul, state->float_type, subnormal, mantissa_f32, + const auto mantissa_f32 = state.builder.AllocateId(); + const auto subnormal = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertUToF, state.float_type, mantissa_f32, mantissa}); + state.builder.AddFunction( + {OpFMul, state.float_type, subnormal, mantissa_f32, ConstantF32Value(state, std::ldexp(1.0f, 1 - 15 - static_cast(mantissa_bits)))}); const auto zero_exp = EmitTBufferCompareU32Constant(state, OpIEqual, exponent, 0); @@ -856,7 +856,7 @@ uint32_t EmitUFloatToF32Bits(EmitterState* state, uint32_t raw, uint32_t bits) { return EmitTBufferBitcastF32ToU32(state, result); } -uint32_t EmitFormatRawComponent(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitFormatRawComponent(EmitterState& state, const IR::Instruction& inst, const Format::BufferFormatInfo& info) { const auto component = inst.memory.component_index; if (component >= info.component_count) { @@ -882,42 +882,42 @@ uint32_t EmitFormatRawComponent(EmitterState* state, const IR::Instruction& inst AddressSourceCount(load_inst, 0), bits, sign_extend); } -uint32_t NormalizeFormatComponent(EmitterState* state, const Format::BufferFormatInfo& info, +uint32_t NormalizeFormatComponent(EmitterState& state, const Format::BufferFormatInfo& info, uint32_t component, uint32_t raw) { const auto bits = info.component_bits[component]; switch (info.type) { case Format::ComponentType::Uint: case Format::ComponentType::Sint: return raw; case Format::ComponentType::Uscaled: { - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertUToF, state->float_type, value, raw}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertUToF, state.float_type, value, raw}); return EmitTBufferBitcastF32ToU32(state, value); } case Format::ComponentType::Sscaled: { const auto signed_raw = EmitTBufferBitcastU32ToI32(state, raw); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpConvertSToF, state->float_type, value, signed_raw}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpConvertSToF, state.float_type, value, signed_raw}); return EmitTBufferBitcastF32ToU32(state, value); } case Format::ComponentType::Unorm: { - const auto value = state->builder.AllocateId(); - const auto normalized = state->builder.AllocateId(); + const auto value = state.builder.AllocateId(); + const auto normalized = state.builder.AllocateId(); const auto max_value = static_cast((1u << bits) - 1u); - state->builder.AddFunction({OpConvertUToF, state->float_type, value, raw}); - state->builder.AddFunction( - {OpFDiv, state->float_type, normalized, value, ConstantF32Value(state, max_value)}); + state.builder.AddFunction({OpConvertUToF, state.float_type, value, raw}); + state.builder.AddFunction( + {OpFDiv, state.float_type, normalized, value, ConstantF32Value(state, max_value)}); return EmitTBufferBitcastF32ToU32(state, normalized); } case Format::ComponentType::Snorm: { const auto signed_raw = EmitTBufferBitcastU32ToI32(state, raw); - const auto value = state->builder.AllocateId(); - const auto normalized = state->builder.AllocateId(); - const auto clamped = state->builder.AllocateId(); + const auto value = state.builder.AllocateId(); + const auto normalized = state.builder.AllocateId(); + const auto clamped = state.builder.AllocateId(); const auto max_value = static_cast((1u << (bits - 1u)) - 1u); - state->builder.AddFunction({OpConvertSToF, state->float_type, value, signed_raw}); - state->builder.AddFunction( - {OpFDiv, state->float_type, normalized, value, ConstantF32Value(state, max_value)}); - state->builder.AddFunction({OpExtInst, state->float_type, clamped, state->glsl_std450, + state.builder.AddFunction({OpConvertSToF, state.float_type, value, signed_raw}); + state.builder.AddFunction( + {OpFDiv, state.float_type, normalized, value, ConstantF32Value(state, max_value)}); + state.builder.AddFunction({OpExtInst, state.float_type, clamped, state.glsl_std450, GlslFMax, normalized, ConstantF32Value(state, -1.0f)}); return EmitTBufferBitcastF32ToU32(state, clamped); } @@ -933,13 +933,13 @@ uint32_t NormalizeFormatComponent(EmitterState* state, const Format::BufferForma } } -uint32_t UnpackTBufferFormat(EmitterState* state, const IR::Instruction& inst, +uint32_t UnpackTBufferFormat(EmitterState& state, const IR::Instruction& inst, const Format::BufferFormatInfo& info) { const auto raw = EmitFormatRawComponent(state, inst, info); return NormalizeFormatComponent(state, info, inst.memory.component_index, raw); } -bool EmitTypedTBufferLoad(EmitterState* state, const IR::Instruction& inst, +bool EmitTypedTBufferLoad(EmitterState& state, const IR::Instruction& inst, const Format::BufferFormatInfo& info) { if (!Format::CanUseTypedBufferLoad(info.format)) { return false; @@ -950,12 +950,12 @@ bool EmitTypedTBufferLoad(EmitterState* state, const IR::Instruction& inst, return true; } -bool EmitFormattedBufferLoad(EmitterState* state, const IR::Instruction& inst) { +bool EmitFormattedBufferLoad(EmitterState& state, const IR::Instruction& inst) { if (!IsFormattedBufferComponent(inst)) { return false; } - const auto format = FormattedBufferFormat(*state, inst); + const auto format = FormattedBufferFormat(state, inst); if (!Format::IsKnownFormat(format)) { return false; } @@ -993,12 +993,12 @@ uint32_t FormattedBufferDwordStoreComponentCount(Prospero::BufferFormat format, } } -bool EmitBufferIntegerFormatStore(EmitterState* state, const IR::Instruction& inst) { +bool EmitBufferIntegerFormatStore(EmitterState& state, const IR::Instruction& inst) { if (!IsFormattedBufferComponent(inst)) { return false; } - const auto format = FormattedBufferFormat(*state, inst); + const auto format = FormattedBufferFormat(state, inst); if (!inst.memory.typed) { const auto dword_components = FormattedBufferDwordStoreComponentCount(format, inst.memory.component_count); @@ -1078,7 +1078,7 @@ bool EmitBufferIntegerFormatStore(EmitterState* state, const IR::Instruction& in return false; } -uint32_t EmitAtomicPointer(EmitterState* state, const IR::Instruction& inst) { +uint32_t EmitAtomicPointer(EmitterState& state, const IR::Instruction& inst) { switch (inst.memory.kind) { case IR::ResourceKind::Lds: return EmitLdsElementPointer(state, EmitDwordIndex(state, inst, 1, 1)); @@ -1090,11 +1090,11 @@ uint32_t EmitAtomicPointer(EmitterState* state, const IR::Instruction& inst) { return EmitStorageBufferElementPointer(state, inst.memory, index, inst.pc); } case IR::ResourceKind::StorageImageUint: { - const auto view = StorageImageViewKind(*state, inst.memory, true, inst.pc); + const auto view = StorageImageViewKind(state, inst.memory, true, inst.pc); const auto image_pointer = StorageImageDescriptorPointer(state, inst.memory.resource, true, inst.pc, view); - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction({OpImageTexelPointer, state->ptr_image_uint, pointer, + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction({OpImageTexelPointer, state.ptr_image_uint, pointer, image_pointer, EmitImageCoordU32(state, inst, view), ConstantU32(state, 0)}); return pointer; @@ -1103,13 +1103,13 @@ uint32_t EmitAtomicPointer(EmitterState* state, const IR::Instruction& inst) { } } -void EmitDeviceAtomicMemoryBarrier(EmitterState* state) { +void EmitDeviceAtomicMemoryBarrier(EmitterState& state) { const auto semantics = MemorySemanticsAcquireRelease | MemorySemanticsUniformMemory; - state->builder.AddFunction( + state.builder.AddFunction( {OpMemoryBarrier, ConstantU32(state, ScopeDevice), ConstantU32(state, semantics)}); } -void EmitAtomicU32(EmitterState* state, const IR::Instruction& inst, uint32_t opcode) { +void EmitAtomicU32(EmitterState& state, const IR::Instruction& inst, uint32_t opcode) { if (IsStorageBufferMemoryKind(inst.memory.kind)) { const auto index = EmitMemoryDwordIndex(state, inst, inst.memory, 1, AddressSourceCount(inst, 1)); @@ -1118,8 +1118,8 @@ void EmitAtomicU32(EmitterState* state, const IR::Instruction& inst, uint32_t op const auto old = EmitValueOrZeroIfCondition(state, in_bounds, [&]() { const auto pointer = EmitStorageBufferElementPointer(state, inst.memory, index, inst.pc); - const auto result = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, result, pointer, + const auto result = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, result, pointer, ConstantU32(state, ScopeDevice), ConstantU32(state, MemorySemanticsNone), value}); EmitDeviceAtomicMemoryBarrier(state); @@ -1134,8 +1134,8 @@ void EmitAtomicU32(EmitterState* state, const IR::Instruction& inst, uint32_t op const auto value = EmitValueLoad(state, inst.src[0]); const auto old = EmitValueOrZeroIfCondition(state, in_bounds, [&]() { const auto pointer = EmitGdsElementPointer(state, index); - const auto result = state->builder.AllocateId(); - state->builder.AddFunction({opcode, state->uint_type, result, pointer, + const auto result = state.builder.AllocateId(); + state.builder.AddFunction({opcode, state.uint_type, result, pointer, ConstantU32(state, ScopeDevice), ConstantU32(state, MemorySemanticsNone), value}); EmitDeviceAtomicMemoryBarrier(state); @@ -1152,9 +1152,9 @@ void EmitAtomicU32(EmitterState* state, const IR::Instruction& inst, uint32_t op } const auto value = EmitValueLoad(state, inst.src[0]); - const auto old = state->builder.AllocateId(); + const auto old = state.builder.AllocateId(); const auto scope = inst.memory.kind == IR::ResourceKind::Lds ? ScopeWorkgroup : ScopeDevice; - state->builder.AddFunction({opcode, state->uint_type, old, pointer, ConstantU32(state, scope), + state.builder.AddFunction({opcode, state.uint_type, old, pointer, ConstantU32(state, scope), ConstantU32(state, MemorySemanticsNone), value}); if (inst.memory.kind == IR::ResourceKind::StorageImageUint || inst.memory.kind == IR::ResourceKind::Gds) { @@ -1163,83 +1163,83 @@ void EmitAtomicU32(EmitterState* state, const IR::Instruction& inst, uint32_t op EmitStoreU32(state, inst.dst, old); } -void EmitSLoadDword(EmitterState* state, const IR::Instruction& inst) { - if (state->address_memory_variable == 0) { - ExitDescriptorBindingFailure(*state, IR::DescriptorBindingKind::AddressMemory, +void EmitSLoadDword(EmitterState& state, const IR::Instruction& inst) { + if (state.address_memory_variable == 0) { + ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::AddressMemory, inst.memory.resource, "scalar memory descriptor array was not emitted"); } - const auto binding = ResourceForDescriptor(*state, IR::DescriptorBindingKind::AddressMemory, + const auto binding = ResourceForDescriptor(state, IR::DescriptorBindingKind::AddressMemory, inst.memory.resource); const auto address = EmitRelativeAddress(state, inst, 0, 1, false, true); - const auto index = state->builder.AllocateId(); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, index, address, ConstantU32(state, 2)}); - const auto object = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, state->ptr_storage_buffer, object, - state->address_memory_variable, + const auto index = state.builder.AllocateId(); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, index, address, ConstantU32(state, 2)}); + const auto object = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer, object, + state.address_memory_variable, ConstantU32(state, binding.array_index)}); - const auto length = state->builder.AllocateId(); - const auto in_bounds = state->builder.AllocateId(); - state->builder.AddFunction({OpArrayLength, state->uint_type, length, object, 0}); - state->builder.AddFunction({OpULessThan, state->bool_type, in_bounds, index, length}); + const auto length = state.builder.AllocateId(); + const auto in_bounds = state.builder.AllocateId(); + state.builder.AddFunction({OpArrayLength, state.uint_type, length, object, 0}); + state.builder.AddFunction({OpULessThan, state.bool_type, in_bounds, index, length}); const auto value = EmitValueOrZeroIfCondition(state, in_bounds, [&]() { - const auto pointer = state->builder.AllocateId(); - const auto loaded = state->builder.AllocateId(); - state->builder.AddFunction( - {OpAccessChain, state->ptr_storage_buffer_uint, pointer, state->address_memory_variable, + const auto pointer = state.builder.AllocateId(); + const auto loaded = state.builder.AllocateId(); + state.builder.AddFunction( + {OpAccessChain, state.ptr_storage_buffer_uint, pointer, state.address_memory_variable, ConstantU32(state, binding.array_index), ConstantU32(state, 0), index}); - state->builder.AddFunction({OpLoad, state->uint_type, loaded, pointer}); + state.builder.AddFunction({OpLoad, state.uint_type, loaded, pointer}); return loaded; }); EmitStoreU32(state, inst.dst, value); } -void EmitLoadSrtDword(EmitterState* state, const IR::Instruction& inst) { - if (state->flattened_srt_variable == 0 || inst.src_count != 1 || +void EmitLoadSrtDword(EmitterState& state, const IR::Instruction& inst) { + if (state.flattened_srt_variable == 0 || inst.src_count != 1 || inst.src[0].kind != IR::OperandKind::ImmediateU32) { - ExitDescriptorBindingFailure(*state, IR::DescriptorBindingKind::FlattenedSrt, + ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::FlattenedSrt, inst.src_count != 0 ? inst.src[0].imm : 0, "invalid flattened SRT load"); } - const auto pointer = state->builder.AllocateId(); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, state->ptr_storage_buffer_uint, pointer, - state->flattened_srt_variable, ConstantU32(state, 0), + const auto pointer = state.builder.AllocateId(); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer_uint, pointer, + state.flattened_srt_variable, ConstantU32(state, 0), ConstantU32(state, inst.src[0].imm)}); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); EmitStoreU32(state, inst.dst, value); } -void EmitBufferLoadUbyte(EmitterState* state, const IR::Instruction& inst) { +void EmitBufferLoadUbyte(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadSubDwordU32(state, inst, IR::ResourceKind::Buffer, 0, AddressSourceCount(inst, 0), 8, false); }); } -void EmitBufferLoadSbyte(EmitterState* state, const IR::Instruction& inst) { +void EmitBufferLoadSbyte(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadSubDwordU32(state, inst, IR::ResourceKind::Buffer, 0, AddressSourceCount(inst, 0), 8, true); }); } -void EmitBufferLoadUshort(EmitterState* state, const IR::Instruction& inst) { +void EmitBufferLoadUshort(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadSubDwordU32(state, inst, IR::ResourceKind::Buffer, 0, AddressSourceCount(inst, 0), 16, false); }); } -void EmitBufferLoadSshort(EmitterState* state, const IR::Instruction& inst) { +void EmitBufferLoadSshort(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadSubDwordU32(state, inst, IR::ResourceKind::Buffer, 0, AddressSourceCount(inst, 0), 16, true); }); } -void EmitBufferLoadDword(EmitterState* state, const IR::Instruction& inst) { +void EmitBufferLoadDword(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { if (EmitFormattedBufferLoad(state, inst)) { return; @@ -1248,95 +1248,95 @@ void EmitBufferLoadDword(EmitterState* state, const IR::Instruction& inst) { }); } -void EmitBufferStoreDword(EmitterState* state, const IR::Instruction& inst) { +void EmitBufferStoreDword(EmitterState& state, const IR::Instruction& inst) { if (EmitBufferIntegerFormatStore(state, inst)) { return; } EmitMemoryStoreU32(state, inst, IR::ResourceKind::Buffer, 1, AddressSourceCount(inst, 1)); } -void EmitFlatLoadUbyte(EmitterState* state, const IR::Instruction& inst) { +void EmitFlatLoadUbyte(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadSubDwordU32(state, inst, inst.memory.kind, 0, inst.src_count, 8, false); }); } -void EmitFlatLoadSbyte(EmitterState* state, const IR::Instruction& inst) { +void EmitFlatLoadSbyte(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadSubDwordU32(state, inst, inst.memory.kind, 0, inst.src_count, 8, true); }); } -void EmitFlatLoadUshort(EmitterState* state, const IR::Instruction& inst) { +void EmitFlatLoadUshort(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadSubDwordU32(state, inst, inst.memory.kind, 0, inst.src_count, 16, false); }); } -void EmitFlatLoadSshort(EmitterState* state, const IR::Instruction& inst) { +void EmitFlatLoadSshort(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadSubDwordU32(state, inst, inst.memory.kind, 0, inst.src_count, 16, true); }); } -void EmitFlatLoadDword(EmitterState* state, const IR::Instruction& inst) { +void EmitFlatLoadDword(EmitterState& state, const IR::Instruction& inst) { EmitGuardedByExec(state, [&]() { EmitMemoryLoadDwordsU32(state, inst, inst.memory.kind, 0, inst.src_count); }); } -uint32_t EmitDsAddtidDwordIndex(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitDsAddtidDwordIndex(EmitterState& state, const IR::Instruction& inst, uint32_t m0_src_index) { - if (state->stage != ShaderType::Compute) { + if (state.stage != ShaderType::Compute) { const auto m0 = m0_src_index < inst.src_count ? EmitValueLoad(state, inst.src[m0_src_index]) : ConstantU32(state, 0); - const auto m0_lo = state->builder.AllocateId(); - const auto base = state->builder.AllocateId(); - const auto index = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, m0_lo, m0, ConstantU32(state, 0x0000ffffu)}); - state->builder.AddFunction( - {OpIAdd, state->uint_type, base, m0_lo, ConstantU32(state, inst.memory.offset)}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, index, base, ConstantU32(state, 2)}); + const auto m0_lo = state.builder.AllocateId(); + const auto base = state.builder.AllocateId(); + const auto index = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, m0_lo, m0, ConstantU32(state, 0x0000ffffu)}); + state.builder.AddFunction( + {OpIAdd, state.uint_type, base, m0_lo, ConstantU32(state, inst.memory.offset)}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, index, base, ConstantU32(state, 2)}); return index; } const auto local_index = EmitLocalInvocationIndex(state); - const auto lane = state->builder.AllocateId(); - const auto lane_bytes = state->builder.AllocateId(); + const auto lane = state.builder.AllocateId(); + const auto lane_bytes = state.builder.AllocateId(); const auto m0 = m0_src_index < inst.src_count ? EmitValueLoad(state, inst.src[m0_src_index]) : ConstantU32(state, 0); - const auto m0_lo = state->builder.AllocateId(); - const auto base = state->builder.AllocateId(); - const auto address = state->builder.AllocateId(); - const auto index = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, local_index, ConstantU32(state, 63)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, lane_bytes, lane, ConstantU32(state, 2)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, m0_lo, m0, ConstantU32(state, 0x0000ffffu)}); - state->builder.AddFunction( - {OpIAdd, state->uint_type, base, m0_lo, ConstantU32(state, inst.memory.offset)}); - state->builder.AddFunction({OpIAdd, state->uint_type, address, base, lane_bytes}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, index, address, ConstantU32(state, 2)}); + const auto m0_lo = state.builder.AllocateId(); + const auto base = state.builder.AllocateId(); + const auto address = state.builder.AllocateId(); + const auto index = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, local_index, ConstantU32(state, 63)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, lane_bytes, lane, ConstantU32(state, 2)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, m0_lo, m0, ConstantU32(state, 0x0000ffffu)}); + state.builder.AddFunction( + {OpIAdd, state.uint_type, base, m0_lo, ConstantU32(state, inst.memory.offset)}); + state.builder.AddFunction({OpIAdd, state.uint_type, address, base, lane_bytes}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, index, address, ConstantU32(state, 2)}); return index; } -void EmitDsWriteAddtidB32(EmitterState* state, const IR::Instruction& inst) { +void EmitDsWriteAddtidB32(EmitterState& state, const IR::Instruction& inst) { const auto value = EmitValueLoad(state, inst.src[0]); const auto index = EmitDsAddtidDwordIndex(state, inst, 1); const auto pointer = EmitLdsElementPointer(state, index); - state->builder.AddFunction({OpStore, pointer, value}); + state.builder.AddFunction({OpStore, pointer, value}); } -void EmitDsReadAddtidB32(EmitterState* state, const IR::Instruction& inst) { +void EmitDsReadAddtidB32(EmitterState& state, const IR::Instruction& inst) { const auto index = EmitDsAddtidDwordIndex(state, inst, 0); const auto pointer = EmitLdsElementPointer(state, index); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); EmitStoreU32(state, inst.dst, value); } @@ -1346,54 +1346,54 @@ struct DsCounterAddress { uint32_t in_lds_bounds = 0; }; -DsCounterAddress EmitAppendConsumeAddress(EmitterState* state, const IR::Instruction& inst) { +DsCounterAddress EmitAppendConsumeAddress(EmitterState& state, const IR::Instruction& inst) { const auto m0 = inst.src_count > 0 ? EmitValueLoad(state, inst.src[0]) : ConstantU32(state, 0); - const auto base = state->builder.AllocateId(); - const auto size = state->builder.AllocateId(); - const auto address = state->builder.AllocateId(); - const auto index = state->builder.AllocateId(); - const auto in_bounds = state->builder.AllocateId(); + const auto base = state.builder.AllocateId(); + const auto size = state.builder.AllocateId(); + const auto address = state.builder.AllocateId(); + const auto index = state.builder.AllocateId(); + const auto in_bounds = state.builder.AllocateId(); // RDNA2 puts the DS append/consume byte base in M0[31:16]. - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, base, m0, ConstantU32(state, 16)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, size, m0, ConstantU32(state, 0xffffu)}); - state->builder.AddFunction( - {OpIAdd, state->uint_type, address, base, ConstantU32(state, inst.memory.offset)}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, index, address, ConstantU32(state, 2)}); - state->builder.AddFunction({OpULessThan, state->bool_type, in_bounds, + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, base, m0, ConstantU32(state, 16)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, size, m0, ConstantU32(state, 0xffffu)}); + state.builder.AddFunction( + {OpIAdd, state.uint_type, address, base, ConstantU32(state, inst.memory.offset)}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, index, address, ConstantU32(state, 2)}); + state.builder.AddFunction({OpULessThan, state.bool_type, in_bounds, ConstantU32(state, inst.memory.offset + 3u), size}); return {index, size, in_bounds}; } -uint32_t EmitGdsElementInBounds(EmitterState* state, uint32_t index) { - const auto length = state->builder.AllocateId(); - const auto in_bounds = state->builder.AllocateId(); - state->builder.AddFunction({OpArrayLength, state->uint_type, length, state->gds_variable, 0}); - state->builder.AddFunction({OpULessThan, state->bool_type, in_bounds, index, length}); +uint32_t EmitGdsElementInBounds(EmitterState& state, uint32_t index) { + const auto length = state.builder.AllocateId(); + const auto in_bounds = state.builder.AllocateId(); + state.builder.AddFunction({OpArrayLength, state.uint_type, length, state.gds_variable, 0}); + state.builder.AddFunction({OpULessThan, state.bool_type, in_bounds, index, length}); return in_bounds; } -uint32_t EmitGdsElementPointer(EmitterState* state, uint32_t index) { - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, state->ptr_storage_buffer_uint, pointer, - state->gds_variable, ConstantU32(state, 0), index}); +uint32_t EmitGdsElementPointer(EmitterState& state, uint32_t index) { + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer_uint, pointer, + state.gds_variable, ConstantU32(state, 0), index}); return pointer; } -uint32_t EmitBitCountU32Value(EmitterState* state, uint32_t value) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitCount, state->uint_type, ret, value}); +uint32_t EmitBitCountU32Value(EmitterState& state, uint32_t value) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitCount, state.uint_type, ret, value}); return ret; } -uint32_t EmitFindLsbU32Value(EmitterState* state, uint32_t value) { - const auto i32 = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->int_type, i32, state->glsl_std450, GlslFindILsb, value}); - state->builder.AddFunction({OpBitcast, state->uint_type, ret, i32}); +uint32_t EmitFindLsbU32Value(EmitterState& state, uint32_t value) { + const auto i32 = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.int_type, i32, state.glsl_std450, GlslFindILsb, value}); + state.builder.AddFunction({OpBitcast, state.uint_type, ret, i32}); return ret; } @@ -1403,18 +1403,18 @@ struct ExecMaskInfo { uint32_t any_active = 0; }; -ExecMaskInfo EmitExecMaskInfo(EmitterState* state) { +ExecMaskInfo EmitExecMaskInfo(EmitterState& state) { uint32_t exec_lo = 0; uint32_t exec_hi = 0; - if (state->per_invocation_masks) { - const auto ballot = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformBallot, state->vec4_uint_type, ballot, + if (state.per_invocation_masks) { + const auto ballot = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot, ConstantU32(state, ScopeSubgroup), EmitExecActiveBool(state)}); - exec_lo = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, exec_lo, ballot, 0}); - if (state->wave_size == 64u) { - exec_hi = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, exec_hi, ballot, 1}); + exec_lo = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, exec_lo, ballot, 0}); + if (state.wave_size == 64u) { + exec_hi = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, exec_hi, ballot, 1}); } else { exec_hi = ConstantU32(state, 0); } @@ -1424,27 +1424,27 @@ ExecMaskInfo EmitExecMaskInfo(EmitterState* state) { } const auto lo_count = EmitBitCountU32Value(state, exec_lo); const auto hi_count = EmitBitCountU32Value(state, exec_hi); - const auto active_count = state->builder.AllocateId(); - state->builder.AddFunction({OpIAdd, state->uint_type, active_count, lo_count, hi_count}); + const auto active_count = state.builder.AllocateId(); + state.builder.AddFunction({OpIAdd, state.uint_type, active_count, lo_count, hi_count}); const auto lo_nonzero = EmitNotEqualZeroBool(state, exec_lo); const auto hi_nonzero = EmitNotEqualZeroBool(state, exec_hi); const auto any_active = EmitLogicalOrBool(state, lo_nonzero, hi_nonzero); const auto hi_lsb = EmitFindLsbU32Value(state, exec_hi); - const auto hi_lane = state->builder.AllocateId(); - state->builder.AddFunction({OpIAdd, state->uint_type, hi_lane, hi_lsb, ConstantU32(state, 32)}); + const auto hi_lane = state.builder.AllocateId(); + state.builder.AddFunction({OpIAdd, state.uint_type, hi_lane, hi_lsb, ConstantU32(state, 32)}); const auto lo_lsb = EmitFindLsbU32Value(state, exec_lo); - const auto selected = state->builder.AllocateId(); - state->builder.AddFunction({OpSelect, state->uint_type, selected, lo_nonzero, lo_lsb, hi_lane}); - const auto first_lane = state->builder.AllocateId(); - state->builder.AddFunction( - {OpSelect, state->uint_type, first_lane, any_active, selected, ConstantU32(state, 0)}); + const auto selected = state.builder.AllocateId(); + state.builder.AddFunction({OpSelect, state.uint_type, selected, lo_nonzero, lo_lsb, hi_lane}); + const auto first_lane = state.builder.AllocateId(); + state.builder.AddFunction( + {OpSelect, state.uint_type, first_lane, any_active, selected, ConstantU32(state, 0)}); return {active_count, first_lane, any_active}; } -void EmitDsAppendConsume(EmitterState* state, const IR::Instruction& inst, uint32_t atomic_opcode) { +void EmitDsAppendConsume(EmitterState& state, const IR::Instruction& inst, uint32_t atomic_opcode) { const auto gds = inst.memory.kind == IR::ResourceKind::Gds; - if (gds && state->gds_variable == 0) { + if (gds && state.gds_variable == 0) { EmitStoreU32(state, inst.dst, ConstantU32(state, 0)); return; } @@ -1456,37 +1456,37 @@ void EmitDsAppendConsume(EmitterState* state, const IR::Instruction& inst, uint3 const auto in_bounds = EmitLogicalAndBool(state, m0_bounds, storage_bounds); const auto exec = EmitExecMaskInfo(state); const auto subid = EmitSubgroupLocalInvocationId(state); - const auto first_lane = state->builder.AllocateId(); - const auto do_atomic = state->builder.AllocateId(); - state->builder.AddFunction({OpIEqual, state->bool_type, first_lane, subid, exec.first_lane}); + const auto first_lane = state.builder.AllocateId(); + const auto do_atomic = state.builder.AllocateId(); + state.builder.AddFunction({OpIEqual, state.bool_type, first_lane, subid, exec.first_lane}); const auto first_active = EmitLogicalAndBool(state, first_lane, exec.any_active); - state->builder.AddFunction( - {OpLogicalAnd, state->bool_type, do_atomic, first_active, in_bounds}); + state.builder.AddFunction( + {OpLogicalAnd, state.bool_type, do_atomic, first_active, in_bounds}); const auto atomic_value = EmitValueOrZeroIfCondition(state, do_atomic, [&]() { const auto pointer = gds ? EmitGdsElementPointer(state, address.index) : EmitLdsElementPointer(state, address.index); - const auto result = state->builder.AllocateId(); - state->builder.AddFunction({atomic_opcode, state->uint_type, result, pointer, + const auto result = state.builder.AllocateId(); + state.builder.AddFunction({atomic_opcode, state.uint_type, result, pointer, ConstantU32(state, gds ? ScopeDevice : ScopeWorkgroup), ConstantU32(state, MemorySemanticsNone), exec.active_count}); if (gds) { EmitDeviceAtomicMemoryBarrier(state); } else { const auto semantics = MemorySemanticsAcquireRelease | MemorySemanticsWorkgroupMemory; - state->builder.AddFunction({OpMemoryBarrier, ConstantU32(state, ScopeWorkgroup), + state.builder.AddFunction({OpMemoryBarrier, ConstantU32(state, ScopeWorkgroup), ConstantU32(state, semantics)}); } return result; }); - const auto broadcast = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformShuffle, state->uint_type, broadcast, + const auto broadcast = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, broadcast, ConstantU32(state, ScopeSubgroup), atomic_value, exec.first_lane}); const auto value = EmitSelectU32Value(state, exec.any_active, broadcast, ConstantU32(state, 0)); EmitStoreU32(state, inst.dst, value); } -void EmitDsFloatMinMaxF32(EmitterState* state, const IR::Instruction& inst, bool max_value) { +void EmitDsFloatMinMaxF32(EmitterState& state, const IR::Instruction& inst, bool max_value) { const auto index = EmitDwordIndex(state, inst, 1, 1); const auto in_bounds = inst.memory.kind == IR::ResourceKind::Gds ? EmitGdsElementInBounds(state, index) : 0u; @@ -1495,23 +1495,23 @@ void EmitDsFloatMinMaxF32(EmitterState* state, const IR::Instruction& inst, bool const auto data_f32 = EmitFloatLoad(state, inst.src[0]); const auto cmp_f32 = EmitFloatLoad(state, inst.src[2]); EmitAtomicUpdateU32(state, pointer, inst.memory.kind, [&](uint32_t old_u32) { - const auto old_f32 = state->builder.AllocateId(); - const auto store_src = state->builder.AllocateId(); - const auto value_f32 = state->builder.AllocateId(); - const auto value_u32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->float_type, old_f32, old_u32}); - state->builder.AddFunction({max_value ? OpFOrdGreaterThan : OpFOrdLessThan, - state->bool_type, store_src, max_value ? old_f32 : cmp_f32, + const auto old_f32 = state.builder.AllocateId(); + const auto store_src = state.builder.AllocateId(); + const auto value_f32 = state.builder.AllocateId(); + const auto value_u32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.float_type, old_f32, old_u32}); + state.builder.AddFunction({max_value ? OpFOrdGreaterThan : OpFOrdLessThan, + state.bool_type, store_src, max_value ? old_f32 : cmp_f32, max_value ? cmp_f32 : old_f32}); - state->builder.AddFunction( - {OpSelect, state->float_type, value_f32, store_src, data_f32, old_f32}); - state->builder.AddFunction({OpBitcast, state->uint_type, value_u32, value_f32}); + state.builder.AddFunction( + {OpSelect, state.float_type, value_f32, store_src, data_f32, old_f32}); + state.builder.AddFunction({OpBitcast, state.uint_type, value_u32, value_f32}); return value_u32; }); }); } -uint32_t EmitDsSwizzleTargetLane(EmitterState* state, uint32_t subid, uint32_t control) { +uint32_t EmitDsSwizzleTargetLane(EmitterState& state, uint32_t subid, uint32_t control) { if ((control & 0xc000u) == 0xc000u) { const uint32_t mask = control & 0x1fu; const uint32_t rotate = (control >> 5u) & 0x1fu; @@ -1527,63 +1527,63 @@ uint32_t EmitDsSwizzleTargetLane(EmitterState* state, uint32_t subid, uint32_t c } if ((control & 0x8000u) != 0) { - const auto lane2 = state->builder.AllocateId(); - const auto shift = state->builder.AllocateId(); - const auto perm0 = state->builder.AllocateId(); - const auto perm = state->builder.AllocateId(); - const auto base = state->builder.AllocateId(); - const auto target = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane2, subid, ConstantU32(state, 3)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shift, lane2, ConstantU32(state, 1)}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, perm0, ConstantU32(state, control), shift}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, perm, perm0, ConstantU32(state, 3)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, base, subid, ConstantU32(state, 0xfffffffcu)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, target, base, perm}); + const auto lane2 = state.builder.AllocateId(); + const auto shift = state.builder.AllocateId(); + const auto perm0 = state.builder.AllocateId(); + const auto perm = state.builder.AllocateId(); + const auto base = state.builder.AllocateId(); + const auto target = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane2, subid, ConstantU32(state, 3)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shift, lane2, ConstantU32(state, 1)}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, perm0, ConstantU32(state, control), shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, perm, perm0, ConstantU32(state, 3)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, base, subid, ConstantU32(state, 0xfffffffcu)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, base, perm}); return target; } - const auto lane = state->builder.AllocateId(); - const auto masked = state->builder.AllocateId(); - const auto ored = state->builder.AllocateId(); - const auto xored = state->builder.AllocateId(); - const auto base = state->builder.AllocateId(); - const auto target = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, subid, ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, masked, lane, ConstantU32(state, control & 0x1fu)}); - state->builder.AddFunction( - {OpBitwiseOr, state->uint_type, ored, masked, ConstantU32(state, (control >> 5u) & 0x1fu)}); - state->builder.AddFunction({OpBitwiseXor, state->uint_type, xored, ored, + const auto lane = state.builder.AllocateId(); + const auto masked = state.builder.AllocateId(); + const auto ored = state.builder.AllocateId(); + const auto xored = state.builder.AllocateId(); + const auto base = state.builder.AllocateId(); + const auto target = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, masked, lane, ConstantU32(state, control & 0x1fu)}); + state.builder.AddFunction( + {OpBitwiseOr, state.uint_type, ored, masked, ConstantU32(state, (control >> 5u) & 0x1fu)}); + state.builder.AddFunction({OpBitwiseXor, state.uint_type, xored, ored, ConstantU32(state, (control >> 10u) & 0x1fu)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, base, subid, ConstantU32(state, 0xffffffe0u)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, target, base, xored}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, base, subid, ConstantU32(state, 0xffffffe0u)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, base, xored}); return target; } -void EmitDsSwizzleB32(EmitterState* state, const IR::Instruction& inst) { +void EmitDsSwizzleB32(EmitterState& state, const IR::Instruction& inst) { const auto source = EmitValueLoad(state, inst.src[0]); const auto control = inst.src_count > 1u ? inst.src[1].imm & 0xffffu : 0u; const auto subid = EmitSubgroupLocalInvocationId(state); const auto target = EmitDsSwizzleTargetLane(state, subid, control); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformShuffle, state->uint_type, value, + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, value, ConstantU32(state, ScopeSubgroup), source, target}); const auto exec_active = EmitLaneIndexActiveBool(state, target); const auto subgroup_active = EmitSubgroupLaneActiveBool(state, target); - const auto source_active = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); + const auto source_active = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); // RDNA2 DS_SWIZZLE returns zero when the selected source thread is invalid. - state->builder.AddFunction( - {OpLogicalAnd, state->bool_type, source_active, exec_active, subgroup_active}); - state->builder.AddFunction( - {OpSelect, state->uint_type, selected, source_active, value, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpLogicalAnd, state.bool_type, source_active, exec_active, subgroup_active}); + state.builder.AddFunction( + {OpSelect, state.uint_type, selected, source_active, value, ConstantU32(state, 0)}); EmitStoreU32(state, inst.dst, selected); } diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterModule.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterModule.cpp index ce75be3a4..8e5483d2f 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterModule.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterModule.cpp @@ -4,7 +4,7 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { const IR::DescriptorBinding* DescriptorBinding(const EmitterState& state, IR::DescriptorBindingKind kind) { - return IR::FindBinding(state.program->bindings, kind); + return IR::FindBinding(state.program.bindings, kind); } uint32_t DescriptorCount(const EmitterState& state, IR::DescriptorBindingKind kind) { @@ -12,37 +12,37 @@ uint32_t DescriptorCount(const EmitterState& state, IR::DescriptorBindingKind ki return binding != nullptr ? static_cast(binding->resources.size()) : 0; } -uint32_t ConstantU32(EmitterState* state, uint32_t value) { - if (auto it = state->constants.find(value); it != state->constants.end()) { +uint32_t ConstantU32(EmitterState& state, uint32_t value) { + if (auto it = state.constants.find(value); it != state.constants.end()) { return it->second; } - const auto id = state->builder.AllocateId(); - state->constants.emplace(value, id); - state->builder.AddType({OpConstant, state->uint_type, id, value}); + const auto id = state.builder.AllocateId(); + state.constants.emplace(value, id); + state.builder.AddType({OpConstant, state.uint_type, id, value}); return id; } -uint32_t ConstantI32(EmitterState* state, int32_t value) { +uint32_t ConstantI32(EmitterState& state, int32_t value) { const auto bits = static_cast(value); - if (auto it = state->signed_constants.find(bits); it != state->signed_constants.end()) { + if (auto it = state.signed_constants.find(bits); it != state.signed_constants.end()) { return it->second; } - const auto id = state->builder.AllocateId(); - state->signed_constants.emplace(bits, id); - state->builder.AddType({OpConstant, state->int_type, id, bits}); + const auto id = state.builder.AllocateId(); + state.signed_constants.emplace(bits, id); + state.builder.AddType({OpConstant, state.int_type, id, bits}); return id; } -uint32_t ConstantF32(EmitterState* state, uint32_t bits) { - if (auto it = state->float_constants.find(bits); it != state->float_constants.end()) { +uint32_t ConstantF32(EmitterState& state, uint32_t bits) { + if (auto it = state.float_constants.find(bits); it != state.float_constants.end()) { return it->second; } - const auto id = state->builder.AllocateId(); - state->float_constants.emplace(bits, id); - state->builder.AddType({OpConstant, state->float_type, id, bits}); + const auto id = state.builder.AllocateId(); + state.float_constants.emplace(bits, id); + state.builder.AddType({OpConstant, state.float_type, id, bits}); return id; } @@ -52,7 +52,7 @@ uint32_t FloatBits(float value) { return bits; } -uint32_t ConstantF32Value(EmitterState* state, float value) { +uint32_t ConstantF32Value(EmitterState& state, float value) { return ConstantF32(state, FloatBits(value)); } @@ -174,43 +174,43 @@ uint32_t VertexParameterInputPointerType(const EmitterState& state, VertexInputS } } -void AllocateInputVariables(EmitterState* state) { - for (auto& binding: state->inputs) { - binding.variable_id = state->builder.AllocateId(); - state->interface_variables.push_back(binding.variable_id); +void AllocateInputVariables(EmitterState& state) { + for (auto& binding: state.inputs) { + binding.variable_id = state.builder.AllocateId(); + state.interface_variables.push_back(binding.variable_id); } - if (state->needs_subgroup_local_invocation_id) { - state->subgroup_local_invocation_id_variable = state->builder.AllocateId(); - state->interface_variables.push_back(state->subgroup_local_invocation_id_variable); + if (state.needs_subgroup_local_invocation_id) { + state.subgroup_local_invocation_id_variable = state.builder.AllocateId(); + state.interface_variables.push_back(state.subgroup_local_invocation_id_variable); } } -static uint32_t AllocateInterfaceVariable(EmitterState* state) { - const auto variable = state->builder.AllocateId(); - state->interface_variables.push_back(variable); +static uint32_t AllocateInterfaceVariable(EmitterState& state) { + const auto variable = state.builder.AllocateId(); + state.interface_variables.push_back(variable); return variable; } -static uint32_t AllocateSharedOutputVariable(EmitterState* state, uint32_t& variable) { +static uint32_t AllocateSharedOutputVariable(EmitterState& state, uint32_t& variable) { if (variable == 0) { variable = AllocateInterfaceVariable(state); } return variable; } -void AllocateOutputVariables(EmitterState* state) { - for (auto& binding: state->outputs) { +void AllocateOutputVariables(EmitterState& state) { + for (auto& binding: state.outputs) { switch (binding.kind) { case IR::StageOutputKind::Position: binding.variable_id = - AllocateSharedOutputVariable(state, state->per_vertex_variable); + AllocateSharedOutputVariable(state, state.per_vertex_variable); break; case IR::StageOutputKind::Depth: - binding.variable_id = AllocateSharedOutputVariable(state, state->depth_variable); + binding.variable_id = AllocateSharedOutputVariable(state, state.depth_variable); break; case IR::StageOutputKind::SampleMask: binding.variable_id = - AllocateSharedOutputVariable(state, state->sample_mask_variable); + AllocateSharedOutputVariable(state, state.sample_mask_variable); break; case IR::StageOutputKind::Parameter: case IR::StageOutputKind::Mrt: @@ -234,695 +234,695 @@ uint32_t BuiltInForInput(IR::StageInputKind kind) { } } -void AddInputAnnotationsAndNames(EmitterState* state) { - if (state->subgroup_local_invocation_id_variable != 0) { - state->builder.AddName(state->subgroup_local_invocation_id_variable, +void AddInputAnnotationsAndNames(EmitterState& state) { + if (state.subgroup_local_invocation_id_variable != 0) { + state.builder.AddName(state.subgroup_local_invocation_id_variable, "gl_SubgroupInvocationID"); - state->builder.AddAnnotation({OpDecorate, state->subgroup_local_invocation_id_variable, + state.builder.AddAnnotation({OpDecorate, state.subgroup_local_invocation_id_variable, DecorationBuiltIn, BuiltInSubgroupLocalInvocationId}); - if (state->stage == ShaderType::Pixel) { - state->builder.AddAnnotation( - {OpDecorate, state->subgroup_local_invocation_id_variable, DecorationFlat}); + if (state.stage == ShaderType::Pixel) { + state.builder.AddAnnotation( + {OpDecorate, state.subgroup_local_invocation_id_variable, DecorationFlat}); } } - for (const auto& input: state->inputs) { - state->builder.AddName(input.variable_id, input.debug_name.c_str()); + for (const auto& input: state.inputs) { + state.builder.AddName(input.variable_id, input.debug_name.c_str()); if (input.kind == IR::StageInputKind::Parameter) { - const auto flat = PixelParameterIsFlat(*state, input.location); + const auto flat = PixelParameterIsFlat(state, input.location); if (flat) { - state->builder.AddAnnotation({OpDecorate, input.variable_id, DecorationFlat}); + state.builder.AddAnnotation({OpDecorate, input.variable_id, DecorationFlat}); } - if (state->stage == ShaderType::Pixel && state->pixel_input_info != nullptr && - state->pixel_input_info->ps_no_perspective && !flat) { - state->builder.AddAnnotation( + if (state.stage == ShaderType::Pixel && state.pixel_input_info != nullptr && + state.pixel_input_info->ps_no_perspective && !flat) { + state.builder.AddAnnotation( {OpDecorate, input.variable_id, DecorationNoPerspective}); } - const auto location = PixelParameterLocation(*state, input.location); - state->builder.AddAnnotation( + const auto location = PixelParameterLocation(state, input.location); + state.builder.AddAnnotation( {OpDecorate, input.variable_id, DecorationLocation, location}); continue; } const auto builtin = BuiltInForInput(input.kind); if (builtin != UINT32_MAX) { - state->builder.AddAnnotation( + state.builder.AddAnnotation( {OpDecorate, input.variable_id, DecorationBuiltIn, builtin}); } } } -void AddOutputAnnotationsAndNames(EmitterState* state) { - if (state->per_vertex_variable != 0) { - state->builder.AddName(state->per_vertex_type, "gl_PerVertex"); - state->builder.AddName(state->per_vertex_variable, "outPerVertex"); - state->builder.AddAnnotation( - {OpMemberDecorate, state->per_vertex_type, 0, DecorationBuiltIn, BuiltInPosition}); - state->builder.AddAnnotation({OpDecorate, state->per_vertex_type, DecorationBlock}); +void AddOutputAnnotationsAndNames(EmitterState& state) { + if (state.per_vertex_variable != 0) { + state.builder.AddName(state.per_vertex_type, "gl_PerVertex"); + state.builder.AddName(state.per_vertex_variable, "outPerVertex"); + state.builder.AddAnnotation( + {OpMemberDecorate, state.per_vertex_type, 0, DecorationBuiltIn, BuiltInPosition}); + state.builder.AddAnnotation({OpDecorate, state.per_vertex_type, DecorationBlock}); } - if (state->depth_variable != 0) { - state->builder.AddName(state->depth_variable, "gl_FragDepth"); - state->builder.AddAnnotation( - {OpDecorate, state->depth_variable, DecorationBuiltIn, BuiltInFragDepth}); + if (state.depth_variable != 0) { + state.builder.AddName(state.depth_variable, "gl_FragDepth"); + state.builder.AddAnnotation( + {OpDecorate, state.depth_variable, DecorationBuiltIn, BuiltInFragDepth}); } - if (state->sample_mask_variable != 0) { - state->builder.AddName(state->sample_mask_variable, "gl_SampleMask"); - state->builder.AddAnnotation( - {OpDecorate, state->sample_mask_variable, DecorationBuiltIn, BuiltInSampleMask}); + if (state.sample_mask_variable != 0) { + state.builder.AddName(state.sample_mask_variable, "gl_SampleMask"); + state.builder.AddAnnotation( + {OpDecorate, state.sample_mask_variable, DecorationBuiltIn, BuiltInSampleMask}); } - for (const auto& binding: state->outputs) { + for (const auto& binding: state.outputs) { if (binding.kind == IR::StageOutputKind::Parameter || binding.kind == IR::StageOutputKind::Mrt) { - state->builder.AddName(binding.variable_id, binding.debug_name.c_str()); - state->builder.AddAnnotation( + state.builder.AddName(binding.variable_id, binding.debug_name.c_str()); + state.builder.AddAnnotation( {OpDecorate, binding.variable_id, DecorationLocation, binding.location}); } } } -void DecorateDescriptor(EmitterState* state, uint32_t variable, const char* name, uint32_t set, +void DecorateDescriptor(EmitterState& state, uint32_t variable, const char* name, uint32_t set, uint32_t binding) { if (variable == 0) { return; } - state->builder.AddName(variable, name); - state->builder.AddAnnotation({OpDecorate, variable, DecorationDescriptorSet, set}); - state->builder.AddAnnotation({OpDecorate, variable, DecorationBinding, binding}); + state.builder.AddName(variable, name); + state.builder.AddAnnotation({OpDecorate, variable, DecorationDescriptorSet, set}); + state.builder.AddAnnotation({OpDecorate, variable, DecorationBinding, binding}); } -void AddDescriptorAnnotationsAndNames(EmitterState* state) { - const auto set = state->program->bindings.descriptor_set; +void AddDescriptorAnnotationsAndNames(EmitterState& state) { + const auto set = state.program.bindings.descriptor_set; auto Decorate = [&](uint32_t variable, const char* name, IR::DescriptorBindingKind kind) { - const auto* binding = DescriptorBinding(*state, kind); + const auto* binding = DescriptorBinding(state, kind); if (binding != nullptr) { DecorateDescriptor(state, variable, name, set, binding->binding); } }; - if (state->storage_buffer_variable != 0) { - Decorate(state->storage_buffer_variable, "buffers", IR::DescriptorBindingKind::Buffers); + if (state.storage_buffer_variable != 0) { + Decorate(state.storage_buffer_variable, "buffers", IR::DescriptorBindingKind::Buffers); } - if (state->address_memory_variable != 0) { - Decorate(state->address_memory_variable, "address_memory", + if (state.address_memory_variable != 0) { + Decorate(state.address_memory_variable, "address_memory", IR::DescriptorBindingKind::AddressMemory); } constexpr const char* SampledNames[] = { "sampled_2d", "sampled_2d_array", "sampled_3d", "sampled_uint_2d", "sampled_uint_2d_array", "sampled_uint_3d"}; - for (uint32_t i = 0; i < state->sampled_images.size(); i++) { + for (uint32_t i = 0; i < state.sampled_images.size(); i++) { const auto view = static_cast(i % 3u); - Decorate(state->sampled_images[i].variable, SampledNames[i], + Decorate(state.sampled_images[i].variable, SampledNames[i], SampledBindingKind(i >= 3u, view)); } - if (state->storage_image_variable != 0) { - Decorate(state->storage_image_variable, "textures2D_L", + if (state.storage_image_variable != 0) { + Decorate(state.storage_image_variable, "textures2D_L", IR::DescriptorBindingKind::Storage2D); } - if (state->storage_image_uint_variable != 0) { - Decorate(state->storage_image_uint_variable, "textures2D_L_U", + if (state.storage_image_uint_variable != 0) { + Decorate(state.storage_image_uint_variable, "textures2D_L_U", IR::DescriptorBindingKind::StorageUint2D); } - if (state->storage_image_2d_array_variable != 0) { - Decorate(state->storage_image_2d_array_variable, "textures2D_L_A", + if (state.storage_image_2d_array_variable != 0) { + Decorate(state.storage_image_2d_array_variable, "textures2D_L_A", IR::DescriptorBindingKind::Storage2DArray); } - if (state->storage_image_uint_2d_array_variable != 0) { - Decorate(state->storage_image_uint_2d_array_variable, "textures2D_L_U_A", + if (state.storage_image_uint_2d_array_variable != 0) { + Decorate(state.storage_image_uint_2d_array_variable, "textures2D_L_U_A", IR::DescriptorBindingKind::StorageUint2DArray); } - if (state->storage_image_3d_variable != 0) { - Decorate(state->storage_image_3d_variable, "textures2D_L_3D", + if (state.storage_image_3d_variable != 0) { + Decorate(state.storage_image_3d_variable, "textures2D_L_3D", IR::DescriptorBindingKind::Storage3D); } - if (state->storage_image_uint_3d_variable != 0) { - Decorate(state->storage_image_uint_3d_variable, "textures2D_L_U_3D", + if (state.storage_image_uint_3d_variable != 0) { + Decorate(state.storage_image_uint_3d_variable, "textures2D_L_U_3D", IR::DescriptorBindingKind::StorageUint3D); } - if (state->sampler_variable != 0) { - Decorate(state->sampler_variable, "samplers", IR::DescriptorBindingKind::Samplers); + if (state.sampler_variable != 0) { + Decorate(state.sampler_variable, "samplers", IR::DescriptorBindingKind::Samplers); } - if (state->gds_variable != 0) { - Decorate(state->gds_variable, "gds", IR::DescriptorBindingKind::Gds); + if (state.gds_variable != 0) { + Decorate(state.gds_variable, "gds", IR::DescriptorBindingKind::Gds); } - if (state->flattened_srt_variable != 0) { - Decorate(state->flattened_srt_variable, "flattened_srt", + if (state.flattened_srt_variable != 0) { + Decorate(state.flattened_srt_variable, "flattened_srt", IR::DescriptorBindingKind::FlattenedSrt); } } -void AddVsharpAnnotationsAndNames(EmitterState* state) { - const auto& bind = state->program->bindings; - if (state->push_constant_variable != 0) { - state->builder.AddName(state->push_constant_block_type, "BufferResource"); - state->builder.AddName(state->push_constant_variable, "vsharp"); - state->builder.AddAnnotation( - {OpDecorate, state->push_constant_u32x4_array_type, DecorationArrayStride, 4}); - state->builder.AddAnnotation( - {OpDecorate, state->push_constant_rows_array_type, DecorationArrayStride, 16}); - state->builder.AddAnnotation({OpMemberDecorate, state->push_constant_block_type, 0, +void AddVsharpAnnotationsAndNames(EmitterState& state) { + const auto& bind = state.program.bindings; + if (state.push_constant_variable != 0) { + state.builder.AddName(state.push_constant_block_type, "BufferResource"); + state.builder.AddName(state.push_constant_variable, "vsharp"); + state.builder.AddAnnotation( + {OpDecorate, state.push_constant_u32x4_array_type, DecorationArrayStride, 4}); + state.builder.AddAnnotation( + {OpDecorate, state.push_constant_rows_array_type, DecorationArrayStride, 16}); + state.builder.AddAnnotation({OpMemberDecorate, state.push_constant_block_type, 0, DecorationOffset, bind.push_constant_offset}); - state->builder.AddAnnotation( - {OpDecorate, state->push_constant_block_type, DecorationBlock}); + state.builder.AddAnnotation( + {OpDecorate, state.push_constant_block_type, DecorationBlock}); } - if (state->vsharp_storage_variable != 0) { - const auto* storage = DescriptorBinding(*state, IR::DescriptorBindingKind::UserData); + if (state.vsharp_storage_variable != 0) { + const auto* storage = DescriptorBinding(state, IR::DescriptorBindingKind::UserData); if (storage != nullptr) { - DecorateDescriptor(state, state->vsharp_storage_variable, "user_data", + DecorateDescriptor(state, state.vsharp_storage_variable, "user_data", bind.descriptor_set, storage->binding); } } } -void EmitHeaderAndTypes(EmitterState* state) { - state->void_type = state->builder.AllocateId(); - state->bool_type = state->builder.AllocateId(); - state->uint_type = state->builder.AllocateId(); - state->uint_pair_type = state->builder.AllocateId(); - state->int_type = state->builder.AllocateId(); - state->int_pair_type = state->builder.AllocateId(); - state->float_type = state->builder.AllocateId(); - state->vec2_uint_type = state->builder.AllocateId(); - state->vec3_uint_type = state->builder.AllocateId(); - state->vec4_uint_type = state->builder.AllocateId(); - state->vec2_int_type = state->builder.AllocateId(); - state->vec3_int_type = state->builder.AllocateId(); - state->vec4_int_type = state->builder.AllocateId(); - state->vec2_float_type = state->builder.AllocateId(); - state->vec3_float_type = state->builder.AllocateId(); - state->vec4_float_type = state->builder.AllocateId(); - state->ptr_func_uint = state->builder.AllocateId(); - state->ptr_input_float = state->builder.AllocateId(); - state->ptr_input_bool = state->builder.AllocateId(); - state->ptr_input_int = state->builder.AllocateId(); - state->ptr_input_uint = state->builder.AllocateId(); - state->ptr_input_vec2_float = state->builder.AllocateId(); - state->ptr_input_vec3_float = state->builder.AllocateId(); - state->ptr_input_vec2_int = state->builder.AllocateId(); - state->ptr_input_vec3_int = state->builder.AllocateId(); - state->ptr_input_vec4_int = state->builder.AllocateId(); - state->ptr_input_vec2_uint = state->builder.AllocateId(); - state->ptr_input_vec3_uint = state->builder.AllocateId(); - state->ptr_input_vec4_uint = state->builder.AllocateId(); - state->ptr_input_vec4_float = state->builder.AllocateId(); - state->sample_mask_array_type = state->builder.AllocateId(); - state->ptr_output_int = state->builder.AllocateId(); - state->ptr_output_sample_mask_array = state->builder.AllocateId(); - state->ptr_output_float = state->builder.AllocateId(); - state->ptr_output_vec4_float = state->builder.AllocateId(); - state->per_vertex_type = state->builder.AllocateId(); - state->ptr_output_per_vertex = state->builder.AllocateId(); - state->storage_runtime_array_type = state->builder.AllocateId(); - state->storage_buffer_type = state->builder.AllocateId(); - state->ptr_storage_buffer = state->builder.AllocateId(); - state->ptr_storage_buffer_uint = state->builder.AllocateId(); - state->storage_buffer_array_type = state->builder.AllocateId(); - state->ptr_storage_buffer_array = state->builder.AllocateId(); - if (state->address_memory_variable != 0) { - state->address_memory_array_type = state->builder.AllocateId(); - state->ptr_address_memory_array = state->builder.AllocateId(); +void EmitHeaderAndTypes(EmitterState& state) { + state.void_type = state.builder.AllocateId(); + state.bool_type = state.builder.AllocateId(); + state.uint_type = state.builder.AllocateId(); + state.uint_pair_type = state.builder.AllocateId(); + state.int_type = state.builder.AllocateId(); + state.int_pair_type = state.builder.AllocateId(); + state.float_type = state.builder.AllocateId(); + state.vec2_uint_type = state.builder.AllocateId(); + state.vec3_uint_type = state.builder.AllocateId(); + state.vec4_uint_type = state.builder.AllocateId(); + state.vec2_int_type = state.builder.AllocateId(); + state.vec3_int_type = state.builder.AllocateId(); + state.vec4_int_type = state.builder.AllocateId(); + state.vec2_float_type = state.builder.AllocateId(); + state.vec3_float_type = state.builder.AllocateId(); + state.vec4_float_type = state.builder.AllocateId(); + state.ptr_func_uint = state.builder.AllocateId(); + state.ptr_input_float = state.builder.AllocateId(); + state.ptr_input_bool = state.builder.AllocateId(); + state.ptr_input_int = state.builder.AllocateId(); + state.ptr_input_uint = state.builder.AllocateId(); + state.ptr_input_vec2_float = state.builder.AllocateId(); + state.ptr_input_vec3_float = state.builder.AllocateId(); + state.ptr_input_vec2_int = state.builder.AllocateId(); + state.ptr_input_vec3_int = state.builder.AllocateId(); + state.ptr_input_vec4_int = state.builder.AllocateId(); + state.ptr_input_vec2_uint = state.builder.AllocateId(); + state.ptr_input_vec3_uint = state.builder.AllocateId(); + state.ptr_input_vec4_uint = state.builder.AllocateId(); + state.ptr_input_vec4_float = state.builder.AllocateId(); + state.sample_mask_array_type = state.builder.AllocateId(); + state.ptr_output_int = state.builder.AllocateId(); + state.ptr_output_sample_mask_array = state.builder.AllocateId(); + state.ptr_output_float = state.builder.AllocateId(); + state.ptr_output_vec4_float = state.builder.AllocateId(); + state.per_vertex_type = state.builder.AllocateId(); + state.ptr_output_per_vertex = state.builder.AllocateId(); + state.storage_runtime_array_type = state.builder.AllocateId(); + state.storage_buffer_type = state.builder.AllocateId(); + state.ptr_storage_buffer = state.builder.AllocateId(); + state.ptr_storage_buffer_uint = state.builder.AllocateId(); + state.storage_buffer_array_type = state.builder.AllocateId(); + state.ptr_storage_buffer_array = state.builder.AllocateId(); + if (state.address_memory_variable != 0) { + state.address_memory_array_type = state.builder.AllocateId(); + state.ptr_address_memory_array = state.builder.AllocateId(); } - if (state->push_constant_variable != 0) { - state->push_constant_u32x4_array_type = state->builder.AllocateId(); - state->push_constant_rows_array_type = state->builder.AllocateId(); - state->push_constant_block_type = state->builder.AllocateId(); - state->ptr_push_constant_block = state->builder.AllocateId(); - state->ptr_push_constant_uint = state->builder.AllocateId(); + if (state.push_constant_variable != 0) { + state.push_constant_u32x4_array_type = state.builder.AllocateId(); + state.push_constant_rows_array_type = state.builder.AllocateId(); + state.push_constant_block_type = state.builder.AllocateId(); + state.ptr_push_constant_block = state.builder.AllocateId(); + state.ptr_push_constant_uint = state.builder.AllocateId(); } - state->lds_array_type = state->builder.AllocateId(); - state->ptr_workgroup_array = state->builder.AllocateId(); - state->ptr_workgroup_uint = state->builder.AllocateId(); - state->lds_variable = state->builder.AllocateId(); - for (auto& image: state->sampled_images) { - image.image_type = state->builder.AllocateId(); - image.sampled_image_type = state->builder.AllocateId(); - image.pointer_type = state->builder.AllocateId(); - image.array_type = state->builder.AllocateId(); - image.array_pointer_type = state->builder.AllocateId(); + state.lds_array_type = state.builder.AllocateId(); + state.ptr_workgroup_array = state.builder.AllocateId(); + state.ptr_workgroup_uint = state.builder.AllocateId(); + state.lds_variable = state.builder.AllocateId(); + for (auto& image: state.sampled_images) { + image.image_type = state.builder.AllocateId(); + image.sampled_image_type = state.builder.AllocateId(); + image.pointer_type = state.builder.AllocateId(); + image.array_type = state.builder.AllocateId(); + image.array_pointer_type = state.builder.AllocateId(); } - state->sampler_type = state->builder.AllocateId(); - state->sampler_array_type = state->builder.AllocateId(); - state->ptr_uniform_sampler = state->builder.AllocateId(); - state->ptr_uniform_sampler_array = state->builder.AllocateId(); - state->storage_image_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image = state->builder.AllocateId(); - state->storage_image_array_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_array = state->builder.AllocateId(); - state->storage_image_2d_array_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_2d_array = state->builder.AllocateId(); - state->storage_image_2d_array_array_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_2d_array_array = state->builder.AllocateId(); - state->storage_image_3d_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_3d = state->builder.AllocateId(); - state->storage_image_3d_array_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_3d_array = state->builder.AllocateId(); - state->storage_image_uint_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_uint = state->builder.AllocateId(); - state->storage_image_uint_array_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_uint_array = state->builder.AllocateId(); - state->storage_image_uint_2d_array_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_uint_2d_array = state->builder.AllocateId(); - state->storage_image_uint_2d_array_array_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_uint_2d_array_array = state->builder.AllocateId(); - state->storage_image_uint_3d_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_uint_3d = state->builder.AllocateId(); - state->storage_image_uint_3d_array_type = state->builder.AllocateId(); - state->ptr_uniform_storage_image_uint_3d_array = state->builder.AllocateId(); - state->ptr_image_uint = state->builder.AllocateId(); - state->func_type = state->builder.AllocateId(); - state->main_func = state->builder.AllocateId(); - state->entry_label = state->builder.AllocateId(); - state->glsl_std450 = state->builder.AllocateId(); + state.sampler_type = state.builder.AllocateId(); + state.sampler_array_type = state.builder.AllocateId(); + state.ptr_uniform_sampler = state.builder.AllocateId(); + state.ptr_uniform_sampler_array = state.builder.AllocateId(); + state.storage_image_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image = state.builder.AllocateId(); + state.storage_image_array_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_array = state.builder.AllocateId(); + state.storage_image_2d_array_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_2d_array = state.builder.AllocateId(); + state.storage_image_2d_array_array_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_2d_array_array = state.builder.AllocateId(); + state.storage_image_3d_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_3d = state.builder.AllocateId(); + state.storage_image_3d_array_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_3d_array = state.builder.AllocateId(); + state.storage_image_uint_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_uint = state.builder.AllocateId(); + state.storage_image_uint_array_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_uint_array = state.builder.AllocateId(); + state.storage_image_uint_2d_array_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_uint_2d_array = state.builder.AllocateId(); + state.storage_image_uint_2d_array_array_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_uint_2d_array_array = state.builder.AllocateId(); + state.storage_image_uint_3d_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_uint_3d = state.builder.AllocateId(); + state.storage_image_uint_3d_array_type = state.builder.AllocateId(); + state.ptr_uniform_storage_image_uint_3d_array = state.builder.AllocateId(); + state.ptr_image_uint = state.builder.AllocateId(); + state.func_type = state.builder.AllocateId(); + state.main_func = state.builder.AllocateId(); + state.entry_label = state.builder.AllocateId(); + state.glsl_std450 = state.builder.AllocateId(); - state->builder.AddCapability({CapabilityShader}); - state->builder.AddCapability({CapabilityImageQuery}); - if (state->needs_image_gather_extended) { - state->builder.AddCapability({CapabilityImageGatherExtended}); + state.builder.AddCapability({CapabilityShader}); + state.builder.AddCapability({CapabilityImageQuery}); + if (state.needs_image_gather_extended) { + state.builder.AddCapability({CapabilityImageGatherExtended}); } - if (state->storage_image_variable != 0 || state->storage_image_2d_array_variable != 0 || - state->storage_image_3d_variable != 0) { - state->builder.AddCapability({CapabilityStorageImageReadWithoutFormat}); - state->builder.AddCapability({CapabilityStorageImageWriteWithoutFormat}); + if (state.storage_image_variable != 0 || state.storage_image_2d_array_variable != 0 || + state.storage_image_3d_variable != 0) { + state.builder.AddCapability({CapabilityStorageImageReadWithoutFormat}); + state.builder.AddCapability({CapabilityStorageImageWriteWithoutFormat}); } - if (state->needs_subgroup_ballot || state->needs_subgroup_shuffle || - state->needs_subgroup_local_invocation_id) { - state->builder.AddCapability({CapabilityGroupNonUniform}); + if (state.needs_subgroup_ballot || state.needs_subgroup_shuffle || + state.needs_subgroup_local_invocation_id) { + state.builder.AddCapability({CapabilityGroupNonUniform}); } - if (state->needs_subgroup_ballot) { - state->builder.AddCapability({CapabilityGroupNonUniformBallot}); + if (state.needs_subgroup_ballot) { + state.builder.AddCapability({CapabilityGroupNonUniformBallot}); } - if (state->needs_subgroup_shuffle) { - state->builder.AddCapability({CapabilityGroupNonUniformShuffle}); + if (state.needs_subgroup_shuffle) { + state.builder.AddCapability({CapabilityGroupNonUniformShuffle}); } - if (state->needs_compute_derivatives && state->stage == ShaderType::Compute) { - state->builder.AddCapability({CapabilityComputeDerivativeGroupQuadsKHR}); - state->builder.AddExtension("SPV_KHR_compute_shader_derivatives"); + if (state.needs_compute_derivatives && state.stage == ShaderType::Compute) { + state.builder.AddCapability({CapabilityComputeDerivativeGroupQuadsKHR}); + state.builder.AddExtension("SPV_KHR_compute_shader_derivatives"); } - state->builder.AddExtInstImport(state->glsl_std450, "GLSL.std.450"); - state->builder.AddMemoryModel({AddressingModelLogical, MemoryModelGLSL450}); - state->builder.AddEntryPoint(ExecutionModelForStage(state->stage), state->main_func, "main", - state->interface_variables); - if (state->stage == ShaderType::Compute) { - uint32_t local_x = state->needs_compute_derivatives ? 2u : 1u; - uint32_t local_y = state->needs_compute_derivatives ? 2u : 1u; + state.builder.AddExtInstImport(state.glsl_std450, "GLSL.std.450"); + state.builder.AddMemoryModel({AddressingModelLogical, MemoryModelGLSL450}); + state.builder.AddEntryPoint(ExecutionModelForStage(state.stage), state.main_func, "main", + state.interface_variables); + if (state.stage == ShaderType::Compute) { + uint32_t local_x = state.needs_compute_derivatives ? 2u : 1u; + uint32_t local_y = state.needs_compute_derivatives ? 2u : 1u; uint32_t local_z = 1u; - if (state->compute_input_info != nullptr) { - const auto* cs = state->compute_input_info; + if (state.compute_input_info != nullptr) { + const auto* cs = state.compute_input_info; local_x = cs->threads_num[0] != 0u ? cs->threads_num[0] : local_x; local_y = cs->threads_num[1] != 0u ? cs->threads_num[1] : local_y; local_z = cs->threads_num[2] != 0u ? cs->threads_num[2] : local_z; } - state->builder.AddExecutionMode( - {state->main_func, ExecutionModeLocalSize, local_x, local_y, local_z}); + state.builder.AddExecutionMode( + {state.main_func, ExecutionModeLocalSize, local_x, local_y, local_z}); } - if (state->stage == ShaderType::Pixel) { - state->builder.AddExecutionMode({state->main_func, ExecutionModeOriginUpperLeft}); - if (state->depth_variable != 0) { - state->builder.AddExecutionMode({state->main_func, ExecutionModeDepthReplacing}); + if (state.stage == ShaderType::Pixel) { + state.builder.AddExecutionMode({state.main_func, ExecutionModeOriginUpperLeft}); + if (state.depth_variable != 0) { + state.builder.AddExecutionMode({state.main_func, ExecutionModeDepthReplacing}); } - if (state->pixel_input_info != nullptr && state->pixel_input_info->ps_early_z && - !state->pixel_input_info->ps_pixel_kill_enable && - !state->pixel_input_info->ps_depth_export_enable && - !state->pixel_input_info->ps_sample_mask_export_enable) { - state->builder.AddExecutionMode({state->main_func, ExecutionModeEarlyFragmentTests}); + if (state.pixel_input_info != nullptr && state.pixel_input_info->ps_early_z && + !state.pixel_input_info->ps_pixel_kill_enable && + !state.pixel_input_info->ps_depth_export_enable && + !state.pixel_input_info->ps_sample_mask_export_enable) { + state.builder.AddExecutionMode({state.main_func, ExecutionModeEarlyFragmentTests}); } } - if (state->needs_compute_derivatives && state->stage == ShaderType::Compute) { - state->builder.AddExecutionMode({state->main_func, ExecutionModeDerivativeGroupQuadsKHR}); + if (state.needs_compute_derivatives && state.stage == ShaderType::Compute) { + state.builder.AddExecutionMode({state.main_func, ExecutionModeDerivativeGroupQuadsKHR}); } - state->builder.AddName(state->main_func, "main"); - if (state->stage == ShaderType::Compute || state->needs_function_lds) { - state->builder.AddName(state->lds_variable, "lds_dwords"); + state.builder.AddName(state.main_func, "main"); + if (state.stage == ShaderType::Compute || state.needs_function_lds) { + state.builder.AddName(state.lds_variable, "lds_dwords"); } AddInputAnnotationsAndNames(state); AddOutputAnnotationsAndNames(state); AddDescriptorAnnotationsAndNames(state); AddVsharpAnnotationsAndNames(state); - state->builder.AddAnnotation( - {OpDecorate, state->storage_runtime_array_type, DecorationArrayStride, 4}); - state->builder.AddAnnotation( - {OpMemberDecorate, state->storage_buffer_type, 0, DecorationOffset, 0}); - state->builder.AddAnnotation({OpDecorate, state->storage_buffer_type, DecorationBlock}); + state.builder.AddAnnotation( + {OpDecorate, state.storage_runtime_array_type, DecorationArrayStride, 4}); + state.builder.AddAnnotation( + {OpMemberDecorate, state.storage_buffer_type, 0, DecorationOffset, 0}); + state.builder.AddAnnotation({OpDecorate, state.storage_buffer_type, DecorationBlock}); - state->builder.AddType({OpTypeVoid, state->void_type}); - state->builder.AddType({OpTypeBool, state->bool_type}); - state->builder.AddType({OpTypeInt, state->uint_type, 32, 0}); - state->builder.AddType( - {OpTypeStruct, state->uint_pair_type, state->uint_type, state->uint_type}); - state->builder.AddType({OpTypeInt, state->int_type, 32, 1}); - state->builder.AddType({OpTypeStruct, state->int_pair_type, state->int_type, state->int_type}); - state->builder.AddType({OpTypeFloat, state->float_type, 32}); - state->builder.AddType({OpTypeVector, state->vec2_uint_type, state->uint_type, 2}); - state->builder.AddType({OpTypeVector, state->vec3_uint_type, state->uint_type, 3}); - state->builder.AddType({OpTypeVector, state->vec4_uint_type, state->uint_type, 4}); - state->builder.AddType({OpTypeVector, state->vec2_int_type, state->int_type, 2}); - state->builder.AddType({OpTypeVector, state->vec3_int_type, state->int_type, 3}); - state->builder.AddType({OpTypeVector, state->vec4_int_type, state->int_type, 4}); - state->builder.AddType({OpTypeVector, state->vec2_float_type, state->float_type, 2}); - state->builder.AddType({OpTypeVector, state->vec3_float_type, state->float_type, 3}); - state->builder.AddType({OpTypeVector, state->vec4_float_type, state->float_type, 4}); - state->builder.AddType( - {OpTypePointer, state->ptr_func_uint, StorageClassFunction, state->uint_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_float, StorageClassInput, state->float_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_bool, StorageClassInput, state->bool_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_int, StorageClassInput, state->int_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_uint, StorageClassInput, state->uint_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec2_float, StorageClassInput, state->vec2_float_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec3_float, StorageClassInput, state->vec3_float_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec2_int, StorageClassInput, state->vec2_int_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec3_int, StorageClassInput, state->vec3_int_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec4_int, StorageClassInput, state->vec4_int_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec2_uint, StorageClassInput, state->vec2_uint_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec3_uint, StorageClassInput, state->vec3_uint_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec4_uint, StorageClassInput, state->vec4_uint_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_input_vec4_float, StorageClassInput, state->vec4_float_type}); - if (state->subgroup_local_invocation_id_variable != 0) { - state->builder.AddType({OpVariable, state->ptr_input_uint, - state->subgroup_local_invocation_id_variable, StorageClassInput}); + state.builder.AddType({OpTypeVoid, state.void_type}); + state.builder.AddType({OpTypeBool, state.bool_type}); + state.builder.AddType({OpTypeInt, state.uint_type, 32, 0}); + state.builder.AddType( + {OpTypeStruct, state.uint_pair_type, state.uint_type, state.uint_type}); + state.builder.AddType({OpTypeInt, state.int_type, 32, 1}); + state.builder.AddType({OpTypeStruct, state.int_pair_type, state.int_type, state.int_type}); + state.builder.AddType({OpTypeFloat, state.float_type, 32}); + state.builder.AddType({OpTypeVector, state.vec2_uint_type, state.uint_type, 2}); + state.builder.AddType({OpTypeVector, state.vec3_uint_type, state.uint_type, 3}); + state.builder.AddType({OpTypeVector, state.vec4_uint_type, state.uint_type, 4}); + state.builder.AddType({OpTypeVector, state.vec2_int_type, state.int_type, 2}); + state.builder.AddType({OpTypeVector, state.vec3_int_type, state.int_type, 3}); + state.builder.AddType({OpTypeVector, state.vec4_int_type, state.int_type, 4}); + state.builder.AddType({OpTypeVector, state.vec2_float_type, state.float_type, 2}); + state.builder.AddType({OpTypeVector, state.vec3_float_type, state.float_type, 3}); + state.builder.AddType({OpTypeVector, state.vec4_float_type, state.float_type, 4}); + state.builder.AddType( + {OpTypePointer, state.ptr_func_uint, StorageClassFunction, state.uint_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_float, StorageClassInput, state.float_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_bool, StorageClassInput, state.bool_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_int, StorageClassInput, state.int_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_uint, StorageClassInput, state.uint_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec2_float, StorageClassInput, state.vec2_float_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec3_float, StorageClassInput, state.vec3_float_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec2_int, StorageClassInput, state.vec2_int_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec3_int, StorageClassInput, state.vec3_int_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec4_int, StorageClassInput, state.vec4_int_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec2_uint, StorageClassInput, state.vec2_uint_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec3_uint, StorageClassInput, state.vec3_uint_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec4_uint, StorageClassInput, state.vec4_uint_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_input_vec4_float, StorageClassInput, state.vec4_float_type}); + if (state.subgroup_local_invocation_id_variable != 0) { + state.builder.AddType({OpVariable, state.ptr_input_uint, + state.subgroup_local_invocation_id_variable, StorageClassInput}); } - for (const auto& input: state->inputs) { - uint32_t ptr_type = state->ptr_input_uint; + for (const auto& input: state.inputs) { + uint32_t ptr_type = state.ptr_input_uint; switch (input.kind) { case IR::StageInputKind::VertexIndex: - case IR::StageInputKind::InstanceIndex: ptr_type = state->ptr_input_int; break; + case IR::StageInputKind::InstanceIndex: ptr_type = state.ptr_input_int; break; case IR::StageInputKind::WorkgroupId: case IR::StageInputKind::LocalInvocationId: case IR::StageInputKind::GlobalInvocationId: - ptr_type = state->ptr_input_vec3_uint; + ptr_type = state.ptr_input_vec3_uint; break; - case IR::StageInputKind::FragCoord: ptr_type = state->ptr_input_vec4_float; break; - case IR::StageInputKind::FrontFacing: ptr_type = state->ptr_input_bool; break; + case IR::StageInputKind::FragCoord: ptr_type = state.ptr_input_vec4_float; break; + case IR::StageInputKind::FrontFacing: ptr_type = state.ptr_input_bool; break; case IR::StageInputKind::Parameter: - if (state->stage == ShaderType::Vertex) { - const auto kind = VertexParameterScalarKind(*state, input.location); - const auto components = VertexParameterComponentCount(*state, input); - ptr_type = VertexParameterInputPointerType(*state, kind, components); + if (state.stage == ShaderType::Vertex) { + const auto kind = VertexParameterScalarKind(state, input.location); + const auto components = VertexParameterComponentCount(state, input); + ptr_type = VertexParameterInputPointerType(state, kind, components); } else { - ptr_type = state->ptr_input_vec4_float; + ptr_type = state.ptr_input_vec4_float; } break; default: break; } - state->builder.AddType({OpVariable, ptr_type, input.variable_id, StorageClassInput}); + state.builder.AddType({OpVariable, ptr_type, input.variable_id, StorageClassInput}); } - state->builder.AddType( - {OpTypePointer, state->ptr_output_float, StorageClassOutput, state->float_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_output_int, StorageClassOutput, state->int_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_output_vec4_float, StorageClassOutput, state->vec4_float_type}); - if (state->per_vertex_variable != 0) { - state->builder.AddType({OpTypeStruct, state->per_vertex_type, state->vec4_float_type}); - state->builder.AddType({OpTypePointer, state->ptr_output_per_vertex, StorageClassOutput, - state->per_vertex_type}); - state->builder.AddType({OpVariable, state->ptr_output_per_vertex, - state->per_vertex_variable, StorageClassOutput}); + state.builder.AddType( + {OpTypePointer, state.ptr_output_float, StorageClassOutput, state.float_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_output_int, StorageClassOutput, state.int_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_output_vec4_float, StorageClassOutput, state.vec4_float_type}); + if (state.per_vertex_variable != 0) { + state.builder.AddType({OpTypeStruct, state.per_vertex_type, state.vec4_float_type}); + state.builder.AddType({OpTypePointer, state.ptr_output_per_vertex, StorageClassOutput, + state.per_vertex_type}); + state.builder.AddType({OpVariable, state.ptr_output_per_vertex, + state.per_vertex_variable, StorageClassOutput}); } - for (const auto& binding: state->outputs) { + for (const auto& binding: state.outputs) { if (binding.kind == IR::StageOutputKind::Parameter || binding.kind == IR::StageOutputKind::Mrt) { - state->builder.AddType({OpVariable, state->ptr_output_vec4_float, binding.variable_id, + state.builder.AddType({OpVariable, state.ptr_output_vec4_float, binding.variable_id, StorageClassOutput}); } } - if (state->depth_variable != 0) { - state->builder.AddType( - {OpVariable, state->ptr_output_float, state->depth_variable, StorageClassOutput}); + if (state.depth_variable != 0) { + state.builder.AddType( + {OpVariable, state.ptr_output_float, state.depth_variable, StorageClassOutput}); } - if (state->sample_mask_variable != 0) { - state->builder.AddType( - {OpTypeArray, state->sample_mask_array_type, state->int_type, ConstantU32(state, 1)}); - state->builder.AddType({OpTypePointer, state->ptr_output_sample_mask_array, - StorageClassOutput, state->sample_mask_array_type}); - state->builder.AddType({OpVariable, state->ptr_output_sample_mask_array, - state->sample_mask_variable, StorageClassOutput}); + if (state.sample_mask_variable != 0) { + state.builder.AddType( + {OpTypeArray, state.sample_mask_array_type, state.int_type, ConstantU32(state, 1)}); + state.builder.AddType({OpTypePointer, state.ptr_output_sample_mask_array, + StorageClassOutput, state.sample_mask_array_type}); + state.builder.AddType({OpVariable, state.ptr_output_sample_mask_array, + state.sample_mask_variable, StorageClassOutput}); } - state->builder.AddType( - {OpTypeRuntimeArray, state->storage_runtime_array_type, state->uint_type}); - state->builder.AddType( - {OpTypeStruct, state->storage_buffer_type, state->storage_runtime_array_type}); - state->builder.AddType({OpTypePointer, state->ptr_storage_buffer, StorageClassStorageBuffer, - state->storage_buffer_type}); - state->builder.AddType({OpTypePointer, state->ptr_storage_buffer_uint, - StorageClassStorageBuffer, state->uint_type}); - if (state->storage_buffer_variable != 0) { + state.builder.AddType( + {OpTypeRuntimeArray, state.storage_runtime_array_type, state.uint_type}); + state.builder.AddType( + {OpTypeStruct, state.storage_buffer_type, state.storage_runtime_array_type}); + state.builder.AddType({OpTypePointer, state.ptr_storage_buffer, StorageClassStorageBuffer, + state.storage_buffer_type}); + state.builder.AddType({OpTypePointer, state.ptr_storage_buffer_uint, + StorageClassStorageBuffer, state.uint_type}); + if (state.storage_buffer_variable != 0) { const auto count = - ConstantU32(state, DescriptorCount(*state, IR::DescriptorBindingKind::Buffers)); - state->builder.AddType( - {OpTypeArray, state->storage_buffer_array_type, state->storage_buffer_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_storage_buffer_array, - StorageClassStorageBuffer, state->storage_buffer_array_type}); - state->builder.AddType({OpVariable, state->ptr_storage_buffer_array, - state->storage_buffer_variable, StorageClassStorageBuffer}); + ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Buffers)); + state.builder.AddType( + {OpTypeArray, state.storage_buffer_array_type, state.storage_buffer_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_storage_buffer_array, + StorageClassStorageBuffer, state.storage_buffer_array_type}); + state.builder.AddType({OpVariable, state.ptr_storage_buffer_array, + state.storage_buffer_variable, StorageClassStorageBuffer}); } - if (state->gds_variable != 0) { - state->builder.AddType({OpVariable, state->ptr_storage_buffer, state->gds_variable, + if (state.gds_variable != 0) { + state.builder.AddType({OpVariable, state.ptr_storage_buffer, state.gds_variable, StorageClassStorageBuffer}); } - if (state->push_constant_variable != 0) { + if (state.push_constant_variable != 0) { const auto row_width = ConstantU32(state, 4); const auto row_count = ConstantU32( - state, std::max((state->program->bindings.push_constant_size + 15u) / 16u, 1u)); - state->builder.AddType( - {OpTypeArray, state->push_constant_u32x4_array_type, state->uint_type, row_width}); - state->builder.AddType({OpTypeArray, state->push_constant_rows_array_type, - state->push_constant_u32x4_array_type, row_count}); - state->builder.AddType( - {OpTypeStruct, state->push_constant_block_type, state->push_constant_rows_array_type}); - state->builder.AddType({OpTypePointer, state->ptr_push_constant_block, - StorageClassPushConstant, state->push_constant_block_type}); - state->builder.AddType({OpTypePointer, state->ptr_push_constant_uint, - StorageClassPushConstant, state->uint_type}); - state->builder.AddType({OpVariable, state->ptr_push_constant_block, - state->push_constant_variable, StorageClassPushConstant}); + state, std::max((state.program.bindings.push_constant_size + 15u) / 16u, 1u)); + state.builder.AddType( + {OpTypeArray, state.push_constant_u32x4_array_type, state.uint_type, row_width}); + state.builder.AddType({OpTypeArray, state.push_constant_rows_array_type, + state.push_constant_u32x4_array_type, row_count}); + state.builder.AddType( + {OpTypeStruct, state.push_constant_block_type, state.push_constant_rows_array_type}); + state.builder.AddType({OpTypePointer, state.ptr_push_constant_block, + StorageClassPushConstant, state.push_constant_block_type}); + state.builder.AddType({OpTypePointer, state.ptr_push_constant_uint, + StorageClassPushConstant, state.uint_type}); + state.builder.AddType({OpVariable, state.ptr_push_constant_block, + state.push_constant_variable, StorageClassPushConstant}); } - if (state->vsharp_storage_variable != 0) { - state->builder.AddType({OpVariable, state->ptr_storage_buffer, - state->vsharp_storage_variable, StorageClassStorageBuffer}); + if (state.vsharp_storage_variable != 0) { + state.builder.AddType({OpVariable, state.ptr_storage_buffer, + state.vsharp_storage_variable, StorageClassStorageBuffer}); } - if (state->address_memory_variable != 0) { + if (state.address_memory_variable != 0) { const auto count = - ConstantU32(state, DescriptorCount(*state, IR::DescriptorBindingKind::AddressMemory)); - state->builder.AddType( - {OpTypeArray, state->address_memory_array_type, state->storage_buffer_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_address_memory_array, - StorageClassStorageBuffer, state->address_memory_array_type}); - state->builder.AddType({OpVariable, state->ptr_address_memory_array, - state->address_memory_variable, StorageClassStorageBuffer}); + ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::AddressMemory)); + state.builder.AddType( + {OpTypeArray, state.address_memory_array_type, state.storage_buffer_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_address_memory_array, + StorageClassStorageBuffer, state.address_memory_array_type}); + state.builder.AddType({OpVariable, state.ptr_address_memory_array, + state.address_memory_variable, StorageClassStorageBuffer}); } - if (state->flattened_srt_variable != 0) { - state->builder.AddType({OpVariable, state->ptr_storage_buffer, - state->flattened_srt_variable, StorageClassStorageBuffer}); + if (state.flattened_srt_variable != 0) { + state.builder.AddType({OpVariable, state.ptr_storage_buffer, + state.flattened_srt_variable, StorageClassStorageBuffer}); } - if (state->stage == ShaderType::Compute || state->needs_function_lds) { + if (state.stage == ShaderType::Compute || state.needs_function_lds) { const auto storage_class = - state->needs_function_lds ? StorageClassFunction : StorageClassWorkgroup; - const auto lds_size = ConstantU32(state, state->needs_function_lds ? 8192u : 1024u); - state->builder.AddType({OpTypeArray, state->lds_array_type, state->uint_type, lds_size}); - state->builder.AddType( - {OpTypePointer, state->ptr_workgroup_array, storage_class, state->lds_array_type}); - state->builder.AddType( - {OpTypePointer, state->ptr_workgroup_uint, storage_class, state->uint_type}); - if (state->stage == ShaderType::Compute) { - state->builder.AddType({OpVariable, state->ptr_workgroup_array, state->lds_variable, + state.needs_function_lds ? StorageClassFunction : StorageClassWorkgroup; + const auto lds_size = ConstantU32(state, state.needs_function_lds ? 8192u : 1024u); + state.builder.AddType({OpTypeArray, state.lds_array_type, state.uint_type, lds_size}); + state.builder.AddType( + {OpTypePointer, state.ptr_workgroup_array, storage_class, state.lds_array_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_workgroup_uint, storage_class, state.uint_type}); + if (state.stage == ShaderType::Compute) { + state.builder.AddType({OpVariable, state.ptr_workgroup_array, state.lds_variable, StorageClassWorkgroup}); } } - for (uint32_t i = 0; i < state->sampled_images.size(); i++) { - auto& image = state->sampled_images[i]; + for (uint32_t i = 0; i < state.sampled_images.size(); i++) { + auto& image = state.sampled_images[i]; const auto view = static_cast(i % 3u); - const auto component = i >= 3u ? state->uint_type : state->float_type; + const auto component = i >= 3u ? state.uint_type : state.float_type; const auto dimension = view == ImageViewKind::Dim3D ? Dim3D : Dim2D; const auto arrayed = view == ImageViewKind::Dim2DArray ? 1u : 0u; - state->builder.AddType({OpTypeImage, image.image_type, component, dimension, 0, arrayed, 0, + state.builder.AddType({OpTypeImage, image.image_type, component, dimension, 0, arrayed, 0, 1, ImageFormatUnknown}); - state->builder.AddType({OpTypeSampledImage, image.sampled_image_type, image.image_type}); - state->builder.AddType( + state.builder.AddType({OpTypeSampledImage, image.sampled_image_type, image.image_type}); + state.builder.AddType( {OpTypePointer, image.pointer_type, StorageClassUniformConstant, image.image_type}); if (image.variable != 0) { const auto kind = SampledBindingKind(i >= 3u, view); - const auto count = ConstantU32(state, DescriptorCount(*state, kind)); - state->builder.AddType({OpTypeArray, image.array_type, image.image_type, count}); - state->builder.AddType({OpTypePointer, image.array_pointer_type, + const auto count = ConstantU32(state, DescriptorCount(state, kind)); + state.builder.AddType({OpTypeArray, image.array_type, image.image_type, count}); + state.builder.AddType({OpTypePointer, image.array_pointer_type, StorageClassUniformConstant, image.array_type}); - state->builder.AddType({OpVariable, image.array_pointer_type, image.variable, + state.builder.AddType({OpVariable, image.array_pointer_type, image.variable, StorageClassUniformConstant}); } } - state->builder.AddType({OpTypeSampler, state->sampler_type}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_sampler, StorageClassUniformConstant, - state->sampler_type}); - if (state->sampler_variable != 0) { + state.builder.AddType({OpTypeSampler, state.sampler_type}); + state.builder.AddType({OpTypePointer, state.ptr_uniform_sampler, StorageClassUniformConstant, + state.sampler_type}); + if (state.sampler_variable != 0) { const auto count = - ConstantU32(state, DescriptorCount(*state, IR::DescriptorBindingKind::Samplers)); - state->builder.AddType( - {OpTypeArray, state->sampler_array_type, state->sampler_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_sampler_array, - StorageClassUniformConstant, state->sampler_array_type}); - state->builder.AddType({OpVariable, state->ptr_uniform_sampler_array, - state->sampler_variable, StorageClassUniformConstant}); + ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Samplers)); + state.builder.AddType( + {OpTypeArray, state.sampler_array_type, state.sampler_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_uniform_sampler_array, + StorageClassUniformConstant, state.sampler_array_type}); + state.builder.AddType({OpVariable, state.ptr_uniform_sampler_array, + state.sampler_variable, StorageClassUniformConstant}); } - state->builder.AddType({OpTypeImage, state->storage_image_type, state->float_type, Dim2D, 0, 0, + state.builder.AddType({OpTypeImage, state.storage_image_type, state.float_type, Dim2D, 0, 0, 0, 2, ImageFormatUnknown}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image, - StorageClassUniformConstant, state->storage_image_type}); - if (state->storage_image_variable != 0) { + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image, + StorageClassUniformConstant, state.storage_image_type}); + if (state.storage_image_variable != 0) { const auto count = - ConstantU32(state, DescriptorCount(*state, IR::DescriptorBindingKind::Storage2D)); - state->builder.AddType( - {OpTypeArray, state->storage_image_array_type, state->storage_image_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_array, - StorageClassUniformConstant, state->storage_image_array_type}); - state->builder.AddType({OpVariable, state->ptr_uniform_storage_image_array, - state->storage_image_variable, StorageClassUniformConstant}); + ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Storage2D)); + state.builder.AddType( + {OpTypeArray, state.storage_image_array_type, state.storage_image_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_array, + StorageClassUniformConstant, state.storage_image_array_type}); + state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_array, + state.storage_image_variable, StorageClassUniformConstant}); } - state->builder.AddType({OpTypeImage, state->storage_image_2d_array_type, state->float_type, + state.builder.AddType({OpTypeImage, state.storage_image_2d_array_type, state.float_type, Dim2D, 0, 1, 0, 2, ImageFormatUnknown}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_2d_array, - StorageClassUniformConstant, state->storage_image_2d_array_type}); - if (state->storage_image_2d_array_variable != 0) { + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_2d_array, + StorageClassUniformConstant, state.storage_image_2d_array_type}); + if (state.storage_image_2d_array_variable != 0) { const auto count = - ConstantU32(state, DescriptorCount(*state, IR::DescriptorBindingKind::Storage2DArray)); - state->builder.AddType({OpTypeArray, state->storage_image_2d_array_array_type, - state->storage_image_2d_array_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_2d_array_array, + ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Storage2DArray)); + state.builder.AddType({OpTypeArray, state.storage_image_2d_array_array_type, + state.storage_image_2d_array_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_2d_array_array, StorageClassUniformConstant, - state->storage_image_2d_array_array_type}); - state->builder.AddType({OpVariable, state->ptr_uniform_storage_image_2d_array_array, - state->storage_image_2d_array_variable, + state.storage_image_2d_array_array_type}); + state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_2d_array_array, + state.storage_image_2d_array_variable, StorageClassUniformConstant}); } - state->builder.AddType({OpTypeImage, state->storage_image_3d_type, state->float_type, Dim3D, 0, + state.builder.AddType({OpTypeImage, state.storage_image_3d_type, state.float_type, Dim3D, 0, 0, 0, 2, ImageFormatUnknown}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_3d, - StorageClassUniformConstant, state->storage_image_3d_type}); - if (state->storage_image_3d_variable != 0) { + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_3d, + StorageClassUniformConstant, state.storage_image_3d_type}); + if (state.storage_image_3d_variable != 0) { const auto count = - ConstantU32(state, DescriptorCount(*state, IR::DescriptorBindingKind::Storage3D)); - state->builder.AddType( - {OpTypeArray, state->storage_image_3d_array_type, state->storage_image_3d_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_3d_array, - StorageClassUniformConstant, state->storage_image_3d_array_type}); - state->builder.AddType({OpVariable, state->ptr_uniform_storage_image_3d_array, - state->storage_image_3d_variable, StorageClassUniformConstant}); + ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Storage3D)); + state.builder.AddType( + {OpTypeArray, state.storage_image_3d_array_type, state.storage_image_3d_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_3d_array, + StorageClassUniformConstant, state.storage_image_3d_array_type}); + state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_3d_array, + state.storage_image_3d_variable, StorageClassUniformConstant}); } - state->builder.AddType({OpTypeImage, state->storage_image_uint_type, state->uint_type, Dim2D, 0, + state.builder.AddType({OpTypeImage, state.storage_image_uint_type, state.uint_type, Dim2D, 0, 0, 0, 2, ImageFormatR32ui}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_uint, - StorageClassUniformConstant, state->storage_image_uint_type}); - if (state->storage_image_uint_variable != 0) { + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint, + StorageClassUniformConstant, state.storage_image_uint_type}); + if (state.storage_image_uint_variable != 0) { const auto count = - ConstantU32(state, DescriptorCount(*state, IR::DescriptorBindingKind::StorageUint2D)); - state->builder.AddType({OpTypeArray, state->storage_image_uint_array_type, - state->storage_image_uint_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_uint_array, - StorageClassUniformConstant, state->storage_image_uint_array_type}); - state->builder.AddType({OpVariable, state->ptr_uniform_storage_image_uint_array, - state->storage_image_uint_variable, StorageClassUniformConstant}); + ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::StorageUint2D)); + state.builder.AddType({OpTypeArray, state.storage_image_uint_array_type, + state.storage_image_uint_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_array, + StorageClassUniformConstant, state.storage_image_uint_array_type}); + state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_uint_array, + state.storage_image_uint_variable, StorageClassUniformConstant}); } - state->builder.AddType({OpTypeImage, state->storage_image_uint_2d_array_type, state->uint_type, + state.builder.AddType({OpTypeImage, state.storage_image_uint_2d_array_type, state.uint_type, Dim2D, 0, 1, 0, 2, ImageFormatR32ui}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_uint_2d_array, - StorageClassUniformConstant, state->storage_image_uint_2d_array_type}); - if (state->storage_image_uint_2d_array_variable != 0) { + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_2d_array, + StorageClassUniformConstant, state.storage_image_uint_2d_array_type}); + if (state.storage_image_uint_2d_array_variable != 0) { const auto count = ConstantU32( - state, DescriptorCount(*state, IR::DescriptorBindingKind::StorageUint2DArray)); - state->builder.AddType({OpTypeArray, state->storage_image_uint_2d_array_array_type, - state->storage_image_uint_2d_array_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_uint_2d_array_array, + state, DescriptorCount(state, IR::DescriptorBindingKind::StorageUint2DArray)); + state.builder.AddType({OpTypeArray, state.storage_image_uint_2d_array_array_type, + state.storage_image_uint_2d_array_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_2d_array_array, StorageClassUniformConstant, - state->storage_image_uint_2d_array_array_type}); - state->builder.AddType({OpVariable, state->ptr_uniform_storage_image_uint_2d_array_array, - state->storage_image_uint_2d_array_variable, + state.storage_image_uint_2d_array_array_type}); + state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_uint_2d_array_array, + state.storage_image_uint_2d_array_variable, StorageClassUniformConstant}); } - state->builder.AddType({OpTypeImage, state->storage_image_uint_3d_type, state->uint_type, Dim3D, + state.builder.AddType({OpTypeImage, state.storage_image_uint_3d_type, state.uint_type, Dim3D, 0, 0, 0, 2, ImageFormatR32ui}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_uint_3d, - StorageClassUniformConstant, state->storage_image_uint_3d_type}); - if (state->storage_image_uint_3d_variable != 0) { + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_3d, + StorageClassUniformConstant, state.storage_image_uint_3d_type}); + if (state.storage_image_uint_3d_variable != 0) { const auto count = - ConstantU32(state, DescriptorCount(*state, IR::DescriptorBindingKind::StorageUint3D)); - state->builder.AddType({OpTypeArray, state->storage_image_uint_3d_array_type, - state->storage_image_uint_3d_type, count}); - state->builder.AddType({OpTypePointer, state->ptr_uniform_storage_image_uint_3d_array, + ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::StorageUint3D)); + state.builder.AddType({OpTypeArray, state.storage_image_uint_3d_array_type, + state.storage_image_uint_3d_type, count}); + state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_3d_array, StorageClassUniformConstant, - state->storage_image_uint_3d_array_type}); - state->builder.AddType({OpVariable, state->ptr_uniform_storage_image_uint_3d_array, - state->storage_image_uint_3d_variable, + state.storage_image_uint_3d_array_type}); + state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_uint_3d_array, + state.storage_image_uint_3d_variable, StorageClassUniformConstant}); } - state->builder.AddType( - {OpTypePointer, state->ptr_image_uint, StorageClassImage, state->uint_type}); - state->builder.AddType({OpTypeFunction, state->func_type, state->void_type}); + state.builder.AddType( + {OpTypePointer, state.ptr_image_uint, StorageClassImage, state.uint_type}); + state.builder.AddType({OpTypeFunction, state.func_type, state.void_type}); } -void AllocateRegisterVariables(EmitterState* state) { - if (state->stage == ShaderType::Pixel && state->needs_pixel_valid_mask) { - state->pixel_valid_mask_variable = state->builder.AllocateId(); - state->builder.AddName(state->pixel_valid_mask_variable, "pixel_valid_mask_active"); +void AllocateRegisterVariables(EmitterState& state) { + if (state.stage == ShaderType::Pixel && state.needs_pixel_valid_mask) { + state.pixel_valid_mask_variable = state.builder.AllocateId(); + state.builder.AddName(state.pixel_valid_mask_variable, "pixel_valid_mask_active"); } - for (auto& binding: state->registers) { - binding.pointer_id = state->builder.AllocateId(); + for (auto& binding: state.registers) { + binding.pointer_id = state.builder.AllocateId(); const auto name = IR::RegisterToString(binding.reg); - state->builder.AddName(binding.pointer_id, name.c_str()); + state.builder.AddName(binding.pointer_id, name.c_str()); } } -void AllocateDescriptorVariables(EmitterState* state) { - if (DescriptorBinding(*state, IR::DescriptorBindingKind::Buffers) != nullptr) { - state->storage_buffer_variable = state->builder.AllocateId(); +void AllocateDescriptorVariables(EmitterState& state) { + if (DescriptorBinding(state, IR::DescriptorBindingKind::Buffers) != nullptr) { + state.storage_buffer_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::AddressMemory) != nullptr) { - state->address_memory_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::AddressMemory) != nullptr) { + state.address_memory_variable = state.builder.AllocateId(); } - if (state->program->bindings.push_constant_size != 0) { - state->push_constant_variable = state->builder.AllocateId(); + if (state.program.bindings.push_constant_size != 0) { + state.push_constant_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::UserData) != nullptr) { - state->vsharp_storage_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::UserData) != nullptr) { + state.vsharp_storage_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::FlattenedSrt) != nullptr) { - state->flattened_srt_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::FlattenedSrt) != nullptr) { + state.flattened_srt_variable = state.builder.AllocateId(); } - for (uint32_t i = 0; i < state->sampled_images.size(); i++) { + for (uint32_t i = 0; i < state.sampled_images.size(); i++) { const auto view = static_cast(i % 3u); - if (DescriptorBinding(*state, SampledBindingKind(i >= 3u, view)) != nullptr) { - state->sampled_images[i].variable = state->builder.AllocateId(); + if (DescriptorBinding(state, SampledBindingKind(i >= 3u, view)) != nullptr) { + state.sampled_images[i].variable = state.builder.AllocateId(); } } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::Storage2D) != nullptr) { - state->storage_image_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::Storage2D) != nullptr) { + state.storage_image_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::StorageUint2D) != nullptr) { - state->storage_image_uint_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::StorageUint2D) != nullptr) { + state.storage_image_uint_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::Storage2DArray) != nullptr) { - state->storage_image_2d_array_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::Storage2DArray) != nullptr) { + state.storage_image_2d_array_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::StorageUint2DArray) != nullptr) { - state->storage_image_uint_2d_array_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::StorageUint2DArray) != nullptr) { + state.storage_image_uint_2d_array_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::Storage3D) != nullptr) { - state->storage_image_3d_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::Storage3D) != nullptr) { + state.storage_image_3d_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::StorageUint3D) != nullptr) { - state->storage_image_uint_3d_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::StorageUint3D) != nullptr) { + state.storage_image_uint_3d_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::Samplers) != nullptr) { - state->sampler_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::Samplers) != nullptr) { + state.sampler_variable = state.builder.AllocateId(); } - if (DescriptorBinding(*state, IR::DescriptorBindingKind::Gds) != nullptr) { - state->gds_variable = state->builder.AllocateId(); + if (DescriptorBinding(state, IR::DescriptorBindingKind::Gds) != nullptr) { + state.gds_variable = state.builder.AllocateId(); } } diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterValues.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterValues.cpp index 44758a094..e06172ba8 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterValues.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterValues.cpp @@ -21,7 +21,7 @@ bool SdwaSelectorOffsetWidth(uint32_t sel, uint32_t& offset, uint32_t& width) { return false; } -uint32_t EmitSdwaExtractU32(EmitterState* state, const IR::Operand& operand, uint32_t value) { +uint32_t EmitSdwaExtractU32(EmitterState& state, const IR::Operand& operand, uint32_t value) { if (operand.sdwa_sel == 6u && !operand.sdwa_sext) { return value; } @@ -33,117 +33,117 @@ uint32_t EmitSdwaExtractU32(EmitterState* state, const IR::Operand& operand, uin } if (operand.sdwa_sext) { - const auto signed_value = state->builder.AllocateId(); - const auto extracted = state->builder.AllocateId(); - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->int_type, signed_value, value}); - state->builder.AddFunction({OpBitFieldSExtract, state->int_type, extracted, signed_value, + const auto signed_value = state.builder.AllocateId(); + const auto extracted = state.builder.AllocateId(); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.int_type, signed_value, value}); + state.builder.AddFunction({OpBitFieldSExtract, state.int_type, extracted, signed_value, ConstantU32(state, offset), ConstantU32(state, width)}); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, extracted}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, extracted}); return bits; } - const auto extracted = state->builder.AllocateId(); - state->builder.AddFunction({OpBitFieldUExtract, state->uint_type, extracted, value, + const auto extracted = state.builder.AllocateId(); + state.builder.AddFunction({OpBitFieldUExtract, state.uint_type, extracted, value, ConstantU32(state, offset), ConstantU32(state, width)}); return extracted; } -uint32_t EmitTrueBool(EmitterState* state) { - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, ret, ConstantU32(state, 1), ConstantU32(state, 0)}); +uint32_t EmitTrueBool(EmitterState& state) { + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, ret, ConstantU32(state, 1), ConstantU32(state, 0)}); return ret; } -DppTargetLane EmitDppQuadPermTargetLane(EmitterState* state, uint32_t subid, uint32_t control) { - const auto quad_base = state->builder.AllocateId(); - const auto lane = state->builder.AllocateId(); - const auto shift = state->builder.AllocateId(); - const auto selected0 = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); - const auto target = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, quad_base, subid, ConstantU32(state, 0xfffffffcu)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, subid, ConstantU32(state, 3)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, shift, lane, ConstantU32(state, 1)}); - state->builder.AddFunction( - {OpShiftRightLogical, state->uint_type, selected0, ConstantU32(state, control), shift}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, selected, selected0, ConstantU32(state, 3)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, target, quad_base, selected}); +DppTargetLane EmitDppQuadPermTargetLane(EmitterState& state, uint32_t subid, uint32_t control) { + const auto quad_base = state.builder.AllocateId(); + const auto lane = state.builder.AllocateId(); + const auto shift = state.builder.AllocateId(); + const auto selected0 = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); + const auto target = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, quad_base, subid, ConstantU32(state, 0xfffffffcu)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 3)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, shift, lane, ConstantU32(state, 1)}); + state.builder.AddFunction( + {OpShiftRightLogical, state.uint_type, selected0, ConstantU32(state, control), shift}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, selected, selected0, ConstantU32(state, 3)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, quad_base, selected}); return {target, EmitTrueBool(state)}; } -DppTargetLane EmitDppRowShiftTargetLane(EmitterState* state, uint32_t subid, uint32_t amount, +DppTargetLane EmitDppRowShiftTargetLane(EmitterState& state, uint32_t subid, uint32_t amount, bool left) { - const auto row = state->builder.AllocateId(); - const auto lane = state->builder.AllocateId(); - const auto lane_shifted = state->builder.AllocateId(); - const auto target = state->builder.AllocateId(); - const auto valid = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, row, subid, ConstantU32(state, 0xfffffff0u)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, subid, ConstantU32(state, 15)}); + const auto row = state.builder.AllocateId(); + const auto lane = state.builder.AllocateId(); + const auto lane_shifted = state.builder.AllocateId(); + const auto target = state.builder.AllocateId(); + const auto valid = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, row, subid, ConstantU32(state, 0xfffffff0u)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)}); if (left) { - state->builder.AddFunction( - {OpIAdd, state->uint_type, lane_shifted, lane, ConstantU32(state, amount)}); - state->builder.AddFunction( - {OpULessThan, state->bool_type, valid, lane, ConstantU32(state, 16u - amount)}); + state.builder.AddFunction( + {OpIAdd, state.uint_type, lane_shifted, lane, ConstantU32(state, amount)}); + state.builder.AddFunction( + {OpULessThan, state.bool_type, valid, lane, ConstantU32(state, 16u - amount)}); } else { - state->builder.AddFunction( - {OpISub, state->uint_type, lane_shifted, lane, ConstantU32(state, amount)}); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, valid, lane, ConstantU32(state, amount)}); + state.builder.AddFunction( + {OpISub, state.uint_type, lane_shifted, lane, ConstantU32(state, amount)}); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, valid, lane, ConstantU32(state, amount)}); } - state->builder.AddFunction({OpBitwiseOr, state->uint_type, target, row, lane_shifted}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, row, lane_shifted}); return {target, valid}; } -DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState* state, uint32_t subid, +DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState& state, uint32_t subid, uint32_t amount) { - const auto row = state->builder.AllocateId(); - const auto lane = state->builder.AllocateId(); - const auto in_high = state->builder.AllocateId(); - const auto minus = state->builder.AllocateId(); - const auto plus = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); - const auto target = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, row, subid, ConstantU32(state, 0xfffffff0u)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, subid, ConstantU32(state, 15)}); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, in_high, lane, ConstantU32(state, amount)}); - state->builder.AddFunction({OpISub, state->uint_type, minus, lane, ConstantU32(state, amount)}); - state->builder.AddFunction( - {OpIAdd, state->uint_type, plus, lane, ConstantU32(state, 16u - amount)}); - state->builder.AddFunction({OpSelect, state->uint_type, selected, in_high, minus, plus}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, target, row, selected}); + const auto row = state.builder.AllocateId(); + const auto lane = state.builder.AllocateId(); + const auto in_high = state.builder.AllocateId(); + const auto minus = state.builder.AllocateId(); + const auto plus = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); + const auto target = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, row, subid, ConstantU32(state, 0xfffffff0u)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 15)}); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, in_high, lane, ConstantU32(state, amount)}); + state.builder.AddFunction({OpISub, state.uint_type, minus, lane, ConstantU32(state, amount)}); + state.builder.AddFunction( + {OpIAdd, state.uint_type, plus, lane, ConstantU32(state, 16u - amount)}); + state.builder.AddFunction({OpSelect, state.uint_type, selected, in_high, minus, plus}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, row, selected}); return {target, EmitTrueBool(state)}; } -DppTargetLane EmitDppMirrorTargetLane(EmitterState* state, uint32_t subid, bool half_row) { +DppTargetLane EmitDppMirrorTargetLane(EmitterState& state, uint32_t subid, bool half_row) { const auto base_mask = half_row ? 0xfffffff8u : 0xfffffff0u; const auto lane_mask = half_row ? 7u : 15u; - const auto base = state->builder.AllocateId(); - const auto lane = state->builder.AllocateId(); - const auto mirrored = state->builder.AllocateId(); - const auto target = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, base, subid, ConstantU32(state, base_mask)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, subid, ConstantU32(state, lane_mask)}); - state->builder.AddFunction( - {OpISub, state->uint_type, mirrored, ConstantU32(state, lane_mask), lane}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, target, base, mirrored}); + const auto base = state.builder.AllocateId(); + const auto lane = state.builder.AllocateId(); + const auto mirrored = state.builder.AllocateId(); + const auto target = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, base, subid, ConstantU32(state, base_mask)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, lane_mask)}); + state.builder.AddFunction( + {OpISub, state.uint_type, mirrored, ConstantU32(state, lane_mask), lane}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, target, base, mirrored}); return {target, EmitTrueBool(state)}; } -DppTargetLane EmitDppTargetLane(EmitterState* state, uint32_t control) { +DppTargetLane EmitDppTargetLane(EmitterState& state, uint32_t control) { const auto subid = EmitSubgroupLocalInvocationId(state); if (control <= 0xffu) { return EmitDppQuadPermTargetLane(state, subid, control); @@ -166,42 +166,42 @@ DppTargetLane EmitDppTargetLane(EmitterState* state, uint32_t control) { return {subid, EmitTrueBool(state)}; } -uint32_t EmitDppValueU32(EmitterState* state, const IR::Operand& operand, uint32_t value) { +uint32_t EmitDppValueU32(EmitterState& state, const IR::Operand& operand, uint32_t value) { if (!operand.dpp) { return value; } const auto target = EmitDppTargetLane(state, operand.dpp_ctrl); - const auto shuffled = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformShuffle, state->uint_type, shuffled, + const auto shuffled = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformShuffle, state.uint_type, shuffled, ConstantU32(state, ScopeSubgroup), value, target.lane}); if (operand.dpp_fetch_inactive) { return shuffled; } const auto source_active = EmitLaneIndexActiveBool(state, target.lane); - const auto can_fetch = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpLogicalAnd, state->bool_type, can_fetch, target.valid, source_active}); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, can_fetch, shuffled, ConstantU32(state, 0)}); + const auto can_fetch = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpLogicalAnd, state.bool_type, can_fetch, target.valid, source_active}); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, can_fetch, shuffled, ConstantU32(state, 0)}); return ret; } -uint32_t EmitValueLoad(EmitterState* state, const IR::Operand& operand) { +uint32_t EmitValueLoad(EmitterState& state, const IR::Operand& operand) { uint32_t value = 0; switch (operand.kind) { case IR::OperandKind::ImmediateU32: case IR::OperandKind::PcRelativeU32: value = ConstantU32(state, operand.imm); break; case IR::OperandKind::Register: { - const auto pointer = PointerForRegister(*state, operand.reg); + const auto pointer = PointerForRegister(state, operand.reg); if (pointer == 0) { value = ConstantU32(state, 0); break; } - value = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + value = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); break; } case IR::OperandKind::Null: value = ConstantU32(state, 0); break; @@ -211,160 +211,160 @@ uint32_t EmitValueLoad(EmitterState* state, const IR::Operand& operand) { return EmitSdwaExtractU32(state, operand, value); } -uint32_t EmitRegisterLoad(EmitterState* state, IR::Register reg) { - if (IsInactiveWave32ExecHigh(*state, reg)) { +uint32_t EmitRegisterLoad(EmitterState& state, IR::Register reg) { + if (IsInactiveWave32ExecHigh(state, reg)) { return ConstantU32(state, 0); } - const auto pointer = PointerForRegister(*state, reg); + const auto pointer = PointerForRegister(state, reg); if (pointer == 0) { return ConstantU32(state, 0); } - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); return value; } -uint32_t WaveMaskHighLoad(EmitterState* state, IR::RegisterFile file) { - if (state->wave_size == 32u && IsMaskRegisterFile(file)) { +uint32_t WaveMaskHighLoad(EmitterState& state, IR::RegisterFile file) { + if (state.wave_size == 32u && IsMaskRegisterFile(file)) { return ConstantU32(state, 0); } return EmitRegisterLoad(state, {file, 1}); } -uint32_t EmitLaneMaskPartU32(EmitterState* state, uint32_t part) { +uint32_t EmitLaneMaskPartU32(EmitterState& state, uint32_t part) { const auto subid = EmitSubgroupLocalInvocationId(state); - const auto lane = state->builder.AllocateId(); - const auto bit = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, subid, ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, bit, ConstantU32(state, 1), lane}); + const auto lane = state.builder.AllocateId(); + const auto bit = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), lane}); if (part == 0) { - const auto in_low = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpULessThan, state->bool_type, in_low, subid, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, in_low, bit, ConstantU32(state, 0)}); + const auto in_low = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpULessThan, state.bool_type, in_low, subid, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, in_low, bit, ConstantU32(state, 0)}); return ret; } - if (state->wave_size == 32u) { + if (state.wave_size == 32u) { return ConstantU32(state, 0); } - const auto in_high = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, in_high, subid, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, in_high, bit, ConstantU32(state, 0)}); + const auto in_high = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, in_high, subid, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, in_high, bit, ConstantU32(state, 0)}); return ret; } -uint32_t EmitThreadMaskBelowPartU32(EmitterState* state, uint32_t part) { +uint32_t EmitThreadMaskBelowPartU32(EmitterState& state, uint32_t part) { const auto subid = EmitSubgroupLocalInvocationId(state); - const auto lane = state->builder.AllocateId(); - const auto bit = state->builder.AllocateId(); - const auto below = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane, subid, ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, bit, ConstantU32(state, 1), lane}); - state->builder.AddFunction({OpISub, state->uint_type, below, bit, ConstantU32(state, 1)}); + const auto lane = state.builder.AllocateId(); + const auto bit = state.builder.AllocateId(); + const auto below = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane, subid, ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), lane}); + state.builder.AddFunction({OpISub, state.uint_type, below, bit, ConstantU32(state, 1)}); if (part == 0) { - const auto in_high = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, in_high, subid, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, in_high, ConstantU32(state, 0xffffffffu), below}); + const auto in_high = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, in_high, subid, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, in_high, ConstantU32(state, 0xffffffffu), below}); return ret; } - if (state->wave_size == 32u) { + if (state.wave_size == 32u) { return ConstantU32(state, 0); } - const auto in_high = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, in_high, subid, ConstantU32(state, 32)}); - state->builder.AddFunction( - {OpSelect, state->uint_type, ret, in_high, below, ConstantU32(state, 0)}); + const auto in_high = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, in_high, subid, ConstantU32(state, 32)}); + state.builder.AddFunction( + {OpSelect, state.uint_type, ret, in_high, below, ConstantU32(state, 0)}); return ret; } -uint32_t EmitMaskActiveBool(EmitterState* state, IR::RegisterFile file) { +uint32_t EmitMaskActiveBool(EmitterState& state, IR::RegisterFile file) { const auto low = EmitRegisterLoad(state, {file, 0}); - const auto condition = state->builder.AllocateId(); - if (state->per_invocation_masks) { - const auto combined = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseOr, state->uint_type, combined, low, WaveMaskHighLoad(state, file)}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, condition, combined, ConstantU32(state, 0)}); + const auto condition = state.builder.AllocateId(); + if (state.per_invocation_masks) { + const auto combined = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseOr, state.uint_type, combined, low, WaveMaskHighLoad(state, file)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, condition, combined, ConstantU32(state, 0)}); return condition; } - if (state->exact_subgroup_operations) { + if (state.exact_subgroup_operations) { const auto high = WaveMaskHighLoad(state, file); - const auto low_hit = state->builder.AllocateId(); - const auto high_hit = state->builder.AllocateId(); - const auto active = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, low_hit, low, EmitLaneMaskPartU32(state, 0)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, high_hit, high, EmitLaneMaskPartU32(state, 1)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, active, low_hit, high_hit}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, condition, active, ConstantU32(state, 0)}); + const auto low_hit = state.builder.AllocateId(); + const auto high_hit = state.builder.AllocateId(); + const auto active = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, low_hit, low, EmitLaneMaskPartU32(state, 0)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, high_hit, high, EmitLaneMaskPartU32(state, 1)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, active, low_hit, high_hit}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, condition, active, ConstantU32(state, 0)}); return condition; } - state->builder.AddFunction( - {OpINotEqual, state->bool_type, condition, low, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, condition, low, ConstantU32(state, 0)}); return condition; } -uint32_t EmitMaskZeroBool(EmitterState* state, IR::RegisterFile file, bool zero) { +uint32_t EmitMaskZeroBool(EmitterState& state, IR::RegisterFile file, bool zero) { const auto active = EmitMaskActiveBool(state, file); if (!zero) { return active; } - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalNot, state->bool_type, cond, active}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalNot, state.bool_type, cond, active}); return cond; } -uint32_t EmitMaskSummaryZeroBool(EmitterState* state, IR::RegisterFile file, bool zero) { - if (state->per_invocation_masks) { +uint32_t EmitMaskSummaryZeroBool(EmitterState& state, IR::RegisterFile file, bool zero) { + if (state.per_invocation_masks) { return EmitMaskZeroBool(state, file, zero); } - if (state->exact_subgroup_operations) { + if (state.exact_subgroup_operations) { const auto low = EmitRegisterLoad(state, {file, 0}); const auto high = WaveMaskHighLoad(state, file); - const auto combined = state->builder.AllocateId(); - const auto active = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, combined, low, high}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, active, combined, ConstantU32(state, 0)}); + const auto combined = state.builder.AllocateId(); + const auto active = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, combined, low, high}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, active, combined, ConstantU32(state, 0)}); if (!zero) { return active; } - const auto inactive = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalNot, state->bool_type, inactive, active}); + const auto inactive = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalNot, state.bool_type, inactive, active}); return inactive; } const auto active = EmitMaskActiveBool(state, file); if (!zero) { return active; } - const auto inactive = state->builder.AllocateId(); - state->builder.AddFunction({OpLogicalNot, state->bool_type, inactive, active}); + const auto inactive = state.builder.AllocateId(); + state.builder.AddFunction({OpLogicalNot, state.bool_type, inactive, active}); return inactive; } -uint32_t EmitExecActiveBool(EmitterState* state) { +uint32_t EmitExecActiveBool(EmitterState& state) { return EmitMaskZeroBool(state, IR::RegisterFile::Exec, false); } -uint32_t EmitConditionBool(EmitterState* state, const IR::Operand& operand) { +uint32_t EmitConditionBool(EmitterState& state, const IR::Operand& operand) { if (operand.kind == IR::OperandKind::Register) { if (operand.reg.file == IR::RegisterFile::Exec || operand.reg.file == IR::RegisterFile::Vcc) { @@ -372,19 +372,19 @@ uint32_t EmitConditionBool(EmitterState* state, const IR::Operand& operand) { } } const auto cond_value = EmitValueLoad(state, operand); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, cond, cond_value, ConstantU32(state, 0)}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, cond, cond_value, ConstantU32(state, 0)}); return cond; } -uint32_t EmitSubgroupLocalInvocationId(EmitterState* state) { - if (state->subgroup_local_invocation_id_variable == 0) { +uint32_t EmitSubgroupLocalInvocationId(EmitterState& state) { + if (state.subgroup_local_invocation_id_variable == 0) { return ConstantU32(state, 0); } - const auto value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpLoad, state->uint_type, value, state->subgroup_local_invocation_id_variable}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpLoad, state.uint_type, value, state.subgroup_local_invocation_id_variable}); return value; } @@ -415,30 +415,30 @@ const InputBinding* InputBindingForParameter(const EmitterState& state, uint32_t return nullptr; } -uint32_t EmitInputComponentU32(EmitterState* state, IR::StageInputKind kind, uint32_t component) { - const auto variable = InputVariableForKind(*state, kind); +uint32_t EmitInputComponentU32(EmitterState& state, IR::StageInputKind kind, uint32_t component) { + const auto variable = InputVariableForKind(state, kind); if (variable == 0) { return ConstantU32(state, 0); } - const auto pointer = state->builder.AllocateId(); - const auto value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpAccessChain, state->ptr_input_uint, pointer, variable, ConstantU32(state, component)}); - state->builder.AddFunction({OpLoad, state->uint_type, value, pointer}); + const auto pointer = state.builder.AllocateId(); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpAccessChain, state.ptr_input_uint, pointer, variable, ConstantU32(state, component)}); + state.builder.AddFunction({OpLoad, state.uint_type, value, pointer}); return value; } -uint32_t EmitLocalInvocationIndex(EmitterState* state) { - const auto variable = InputVariableForKind(*state, IR::StageInputKind::LocalInvocationIndex); +uint32_t EmitLocalInvocationIndex(EmitterState& state) { + const auto variable = InputVariableForKind(state, IR::StageInputKind::LocalInvocationIndex); if (variable == 0) { return ConstantU32(state, 0); } - const auto value = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->uint_type, value, variable}); + const auto value = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.uint_type, value, variable}); return value; } -uint32_t VertexInputDefaultComponentU32(EmitterState* state, VertexInputScalarKind kind, +uint32_t VertexInputDefaultComponentU32(EmitterState& state, VertexInputScalarKind kind, uint32_t component) { if ((component & 3u) != 3u) { return ConstantU32(state, 0); @@ -446,105 +446,105 @@ uint32_t VertexInputDefaultComponentU32(EmitterState* state, VertexInputScalarKi return ConstantU32(state, kind == VertexInputScalarKind::Float ? 0x3f800000u : 1u); } -uint32_t EmitVertexParameterComponentU32(EmitterState* state, const InputBinding& input, +uint32_t EmitVertexParameterComponentU32(EmitterState& state, const InputBinding& input, uint32_t component) { - const auto count = VertexParameterComponentCount(*state, input); - const auto kind = VertexParameterScalarKind(*state, input.location); + const auto count = VertexParameterComponentCount(state, input); + const auto kind = VertexParameterScalarKind(state, input.location); if (component >= count) { return VertexInputDefaultComponentU32(state, kind, component); } - const auto scalar_type = VertexParameterScalarType(*state, kind); - uint32_t raw = state->builder.AllocateId(); + const auto scalar_type = VertexParameterScalarType(state, kind); + uint32_t raw = state.builder.AllocateId(); if (count == 1u) { - state->builder.AddFunction({OpLoad, scalar_type, raw, input.variable_id}); + state.builder.AddFunction({OpLoad, scalar_type, raw, input.variable_id}); } else { - const auto pointer_type = VertexParameterScalarPointerType(*state, kind); - const auto pointer = state->builder.AllocateId(); - state->builder.AddFunction({OpAccessChain, pointer_type, pointer, input.variable_id, + const auto pointer_type = VertexParameterScalarPointerType(state, kind); + const auto pointer = state.builder.AllocateId(); + state.builder.AddFunction({OpAccessChain, pointer_type, pointer, input.variable_id, ConstantU32(state, component)}); - state->builder.AddFunction({OpLoad, scalar_type, raw, pointer}); + state.builder.AddFunction({OpLoad, scalar_type, raw, pointer}); } if (kind == VertexInputScalarKind::Uint) { return raw; } - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, raw}); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, raw}); return bits; } -void EmitLoadInputF32(EmitterState* state, const IR::Instruction& inst) { - const auto* input = InputBindingForParameter(*state, inst.input_info.attr); +void EmitLoadInputF32(EmitterState& state, const IR::Instruction& inst) { + const auto* input = InputBindingForParameter(state, inst.input_info.attr); if (input == nullptr || input->variable_id == 0) { EmitStoreU32(state, inst.dst, ConstantU32(state, 0)); return; } - if (state->stage == ShaderType::Vertex) { + if (state.stage == ShaderType::Vertex) { EmitStoreU32(state, inst.dst, EmitVertexParameterComponentU32(state, *input, inst.input_info.chan & 3u)); return; } - const auto input_value = state->builder.AllocateId(); - const auto component = state->builder.AllocateId(); - const auto bits = state->builder.AllocateId(); - state->builder.AddFunction({OpLoad, state->vec4_float_type, input_value, input->variable_id}); - state->builder.AddFunction( - {OpCompositeExtract, state->float_type, component, input_value, inst.input_info.chan & 3u}); - state->builder.AddFunction({OpBitcast, state->uint_type, bits, component}); + const auto input_value = state.builder.AllocateId(); + const auto component = state.builder.AllocateId(); + const auto bits = state.builder.AllocateId(); + state.builder.AddFunction({OpLoad, state.vec4_float_type, input_value, input->variable_id}); + state.builder.AddFunction( + {OpCompositeExtract, state.float_type, component, input_value, inst.input_info.chan & 3u}); + state.builder.AddFunction({OpBitcast, state.uint_type, bits, component}); EmitStoreU32(state, inst.dst, bits); } -uint32_t EmitSccBool(EmitterState* state, bool non_zero) { +uint32_t EmitSccBool(EmitterState& state, bool non_zero) { const auto value = EmitRegisterLoad(state, SccRegister()); - const auto cond = state->builder.AllocateId(); - state->builder.AddFunction( - {non_zero ? OpINotEqual : OpIEqual, state->bool_type, cond, value, ConstantU32(state, 0)}); + const auto cond = state.builder.AllocateId(); + state.builder.AddFunction( + {non_zero ? OpINotEqual : OpIEqual, state.bool_type, cond, value, ConstantU32(state, 0)}); return cond; } -uint32_t EmitFloatLoad(EmitterState* state, const IR::Operand& operand) { +uint32_t EmitFloatLoad(EmitterState& state, const IR::Operand& operand) { const auto uint_value = EmitValueLoad(state, operand); - auto float_value = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->float_type, float_value, uint_value}); + auto float_value = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.float_type, float_value, uint_value}); if (operand.absolute) { - const auto abs_value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, abs_value, state->glsl_std450, GlslFAbs, float_value}); + const auto abs_value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, abs_value, state.glsl_std450, GlslFAbs, float_value}); float_value = abs_value; } if (operand.negate) { - const auto neg_value = state->builder.AllocateId(); - state->builder.AddFunction({OpFNegate, state->float_type, neg_value, float_value}); + const auto neg_value = state.builder.AllocateId(); + state.builder.AddFunction({OpFNegate, state.float_type, neg_value, float_value}); float_value = neg_value; } return float_value; } -uint32_t ApplyResultModifiersF32(EmitterState* state, uint32_t value, const IR::Operand& dst) { +uint32_t ApplyResultModifiersF32(EmitterState& state, uint32_t value, const IR::Operand& dst) { uint32_t result = value; if (dst.omod != 0) { const uint32_t bits = dst.omod == 1u ? 0x40000000u : dst.omod == 2u ? 0x40800000u : 0x3f000000u; - const auto scaled = state->builder.AllocateId(); - state->builder.AddFunction( - {OpFMul, state->float_type, scaled, result, ConstantF32(state, bits)}); + const auto scaled = state.builder.AllocateId(); + state.builder.AddFunction( + {OpFMul, state.float_type, scaled, result, ConstantF32(state, bits)}); result = scaled; } if (!dst.clamp) { return result; } - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpExtInst, state->float_type, ret, state->glsl_std450, GlslFClamp, + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpExtInst, state.float_type, ret, state.glsl_std450, GlslFClamp, result, ConstantF32(state, 0), ConstantF32(state, 0x3f800000u)}); return ret; } -uint32_t EmitMixF32Load(EmitterState* state, const IR::Operand& operand) { +uint32_t EmitMixF32Load(EmitterState& state, const IR::Operand& operand) { auto value_operand = operand; value_operand.negate_hi = false; @@ -562,21 +562,21 @@ uint32_t EmitMixF32Load(EmitterState* state, const IR::Operand& operand) { raw.dpp_bound_ctrl = false; const auto bits = EmitValueLoad(state, raw); - const auto unpacked = state->builder.AllocateId(); - auto f32 = state->builder.AllocateId(); - state->builder.AddFunction({OpExtInst, state->vec2_float_type, unpacked, state->glsl_std450, + const auto unpacked = state.builder.AllocateId(); + auto f32 = state.builder.AllocateId(); + state.builder.AddFunction({OpExtInst, state.vec2_float_type, unpacked, state.glsl_std450, GlslUnpackHalf2x16, bits}); - state->builder.AddFunction( - {OpCompositeExtract, state->float_type, f32, unpacked, operand.op_sel ? 1u : 0u}); + state.builder.AddFunction( + {OpCompositeExtract, state.float_type, f32, unpacked, operand.op_sel ? 1u : 0u}); if (operand.absolute) { - const auto abs_value = state->builder.AllocateId(); - state->builder.AddFunction( - {OpExtInst, state->float_type, abs_value, state->glsl_std450, GlslFAbs, f32}); + const auto abs_value = state.builder.AllocateId(); + state.builder.AddFunction( + {OpExtInst, state.float_type, abs_value, state.glsl_std450, GlslFAbs, f32}); f32 = abs_value; } if (value_operand.negate) { - const auto neg_value = state->builder.AllocateId(); - state->builder.AddFunction({OpFNegate, state->float_type, neg_value, f32}); + const auto neg_value = state.builder.AllocateId(); + state.builder.AddFunction({OpFNegate, state.float_type, neg_value, f32}); f32 = neg_value; } return f32; @@ -611,10 +611,10 @@ IR::Operand OffsetRegisterOperand(const IR::Operand& operand, uint32_t offset) { return ret; } -uint32_t EmitLaneMaskOperandActiveBool(EmitterState* state, const IR::Operand& operand) { +uint32_t EmitLaneMaskOperandActiveBool(EmitterState& state, const IR::Operand& operand) { const auto low = EmitValueLoad(state, operand); - const auto active = state->builder.AllocateId(); - if (state->per_invocation_masks || state->exact_subgroup_operations) { + const auto active = state.builder.AllocateId(); + if (state.per_invocation_masks || state.exact_subgroup_operations) { uint32_t high = ConstantU32(state, 0); if (operand.kind == IR::OperandKind::Register && (operand.reg.file == IR::RegisterFile::Scalar || @@ -624,102 +624,102 @@ uint32_t EmitLaneMaskOperandActiveBool(EmitterState* state, const IR::Operand& o ? WaveMaskHighLoad(state, operand.reg.file) : EmitValueLoad(state, OffsetRegisterOperand(operand, 1)); } - if (state->per_invocation_masks) { - const auto combined = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, combined, low, high}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, active, combined, ConstantU32(state, 0)}); + if (state.per_invocation_masks) { + const auto combined = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, combined, low, high}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, active, combined, ConstantU32(state, 0)}); return active; } - const auto low_hit = state->builder.AllocateId(); - const auto high_hit = state->builder.AllocateId(); - const auto hit = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, low_hit, low, EmitLaneMaskPartU32(state, 0)}); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, high_hit, high, EmitLaneMaskPartU32(state, 1)}); - state->builder.AddFunction({OpBitwiseOr, state->uint_type, hit, low_hit, high_hit}); - state->builder.AddFunction( - {OpINotEqual, state->bool_type, active, hit, ConstantU32(state, 0)}); + const auto low_hit = state.builder.AllocateId(); + const auto high_hit = state.builder.AllocateId(); + const auto hit = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, low_hit, low, EmitLaneMaskPartU32(state, 0)}); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, high_hit, high, EmitLaneMaskPartU32(state, 1)}); + state.builder.AddFunction({OpBitwiseOr, state.uint_type, hit, low_hit, high_hit}); + state.builder.AddFunction( + {OpINotEqual, state.bool_type, active, hit, ConstantU32(state, 0)}); return active; } - state->builder.AddFunction({OpINotEqual, state->bool_type, active, low, ConstantU32(state, 0)}); + state.builder.AddFunction({OpINotEqual, state.bool_type, active, low, ConstantU32(state, 0)}); return active; } -uint32_t EmitLaneIndexActiveBool(EmitterState* state, uint32_t lane) { - if (state->per_invocation_masks) { - const auto ballot = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformBallot, state->vec4_uint_type, ballot, +uint32_t EmitLaneIndexActiveBool(EmitterState& state, uint32_t lane) { + if (state.per_invocation_masks) { + const auto ballot = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, ballot, ConstantU32(state, ScopeSubgroup), EmitExecActiveBool(state)}); return EmitBallotLaneActiveBool(state, ballot, lane); } - const auto lane_low = state->builder.AllocateId(); - const auto bit = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane_low, lane, ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, bit, ConstantU32(state, 1), lane_low}); + const auto lane_low = state.builder.AllocateId(); + const auto bit = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane_low, lane, ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), lane_low}); uint32_t mask = EmitRegisterLoad(state, {IR::RegisterFile::Exec, 0}); - if (state->wave_size == 64u) { + if (state.wave_size == 64u) { const auto high = EmitRegisterLoad(state, {IR::RegisterFile::Exec, 1}); - const auto in_high = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, in_high, lane, ConstantU32(state, 32)}); - state->builder.AddFunction({OpSelect, state->uint_type, selected, in_high, high, mask}); + const auto in_high = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, in_high, lane, ConstantU32(state, 32)}); + state.builder.AddFunction({OpSelect, state.uint_type, selected, in_high, high, mask}); mask = selected; } - const auto hit = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, hit, mask, bit}); - state->builder.AddFunction({OpINotEqual, state->bool_type, ret, hit, ConstantU32(state, 0)}); + const auto hit = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, hit, mask, bit}); + state.builder.AddFunction({OpINotEqual, state.bool_type, ret, hit, ConstantU32(state, 0)}); return ret; } -uint32_t EmitSubgroupLaneActiveBool(EmitterState* state, uint32_t lane) { - const auto active_ballot = state->builder.AllocateId(); - state->builder.AddFunction({OpGroupNonUniformBallot, state->vec4_uint_type, active_ballot, +uint32_t EmitSubgroupLaneActiveBool(EmitterState& state, uint32_t lane) { + const auto active_ballot = state.builder.AllocateId(); + state.builder.AddFunction({OpGroupNonUniformBallot, state.vec4_uint_type, active_ballot, ConstantU32(state, ScopeSubgroup), EmitTrueBool(state)}); return EmitBallotLaneActiveBool(state, active_ballot, lane); } -uint32_t EmitBallotLaneActiveBool(EmitterState* state, uint32_t active_ballot, uint32_t lane) { - const auto low = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, low, active_ballot, 0}); +uint32_t EmitBallotLaneActiveBool(EmitterState& state, uint32_t active_ballot, uint32_t lane) { + const auto low = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, low, active_ballot, 0}); uint32_t mask = low; - if (state->wave_size == 64u) { - const auto high = state->builder.AllocateId(); - const auto in_high = state->builder.AllocateId(); - const auto selected = state->builder.AllocateId(); - state->builder.AddFunction({OpCompositeExtract, state->uint_type, high, active_ballot, 1}); - state->builder.AddFunction( - {OpUGreaterThanEqual, state->bool_type, in_high, lane, ConstantU32(state, 32)}); - state->builder.AddFunction({OpSelect, state->uint_type, selected, in_high, high, low}); + if (state.wave_size == 64u) { + const auto high = state.builder.AllocateId(); + const auto in_high = state.builder.AllocateId(); + const auto selected = state.builder.AllocateId(); + state.builder.AddFunction({OpCompositeExtract, state.uint_type, high, active_ballot, 1}); + state.builder.AddFunction( + {OpUGreaterThanEqual, state.bool_type, in_high, lane, ConstantU32(state, 32)}); + state.builder.AddFunction({OpSelect, state.uint_type, selected, in_high, high, low}); mask = selected; } - const auto lane_low = state->builder.AllocateId(); - const auto bit = state->builder.AllocateId(); - state->builder.AddFunction( - {OpBitwiseAnd, state->uint_type, lane_low, lane, ConstantU32(state, 31)}); - state->builder.AddFunction( - {OpShiftLeftLogical, state->uint_type, bit, ConstantU32(state, 1), lane_low}); + const auto lane_low = state.builder.AllocateId(); + const auto bit = state.builder.AllocateId(); + state.builder.AddFunction( + {OpBitwiseAnd, state.uint_type, lane_low, lane, ConstantU32(state, 31)}); + state.builder.AddFunction( + {OpShiftLeftLogical, state.uint_type, bit, ConstantU32(state, 1), lane_low}); - const auto hit = state->builder.AllocateId(); - const auto active = state->builder.AllocateId(); - const auto in_range = state->builder.AllocateId(); - const auto ret = state->builder.AllocateId(); - state->builder.AddFunction({OpBitwiseAnd, state->uint_type, hit, mask, bit}); - state->builder.AddFunction({OpINotEqual, state->bool_type, active, hit, ConstantU32(state, 0)}); - state->builder.AddFunction( - {OpULessThan, state->bool_type, in_range, lane, ConstantU32(state, state->wave_size)}); - state->builder.AddFunction({OpLogicalAnd, state->bool_type, ret, active, in_range}); + const auto hit = state.builder.AllocateId(); + const auto active = state.builder.AllocateId(); + const auto in_range = state.builder.AllocateId(); + const auto ret = state.builder.AllocateId(); + state.builder.AddFunction({OpBitwiseAnd, state.uint_type, hit, mask, bit}); + state.builder.AddFunction({OpINotEqual, state.bool_type, active, hit, ConstantU32(state, 0)}); + state.builder.AddFunction( + {OpULessThan, state.bool_type, in_range, lane, ConstantU32(state, state.wave_size)}); + state.builder.AddFunction({OpLogicalAnd, state.bool_type, ret, active, in_range}); return ret; } -uint32_t EmitSequentialValueLoad(EmitterState* state, const IR::Operand& operand, uint32_t offset) { +uint32_t EmitSequentialValueLoad(EmitterState& state, const IR::Operand& operand, uint32_t offset) { if (offset == 0 || operand.kind == IR::OperandKind::Register) { return EmitValueLoad(state, OffsetRegisterOperand(operand, offset)); } @@ -729,10 +729,10 @@ uint32_t EmitSequentialValueLoad(EmitterState* state, const IR::Operand& operand return ConstantU32(state, 0); } -uint32_t EmitSequentialFloatLoad(EmitterState* state, const IR::Operand& operand, uint32_t offset) { +uint32_t EmitSequentialFloatLoad(EmitterState& state, const IR::Operand& operand, uint32_t offset) { const auto value = EmitSequentialValueLoad(state, operand, offset); - const auto f32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->float_type, f32, value}); + const auto f32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.float_type, f32, value}); return f32; } @@ -803,7 +803,7 @@ IR::Operand ImageAddressOperand(const IR::Instruction& inst, const IR::Operand& return OffsetRegisterOperand(base, packed_component); } -uint32_t EmitImageAddressValueLoad(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageAddressValueLoad(EmitterState& state, const IR::Instruction& inst, const IR::Operand& base, uint32_t component) { const auto operand = ImageAddressOperand(inst, base, component); const auto packed_component = ImageAddressPackedComponent(inst, component); @@ -820,20 +820,20 @@ uint32_t EmitImageAddressValueLoad(EmitterState* state, const IR::Instruction& i return ConstantU32(state, 0); } -uint32_t EmitImageAddressFloatLoad(EmitterState* state, const IR::Instruction& inst, +uint32_t EmitImageAddressFloatLoad(EmitterState& state, const IR::Instruction& inst, const IR::Operand& base, uint32_t component) { const auto value = EmitImageAddressValueLoad(state, inst, base, component); if (ImageAddressComponentUsesA16(inst, component)) { return EmitF16BitsToF32(state, value); } - const auto f32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->float_type, f32, value}); + const auto f32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.float_type, f32, value}); return f32; } -uint32_t EmitZeroF32(EmitterState* state) { - const auto f32 = state->builder.AllocateId(); - state->builder.AddFunction({OpBitcast, state->float_type, f32, ConstantU32(state, 0)}); +uint32_t EmitZeroF32(EmitterState& state) { + const auto f32 = state.builder.AllocateId(); + state.builder.AddFunction({OpBitcast, state.float_type, f32, ConstantU32(state, 0)}); return f32; } diff --git a/src/graphics/shader/shader.cpp b/src/graphics/shader/shader.cpp index 9dec733a2..c8680d140 100644 --- a/src/graphics/shader/shader.cpp +++ b/src/graphics/shader/shader.cpp @@ -135,14 +135,13 @@ void ShaderMapUserData(uint64_t addr, const ShaderMappedData& data) { (*g_shader_map)[addr] = data; } -static bool ShaderGetMappedData(uint64_t addr, ShaderMappedData* data) { +static bool ShaderGetMappedData(uint64_t addr, ShaderMappedData& data) { EXIT_IF(g_shader_map == nullptr); - EXIT_IF(data == nullptr); std::scoped_lock lock(g_shader_map_mutex); if (auto iter = g_shader_map->find(addr); iter != g_shader_map->end()) { - *data = iter->second; + data = iter->second; return true; } @@ -219,7 +218,7 @@ static const ShaderBinaryInfo* GetBinaryInfo(const uint32_t* code) { static std::span ShaderGetMappedCode(uint64_t shader_addr, const char* label, uint64_t shader_hash) { ShaderMappedData data; - if (!ShaderGetMappedData(shader_addr, &data)) { + if (!ShaderGetMappedData(shader_addr, data)) { EXIT("%s hash=0x%016" PRIx64 " shader=0x%016" PRIx64 " is missing from ShaderMap\n", label, shader_hash, shader_addr); } @@ -435,10 +434,7 @@ static void cs_check(const HW::CsStageRegisters& cs, const HW::ShaderRegisters& } #endif -static void GetNextGenFallbackShaderId(uint64_t addr, uint32_t* hash0, uint32_t* crc32) { - EXIT_IF(hash0 == nullptr); - EXIT_IF(crc32 == nullptr); - +static void GetNextGenFallbackShaderId(uint64_t addr, uint32_t& hash0, uint32_t& crc32) { auto x = addr; x ^= x >> 33u; x *= 0xff51afd7ed558ccdull; @@ -446,28 +442,26 @@ static void GetNextGenFallbackShaderId(uint64_t addr, uint32_t* hash0, uint32_t* x *= 0xc4ceb9fe1a85ec53ull; x ^= x >> 33u; - *hash0 = static_cast((x >> 32u) & 0xffffffffu); - *crc32 = static_cast(x & 0xffffffffu); + hash0 = static_cast((x >> 32u) & 0xffffffffu); + crc32 = static_cast(x & 0xffffffffu); } -static void ShaderDetectBuffers(ShaderVertexInputInfo* info) { +static void ShaderDetectBuffers(ShaderVertexInputInfo& info) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(info == nullptr); + info.buffers_num = 0; - info->buffers_num = 0; - - for (int ri = 0; ri < info->resources_num; ri++) { - const auto& r = info->resources[ri]; + for (int ri = 0; ri < info.resources_num; ri++) { + const auto& r = info.resources[ri]; bool merged = false; - for (int bi = 0; bi < info->buffers_num; bi++) { - auto& b = info->buffers[bi]; + for (int bi = 0; bi < info.buffers_num; bi++) { + auto& b = info.buffers[bi]; uint64_t stride = b.stride; if (stride == r.Stride() && - b.fetch_index == static_cast(info->resources_dst[ri].fetch_index)) { + b.fetch_index == static_cast(info.resources_dst[ri].fetch_index)) { uint64_t rbase = r.Base48(); uint64_t base = std::min(rbase, b.addr); uint64_t offset1 = rbase - base; @@ -485,21 +479,21 @@ static void ShaderDetectBuffers(ShaderVertexInputInfo* info) { } if (!merged) { - EXIT_NOT_IMPLEMENTED(info->buffers_num >= ShaderVertexInputInfo::RES_MAX); - int bi = info->buffers_num++; - info->buffers[bi].addr = r.Base48(); - info->buffers[bi].stride = r.Stride(); - info->buffers[bi].num_records = r.NumRecords(); - info->buffers[bi].fetch_index = info->resources_dst[ri].fetch_index; - info->buffers[bi].attr_num = 1; - info->buffers[bi].attr_indices[0] = ri; + EXIT_NOT_IMPLEMENTED(info.buffers_num >= ShaderVertexInputInfo::RES_MAX); + int bi = info.buffers_num++; + info.buffers[bi].addr = r.Base48(); + info.buffers[bi].stride = r.Stride(); + info.buffers[bi].num_records = r.NumRecords(); + info.buffers[bi].fetch_index = info.resources_dst[ri].fetch_index; + info.buffers[bi].attr_num = 1; + info.buffers[bi].attr_indices[0] = ri; } } - for (int bi = 0; bi < info->buffers_num; bi++) { - auto& b = info->buffers[bi]; + for (int bi = 0; bi < info.buffers_num; bi++) { + auto& b = info.buffers[bi]; for (int ri = 0; ri < b.attr_num; ri++) { - b.attr_offsets[ri] = info->resources[b.attr_indices[ri]].Base48() - b.addr; + b.attr_offsets[ri] = info.resources[b.attr_indices[ri]].Base48() - b.addr; } } } @@ -610,13 +604,13 @@ static uint32_t VertexAttribFormatToBufferFormat(uint32_t format) { return format; } -static void ShaderApplyAttribSemantics(ShaderVertexInputInfo* info, +static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info, const ShaderSemantic* input_semantics, uint32_t num_input_semantics, const uint32_t* attrib, const uint32_t* buffer) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(info == nullptr || attrib == nullptr || buffer == nullptr); + EXIT_IF(attrib == nullptr || buffer == nullptr); for (uint32_t i = 0; i < num_input_semantics; i++) { const auto& in = input_semantics[i]; @@ -647,10 +641,10 @@ static void ShaderApplyAttribSemantics(ShaderVertexInputInfo* info, const auto* sharp = &buffer[index * 4]; - EXIT_NOT_IMPLEMENTED(info->resources_num >= ShaderVertexInputInfo::RES_MAX); + EXIT_NOT_IMPLEMENTED(info.resources_num >= ShaderVertexInputInfo::RES_MAX); - auto& r = info->resources[info->resources_num]; - auto& rd = info->resources_dst[info->resources_num]; + auto& r = info.resources[info.resources_num]; + auto& rd = info.resources_dst[info.resources_num]; rd.register_start = static_cast(reg); rd.registers_num = static_cast(size); rd.attr_id = static_cast(in.semantic); @@ -675,7 +669,7 @@ static void ShaderApplyAttribSemantics(ShaderVertexInputInfo* info, r.UpdateAddress48(r.Base48() + offset); } - info->resources_num++; + info.resources_num++; } } @@ -735,23 +729,21 @@ static uint32_t ShaderCalcPsSystemInputBase(const HW::ShaderRegisters& regs) { return reg; } -static bool ShaderGetStaticInputInfoVS(const HW::VertexShaderInfo* regs, - const HW::ShaderRegisters* sh, ShaderVertexInputInfo* info) { +static bool ShaderGetStaticInputInfoVS(const HW::VertexShaderInfo& regs, + const HW::ShaderRegisters& sh, ShaderVertexInputInfo& info) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(info == nullptr || regs == nullptr || sh == nullptr); + info = {}; - *info = {}; + info.export_count = static_cast(sh.GetExportCount()); - info->export_count = static_cast(sh->GetExportCount()); + EXIT_NOT_IMPLEMENTED(regs.es_regs.data_addr == 0 || regs.gs_regs.chksum == 0); - EXIT_NOT_IMPLEMENTED(regs->es_regs.data_addr == 0 || regs->gs_regs.chksum == 0); - - uint64_t shader_addr = regs->es_regs.data_addr; - const HW::UserSgprInfo& user_sgpr = regs->gs_user_sgpr; - auto user_sgpr_num = regs->gs_regs.rsrc2.user_sgpr; + uint64_t shader_addr = regs.es_regs.data_addr; + const HW::UserSgprInfo& user_sgpr = regs.gs_user_sgpr; + auto user_sgpr_num = regs.gs_regs.rsrc2.user_sgpr; ShaderMappedData data; - if (!ShaderGetMappedData(shader_addr, &data)) { + if (!ShaderGetMappedData(shader_addr, data)) { LOGF("ShaderGetInputInfoVS(): shader=0x%016" PRIx64 " is missing from ShaderMap\n", shader_addr); return false; @@ -760,22 +752,22 @@ static bool ShaderGetStaticInputInfoVS(const HW::VertexShaderInfo* regs, if (data.user_data == nullptr) { LOGF("ShaderGetInputInfoVS(): no AGC user data for shader=0x%016" PRIx64 " es=0x%016" PRIx64 " gs=0x%016" PRIx64 " chksum=0x%016" PRIx64 " user_sgpr_num=%u\n", - shader_addr, regs->es_regs.data_addr, regs->gs_regs.data_addr, regs->gs_regs.chksum, + shader_addr, regs.es_regs.data_addr, regs.gs_regs.data_addr, regs.gs_regs.chksum, static_cast(user_sgpr_num)); } ShaderVertexMetadata metadata; std::string metadata_error; - if (!ShaderReadVertexMetadata(data, HW::UserSgprInfo::SGPRS_MAX, &metadata, &metadata_error)) { + if (!ShaderReadVertexMetadata(data, HW::UserSgprInfo::SGPRS_MAX, metadata, &metadata_error)) { LOGF("ShaderGetInputInfoVS(): invalid AGC metadata shader=0x%016" PRIx64 ": %s\n", shader_addr, metadata_error.c_str()); return false; } if (metadata.vertex_buffer_reg >= 0) { - info->fetch_external = false; - info->fetch_embedded = true; - info->fetch_attrib_reg = metadata.vertex_attrib_reg; - info->fetch_buffer_reg = metadata.vertex_buffer_reg; + info.fetch_external = false; + info.fetch_embedded = true; + info.fetch_attrib_reg = metadata.vertex_attrib_reg; + info.fetch_buffer_reg = metadata.vertex_buffer_reg; const auto* attrib = reinterpret_cast( static_cast(user_sgpr.value[metadata.vertex_attrib_reg]) | @@ -797,76 +789,68 @@ static bool ShaderGetStaticInputInfoVS(const HW::VertexShaderInfo* regs, } static void ShaderGetStaticInputInfoPS( - const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh, - const ShaderVertexInputInfo* vs_info, + const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh, + const ShaderVertexInputInfo& vs_info, std::span target_export_mapping, - ShaderPixelInputInfo* ps_info) { + ShaderPixelInputInfo& ps_info) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(vs_info == nullptr); - EXIT_IF(ps_info == nullptr); - EXIT_IF(regs == nullptr); - EXIT_IF(sh == nullptr); + ps_info = {}; - *ps_info = {}; + ps_info.input_num = sh.ps_in_control; + ps_info.ps_system_input_base = ShaderCalcPsSystemInputBase(sh); + const uint32_t active_inputs = sh.ps_input_ena & sh.ps_input_addr; + ps_info.ps_pos_x = (active_inputs & 0x00000100u) != 0; + ps_info.ps_pos_y = (active_inputs & 0x00000200u) != 0; + ps_info.ps_pos_xy = ps_info.ps_pos_x && ps_info.ps_pos_y; + ps_info.ps_pos_z = (active_inputs & 0x00000400u) != 0; + ps_info.ps_pos_w = (active_inputs & 0x00000800u) != 0; + ps_info.ps_front_face = (active_inputs & 0x00001000u) != 0; + ps_info.ps_sample_shading = (active_inputs & 0x00000011u) != 0; + ps_info.ps_no_perspective = (sh.ps_input_ena & sh.ps_input_addr & 0x00000020u) != 0; + ps_info.ps_pixel_kill_enable = sh.db_shader_control.shader_kill_enable; + ps_info.ps_depth_export_enable = sh.db_shader_control.shader_z_export_enable; + ps_info.ps_sample_mask_export_enable = sh.db_shader_control.shader_mask_export_enable; + ps_info.ps_early_z = + (sh.db_shader_control.shader_z_behavior == 1 && !sh.db_shader_control.shader_kill_enable && + !sh.db_shader_control.shader_z_export_enable && + !sh.db_shader_control.shader_mask_export_enable); + ps_info.ps_execute_on_noop = sh.db_shader_control.shader_execute_on_noop; - ps_info->input_num = sh->ps_in_control; - ps_info->ps_system_input_base = ShaderCalcPsSystemInputBase(*sh); - const uint32_t active_inputs = sh->ps_input_ena & sh->ps_input_addr; - ps_info->ps_pos_x = (active_inputs & 0x00000100u) != 0; - ps_info->ps_pos_y = (active_inputs & 0x00000200u) != 0; - ps_info->ps_pos_xy = ps_info->ps_pos_x && ps_info->ps_pos_y; - ps_info->ps_pos_z = (active_inputs & 0x00000400u) != 0; - ps_info->ps_pos_w = (active_inputs & 0x00000800u) != 0; - ps_info->ps_front_face = (active_inputs & 0x00001000u) != 0; - ps_info->ps_sample_shading = (active_inputs & 0x00000011u) != 0; - ps_info->ps_no_perspective = (sh->ps_input_ena & sh->ps_input_addr & 0x00000020u) != 0; - ps_info->ps_pixel_kill_enable = sh->db_shader_control.shader_kill_enable; - ps_info->ps_depth_export_enable = sh->db_shader_control.shader_z_export_enable; - ps_info->ps_sample_mask_export_enable = sh->db_shader_control.shader_mask_export_enable; - ps_info->ps_early_z = (sh->db_shader_control.shader_z_behavior == 1 && - !sh->db_shader_control.shader_kill_enable && - !sh->db_shader_control.shader_z_export_enable && - !sh->db_shader_control.shader_mask_export_enable); - ps_info->ps_execute_on_noop = sh->db_shader_control.shader_execute_on_noop; - - for (uint32_t i = 0; i < ps_info->input_num; i++) { - ps_info->interpolator_settings[i] = sh->ps_interpolator_settings[i]; + for (uint32_t i = 0; i < ps_info.input_num; i++) { + ps_info.interpolator_settings[i] = sh.ps_interpolator_settings[i]; } - ps_info->descriptor_set = - vs_info->stage.program != nullptr && !vs_info->stage.program->bindings.descriptors.empty() + ps_info.descriptor_set = + vs_info.stage.program != nullptr && !vs_info.stage.program->bindings.descriptors.empty() ? 1 : 0; for (int i = 0; i < 8; i++) { - ps_info->target_output_mode[i] = sh->target_output_mode[i]; - ps_info->target_export_mapping[i] = sh->target_output_mode[i] != 0 - ? target_export_mapping[i] - : Prospero::ColorComponentMapping {}; + ps_info.target_output_mode[i] = sh.target_output_mode[i]; + ps_info.target_export_mapping[i] = sh.target_output_mode[i] != 0 + ? target_export_mapping[i] + : Prospero::ColorComponentMapping {}; } - ps_info->mrt_output_mask = 0; + ps_info.mrt_output_mask = 0; } -static void ShaderGetStaticInputInfoCS(const HW::ComputeShaderInfo* regs, - const HW::ShaderRegisters* /*sh*/, - ShaderComputeInputInfo* info) { - EXIT_IF(info == nullptr); - EXIT_IF(regs == nullptr); +static void ShaderGetStaticInputInfoCS(const HW::ComputeShaderInfo& regs, + const HW::ShaderRegisters& /*sh*/, + ShaderComputeInputInfo& info) { + info = {}; - *info = {}; + info.threads_num[0] = regs.cs_regs.num_thread_x; + info.threads_num[1] = regs.cs_regs.num_thread_y; + info.threads_num[2] = regs.cs_regs.num_thread_z; + info.group_id[0] = regs.cs_regs.tgid_x_en != 0; + info.group_id[1] = regs.cs_regs.tgid_y_en != 0; + info.group_id[2] = regs.cs_regs.tgid_z_en != 0; + info.wave_size = regs.cs_regs.wave_size; + info.thread_ids_num = regs.cs_regs.tidig_comp_cnt + 1; + info.tg_size_en = regs.cs_regs.tg_size_en != 0; - info->threads_num[0] = regs->cs_regs.num_thread_x; - info->threads_num[1] = regs->cs_regs.num_thread_y; - info->threads_num[2] = regs->cs_regs.num_thread_z; - info->group_id[0] = regs->cs_regs.tgid_x_en != 0; - info->group_id[1] = regs->cs_regs.tgid_y_en != 0; - info->group_id[2] = regs->cs_regs.tgid_z_en != 0; - info->wave_size = regs->cs_regs.wave_size; - info->thread_ids_num = regs->cs_regs.tidig_comp_cnt + 1; - info->tg_size_en = regs->cs_regs.tg_size_en != 0; - - info->workgroup_register = regs->cs_regs.user_sgpr; + info.workgroup_register = regs.cs_regs.user_sgpr; } static ShaderStageProgramKey MakeShaderStageProgramKey(ShaderType stage, uint64_t shader_hash, @@ -882,24 +866,24 @@ static ShaderStageProgramKey MakeShaderStageProgramKey(ShaderType stage, uint64_ return key; } -static void ApplyVertexOutputs(ShaderVertexInputInfo* info, +static void ApplyVertexOutputs(ShaderVertexInputInfo& info, const ShaderRecompiler::IR::Program& program) { - info->export_count = 0; - info->param_export_mask = 0; + info.export_count = 0; + info.param_export_mask = 0; for (const auto& output: program.info.outputs) { if (output.kind == ShaderRecompiler::IR::StageOutputKind::Parameter && output.index < 32) { - info->param_export_mask |= 1u << output.index; - info->export_count = std::max(info->export_count, static_cast(output.index + 1)); + info.param_export_mask |= 1u << output.index; + info.export_count = std::max(info.export_count, static_cast(output.index + 1)); } } } -static void ApplyPixelOutputs(ShaderPixelInputInfo* info, +static void ApplyPixelOutputs(ShaderPixelInputInfo& info, const ShaderRecompiler::IR::Program& program) { - info->mrt_output_mask = 0; + info.mrt_output_mask = 0; for (const auto& output: program.info.outputs) { if (output.kind == ShaderRecompiler::IR::StageOutputKind::Mrt && output.index < 8) { - info->mrt_output_mask |= 1u << output.index; + info.mrt_output_mask |= 1u << output.index; } } } @@ -920,14 +904,13 @@ static bool LogPermutationMismatch(const ShaderProgramPermutation& permutation, } static bool TryUseVertexPermutation(const ShaderProgramPermutation& permutation, - const HW::VertexShaderInfo* regs, ShaderVertexInputInfo* info, + const HW::VertexShaderInfo& regs, ShaderVertexInputInfo& info, uint64_t shader_hash) { - EXIT_IF(regs == nullptr || info == nullptr); std::string error; if (!ShaderMaterializeStageRuntime( permutation.program, - std::span(regs->gs_user_sgpr.value, regs->gs_regs.rsrc2.user_sgpr), - regs->es_regs.data_addr, &info->stage, &error)) { + std::span(regs.gs_user_sgpr.value, regs.gs_regs.rsrc2.user_sgpr), + regs.es_regs.data_addr, info.stage, &error)) { return LogPermutationMismatch(permutation, "VS", shader_hash, error); } ApplyVertexOutputs(info, *permutation.program); @@ -935,14 +918,13 @@ static bool TryUseVertexPermutation(const ShaderProgramPermutation& permutation, } static bool TryUsePixelPermutation(const ShaderProgramPermutation& permutation, - const HW::PixelShaderInfo* regs, ShaderPixelInputInfo* info, + const HW::PixelShaderInfo& regs, ShaderPixelInputInfo& info, uint64_t shader_hash) { - EXIT_IF(regs == nullptr || info == nullptr); std::string error; if (!ShaderMaterializeStageRuntime( permutation.program, - std::span(regs->ps_user_sgpr.value, regs->ps_regs.rsrc2.user_sgpr), - regs->ps_regs.data_addr, &info->stage, &error)) { + std::span(regs.ps_user_sgpr.value, regs.ps_regs.rsrc2.user_sgpr), + regs.ps_regs.data_addr, info.stage, &error)) { return LogPermutationMismatch(permutation, "PS", shader_hash, error); } ApplyPixelOutputs(info, *permutation.program); @@ -950,14 +932,13 @@ static bool TryUsePixelPermutation(const ShaderProgramPermutation& permutation, } static bool TryUseComputePermutation(const ShaderProgramPermutation& permutation, - const HW::ComputeShaderInfo* regs, - ShaderComputeInputInfo* info, uint64_t shader_hash) { - EXIT_IF(regs == nullptr || info == nullptr); + const HW::ComputeShaderInfo& regs, + ShaderComputeInputInfo& info, uint64_t shader_hash) { std::string error; if (!ShaderMaterializeStageRuntime( permutation.program, - std::span(regs->cs_user_sgpr.value, regs->cs_regs.user_sgpr), - regs->cs_regs.data_addr, &info->stage, &error)) { + std::span(regs.cs_user_sgpr.value, regs.cs_regs.user_sgpr), + regs.cs_regs.data_addr, info.stage, &error)) { return LogPermutationMismatch(permutation, "CS", shader_hash, error); } return true; @@ -1001,39 +982,39 @@ static std::string ShaderDescribeSpecialization(const ShaderRecompiler::IR::Prog return ret; } -static void ShaderAppendNativeSpecialization(std::vector* ids, +static void ShaderAppendNativeSpecialization(std::vector& ids, const ShaderRecompiler::IR::Program& program) { - EXIT_IF(ids == nullptr || !program.binding_layout_complete); - ids->push_back(static_cast(program.lane_mask_mode)); - ids->push_back(program.bindings.descriptor_set); - ids->push_back(program.bindings.push_constant_offset); - ids->push_back(program.bindings.push_constant_size); - ids->push_back(static_cast(program.bindings.user_data_registers.size())); - ids->insert(ids->end(), program.bindings.user_data_registers.begin(), + EXIT_IF(!program.binding_layout_complete); + ids.push_back(static_cast(program.lane_mask_mode)); + ids.push_back(program.bindings.descriptor_set); + ids.push_back(program.bindings.push_constant_offset); + ids.push_back(program.bindings.push_constant_size); + ids.push_back(static_cast(program.bindings.user_data_registers.size())); + ids.insert(ids.end(), program.bindings.user_data_registers.begin(), program.bindings.user_data_registers.end()); - ids->push_back(static_cast(program.bindings.descriptors.size())); + ids.push_back(static_cast(program.bindings.descriptors.size())); for (const auto& binding: program.bindings.descriptors) { - ids->push_back(static_cast(binding.kind)); - ids->push_back(binding.binding); - ids->push_back(static_cast(binding.resources.size())); - ids->insert(ids->end(), binding.resources.begin(), binding.resources.end()); + ids.push_back(static_cast(binding.kind)); + ids.push_back(binding.binding); + ids.push_back(static_cast(binding.resources.size())); + ids.insert(ids.end(), binding.resources.begin(), binding.resources.end()); } - ids->push_back(static_cast(program.info.buffers.size())); + ids.push_back(static_cast(program.info.buffers.size())); for (const auto& buffer: program.info.buffers) { - ids->push_back(buffer.packed_stride); - ids->push_back(buffer.descriptor_format); + ids.push_back(buffer.packed_stride); + ids.push_back(buffer.descriptor_format); } - ids->push_back(static_cast(program.info.images.size())); + ids.push_back(static_cast(program.info.images.size())); for (const auto& image: program.info.images) { - ids->push_back(static_cast(image.kind)); - ids->push_back(static_cast(image.dimension)); - ids->push_back(static_cast(image.mip_mode)); - ids->push_back(image.storage_swizzle); + ids.push_back(static_cast(image.kind)); + ids.push_back(static_cast(image.dimension)); + ids.push_back(static_cast(image.mip_mode)); + ids.push_back(image.storage_swizzle); } - ids->push_back(static_cast(program.info.addresses.size())); + ids.push_back(static_cast(program.info.addresses.size())); for (const auto& address: program.info.addresses) { - ids->push_back(static_cast(address.specialized_base)); - ids->push_back(static_cast(address.specialized_base >> 32u)); + ids.push_back(static_cast(address.specialized_base)); + ids.push_back(static_cast(address.specialized_base >> 32u)); } } @@ -1073,16 +1054,15 @@ static std::span AddShaderProgramPermutation(const char* stage, return spirv; } -bool ShaderCompileInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderLaneMaskMode lane_mask_mode, ShaderVertexInputInfo* info, - std::span* spirv) { - EXIT_IF(spirv == nullptr); - *spirv = {}; +bool ShaderCompileInfoVS(const HW::VertexShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderLaneMaskMode lane_mask_mode, ShaderVertexInputInfo& info, + std::span& spirv) { + spirv = {}; if (!ShaderGetStaticInputInfoVS(regs, sh, info)) { return false; } - const auto shader_hash = regs->gs_regs.chksum; + const auto shader_hash = regs.gs_regs.chksum; const auto program_id = ShaderGetIdVS(regs, info, false); const auto key = MakeShaderStageProgramKey(ShaderType::Vertex, shader_hash, program_id, lane_mask_mode); @@ -1092,9 +1072,9 @@ bool ShaderCompileInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegis if (auto iter = g_shader_program_cache.find(key); iter != g_shader_program_cache.end()) { for (const auto& permutation: iter->second) { if (TryUseVertexPermutation(*permutation, regs, info, shader_hash)) { - *spirv = MakeShaderSpirvView(permutation->spirv); + spirv = MakeShaderSpirvView(permutation->spirv); LogShaderProgramCacheHit("VS", shader_hash, - static_cast(spirv->size())); + static_cast(spirv.size())); return true; } } @@ -1102,27 +1082,26 @@ bool ShaderCompileInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegis } std::vector compiled_spirv; - if (!ShaderCompileSpirvVS(regs, sh, lane_mask_mode, info, &compiled_spirv)) { + if (!ShaderCompileSpirvVS(regs, sh, lane_mask_mode, info, compiled_spirv)) { return false; } ShaderProgramPermutation permutation {}; permutation.spirv = std::move(compiled_spirv); - permutation.program = info->stage.program; - *spirv = AddShaderProgramPermutation("VS", shader_hash, key, std::move(permutation)); + permutation.program = info.stage.program; + spirv = AddShaderProgramPermutation("VS", shader_hash, key, std::move(permutation)); return true; } -bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderLaneMaskMode lane_mask_mode, const ShaderVertexInputInfo* vs_info, +bool ShaderCompileInfoPS(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderLaneMaskMode lane_mask_mode, const ShaderVertexInputInfo& vs_info, std::span target_export_mapping, - ShaderPixelInputInfo* ps_info, std::span* spirv) { - EXIT_IF(spirv == nullptr); - *spirv = {}; + ShaderPixelInputInfo& ps_info, std::span& spirv) { + spirv = {}; ShaderGetStaticInputInfoPS(regs, sh, vs_info, target_export_mapping, ps_info); const auto shader_hash = - regs->ps_regs.chksum != 0 ? regs->ps_regs.chksum : regs->ps_regs.data_addr; + regs.ps_regs.chksum != 0 ? regs.ps_regs.chksum : regs.ps_regs.data_addr; const auto program_id = ShaderGetIdPS(regs, ps_info, false); const auto key = MakeShaderStageProgramKey(ShaderType::Pixel, shader_hash, program_id, lane_mask_mode); @@ -1132,9 +1111,9 @@ bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegist if (auto iter = g_shader_program_cache.find(key); iter != g_shader_program_cache.end()) { for (const auto& permutation: iter->second) { if (TryUsePixelPermutation(*permutation, regs, ps_info, shader_hash)) { - *spirv = MakeShaderSpirvView(permutation->spirv); + spirv = MakeShaderSpirvView(permutation->spirv); LogShaderProgramCacheHit("PS", shader_hash, - static_cast(spirv->size())); + static_cast(spirv.size())); return true; } } @@ -1142,24 +1121,23 @@ bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegist } std::vector compiled_spirv; - if (!ShaderCompileSpirvPS(regs, sh, lane_mask_mode, ps_info, &compiled_spirv)) { + if (!ShaderCompileSpirvPS(regs, sh, lane_mask_mode, ps_info, compiled_spirv)) { return false; } ShaderProgramPermutation permutation {}; permutation.spirv = std::move(compiled_spirv); - permutation.program = ps_info->stage.program; - *spirv = AddShaderProgramPermutation("PS", shader_hash, key, std::move(permutation)); + permutation.program = ps_info.stage.program; + spirv = AddShaderProgramPermutation("PS", shader_hash, key, std::move(permutation)); return true; } -bool ShaderCompileInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderComputeInputInfo* info, std::span* spirv) { - EXIT_IF(spirv == nullptr); - *spirv = {}; +bool ShaderCompileInfoCS(const HW::ComputeShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderComputeInputInfo& info, std::span& spirv) { + spirv = {}; ShaderGetStaticInputInfoCS(regs, sh, info); - const auto shader_hash = regs->cs_regs.data_addr; + const auto shader_hash = regs.cs_regs.data_addr; const auto program_id = ShaderGetIdCS(regs, info, false); const auto key = MakeShaderStageProgramKey(ShaderType::Compute, shader_hash, program_id, ShaderLaneMaskMode::NativeWave); @@ -1169,9 +1147,9 @@ bool ShaderCompileInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegi if (auto iter = g_shader_program_cache.find(key); iter != g_shader_program_cache.end()) { for (const auto& permutation: iter->second) { if (TryUseComputePermutation(*permutation, regs, info, shader_hash)) { - *spirv = MakeShaderSpirvView(permutation->spirv); + spirv = MakeShaderSpirvView(permutation->spirv); LogShaderProgramCacheHit("CS", shader_hash, - static_cast(spirv->size())); + static_cast(spirv.size())); return true; } } @@ -1179,19 +1157,19 @@ bool ShaderCompileInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegi } std::vector compiled_spirv; - if (!ShaderCompileSpirvCS(regs, sh, info, &compiled_spirv)) { + if (!ShaderCompileSpirvCS(regs, sh, info, compiled_spirv)) { return false; } ShaderProgramPermutation permutation {}; permutation.spirv = std::move(compiled_spirv); - permutation.program = info->stage.program; - *spirv = AddShaderProgramPermutation("CS", shader_hash, key, std::move(permutation)); + permutation.program = info.stage.program; + spirv = AddShaderProgramPermutation("CS", shader_hash, key, std::move(permutation)); return true; } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info) { +void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo& info) { KYTY_PROFILER_BLOCK("ShaderDbgDumpInputInfo(Vs)"); LOGF("ShaderDbgDumpInputInfo()\n"); @@ -1200,14 +1178,14 @@ void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info) { "\t fetch_embedded = %s\n" "\t param_export_mask = 0x%08" PRIx32 "\n" "\t export_count = %d\n", - info->fetch_external ? "true" : "false", info->fetch_embedded ? "true" : "false", - info->param_export_mask, info->export_count); + info.fetch_external ? "true" : "false", info.fetch_embedded ? "true" : "false", + info.param_export_mask, info.export_count); - for (int i = 0; i < info->resources_num; i++) { + for (int i = 0; i < info.resources_num; i++) { LOGF("\t input %d\n", i); - const auto& r = info->resources[i]; - const auto& rd = info->resources_dst[i]; + const auto& r = info.resources[i]; + const auto& rd = info.resources_dst[i]; LOGF("\t\t register_start = %d\n" "\t\t registers_num = %d\n" @@ -1231,10 +1209,10 @@ void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info) { LOGF("\t\t AddTid() = %s\n", r.AddTid() ? "true" : "false"); } - for (int i = 0; i < info->buffers_num; i++) { + for (int i = 0; i < info.buffers_num; i++) { LOGF("\t buffer %d\n", i); - const auto& r = info->buffers[i]; + const auto& r = info.buffers[i]; LOGF("\t\t addr = %" PRIx64 "\n" "\t\t stride = %" PRIu32 "\n" "\t\t num_records = %" PRIu32 "\n" @@ -1249,7 +1227,7 @@ void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info) { } } -void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo* info) { +void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo& info) { KYTY_PROFILER_BLOCK("ShaderDbgDumpInputInfo(Ps)"); LOGF("ShaderDbgDumpInputInfo()\n"); @@ -1266,19 +1244,19 @@ void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo* info) { "\t ps_pixel_kill_enable = %s\n" "\t ps_early_z = %s\n" "\t ps_execute_on_noop = %s\n", - info->input_num, info->ps_system_input_base, info->ps_pos_x ? "true" : "false", - info->ps_pos_y ? "true" : "false", info->ps_pos_z ? "true" : "false", - info->ps_pos_w ? "true" : "false", info->ps_front_face ? "true" : "false", - info->ps_sample_shading ? "true" : "false", info->ps_no_perspective ? "true" : "false", - info->ps_pixel_kill_enable ? "true" : "false", info->ps_early_z ? "true" : "false", - info->ps_execute_on_noop ? "true" : "false"); + info.input_num, info.ps_system_input_base, info.ps_pos_x ? "true" : "false", + info.ps_pos_y ? "true" : "false", info.ps_pos_z ? "true" : "false", + info.ps_pos_w ? "true" : "false", info.ps_front_face ? "true" : "false", + info.ps_sample_shading ? "true" : "false", info.ps_no_perspective ? "true" : "false", + info.ps_pixel_kill_enable ? "true" : "false", info.ps_early_z ? "true" : "false", + info.ps_execute_on_noop ? "true" : "false"); - for (uint32_t i = 0; i < info->input_num; i++) { - LOGF("\t interpolator_settings[%u] = %u\n", i, info->interpolator_settings[i]); + for (uint32_t i = 0; i < info.input_num; i++) { + LOGF("\t interpolator_settings[%u] = %u\n", i, info.interpolator_settings[i]); } } -void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo* info) { +void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo& info) { LOGF("ShaderDbgDumpInputInfo()\n"); LOGF("\t workgroup_register = %d\n" @@ -1286,10 +1264,10 @@ void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo* info) { "\t wave_size = %u\n" "\t threads_num = {%u, %u, %u}\n" "\t tg_size_en = %s\n", - info->workgroup_register, info->thread_ids_num, info->wave_size, info->threads_num[0], - info->threads_num[1], info->threads_num[2], info->tg_size_en ? "true" : "false"); - LOGF("\t threadgroup_id = {%s, %s, %s}\n", info->group_id[0] ? "true" : "false", - info->group_id[1] ? "true" : "false", info->group_id[2] ? "true" : "false"); + info.workgroup_register, info.thread_ids_num, info.wave_size, info.threads_num[0], + info.threads_num[1], info.threads_num[2], info.tg_size_en ? "true" : "false"); + LOGF("\t threadgroup_id = {%s, %s, %s}\n", info.group_id[0] ? "true" : "false", + info.group_id[1] ? "true" : "false", info.group_id[2] ? "true" : "false"); } static bool ShaderRecompilerTextDumpEnabled() { @@ -1387,39 +1365,34 @@ static void DumpShaderRecompilerOriginal(const char* type, uint64_t shader_hash, } } -bool ShaderCompileSpirvVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderLaneMaskMode lane_mask_mode, ShaderVertexInputInfo* input_info, - std::vector* spirv) { +bool ShaderCompileSpirvVS(const HW::VertexShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderLaneMaskMode lane_mask_mode, ShaderVertexInputInfo& input_info, + std::vector& spirv) { KYTY_PROFILER_FUNCTION(profiler::colors::Amber300); - EXIT_IF(regs == nullptr); - EXIT_IF(sh == nullptr); - EXIT_IF(input_info == nullptr); - EXIT_IF(spirv == nullptr); + EXIT_NOT_IMPLEMENTED(regs.es_regs.data_addr == 0 || regs.gs_regs.chksum == 0); - EXIT_NOT_IMPLEMENTED(regs->es_regs.data_addr == 0 || regs->gs_regs.chksum == 0); - - const uint64_t shader_addr = regs->es_regs.data_addr; - const auto code = ShaderGetMappedCode(shader_addr, "ShaderRecompiler VS", regs->gs_regs.chksum); + const uint64_t shader_addr = regs.es_regs.data_addr; + const auto code = ShaderGetMappedCode(shader_addr, "ShaderRecompiler VS", regs.gs_regs.chksum); ShaderRecompiler::CompileOptions options; options.stage = ShaderType::Vertex; options.lane_mask_mode = lane_mask_mode; - options.shader_hash = regs->gs_regs.chksum; + options.shader_hash = regs.gs_regs.chksum; options.shader_base = shader_addr; options.user_data_base = 8; - options.user_data_count = regs->gs_regs.rsrc2.user_sgpr; - options.user_data = regs->gs_user_sgpr.value; + options.user_data_count = regs.gs_regs.rsrc2.user_sgpr; + options.user_data = regs.gs_user_sgpr.value; options.descriptor_set = 0; options.push_constant_offset = 0; - options.vertex_input_info = input_info; + options.vertex_input_info = &input_info; options.dump_ir = ShaderRecompilerTextDumpEnabled(); options.early_dump = options.dump_ir; options.dump_label = "ShaderRecompiler VS"; ShaderRecompiler::CompileResult result; std::string error; - if (!ShaderRecompiler::TryRecompile(code, options, &result, &error)) { + if (!ShaderRecompiler::TryRecompile(code, options, result, &error)) { ExitShaderRecompilerFailure("ShaderRecompiler VS", options.shader_hash, error.c_str()); } DumpShaderRecompilerOriginal("vs", options.shader_hash, code, result.decoded_dump); @@ -1429,37 +1402,31 @@ bool ShaderCompileSpirvVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegi "SPIR-V validation failed"); } - input_info->stage.program = + input_info.stage.program = std::make_shared(std::move(result.program)); - input_info->stage.resources = + input_info.stage.resources = std::make_shared(std::move(result.resources)); - ApplyVertexOutputs(input_info, *input_info->stage.program); - *spirv = std::move(result.spirv); - DumpShaderRecompilerSpirv("vs", options.shader_hash, *spirv); + ApplyVertexOutputs(input_info, *input_info.stage.program); + spirv = std::move(result.spirv); + DumpShaderRecompilerSpirv("vs", options.shader_hash, spirv); if (options.dump_ir) { if (!options.early_dump) { LOGF("ShaderRecompiler VS decoded RDNA2:\n%s", result.decoded_dump.c_str()); LOGF("ShaderRecompiler VS IR:\n%s", result.ir_dump.c_str()); } - LOGF("ShaderRecompiler VS SPIR-V words=%" PRIu64 "\n", - static_cast(spirv->size())); + LOGF("ShaderRecompiler VS SPIR-V words=%" PRIu64 "\n", static_cast(spirv.size())); } return true; } -bool ShaderCompileSpirvPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderLaneMaskMode lane_mask_mode, ShaderPixelInputInfo* input_info, - std::vector* spirv) { +bool ShaderCompileSpirvPS(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderLaneMaskMode lane_mask_mode, ShaderPixelInputInfo& input_info, + std::vector& spirv) { KYTY_PROFILER_FUNCTION(profiler::colors::Blue300); - EXIT_IF(regs == nullptr); - EXIT_IF(sh == nullptr); - EXIT_IF(input_info == nullptr); - EXIT_IF(spirv == nullptr); - - const uint64_t shader_addr = regs->ps_regs.data_addr; - const uint64_t shader_hash = regs->ps_regs.chksum != 0 ? regs->ps_regs.chksum : shader_addr; + const uint64_t shader_addr = regs.ps_regs.data_addr; + const uint64_t shader_hash = regs.ps_regs.chksum != 0 ? regs.ps_regs.chksum : shader_addr; const auto code = ShaderGetMappedCode(shader_addr, "ShaderRecompiler PS", shader_hash); ShaderRecompiler::CompileOptions options; @@ -1467,18 +1434,18 @@ bool ShaderCompileSpirvPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegis options.lane_mask_mode = lane_mask_mode; options.shader_hash = shader_hash; options.shader_base = shader_addr; - options.user_data_count = regs->ps_regs.rsrc2.user_sgpr; - options.user_data = regs->ps_user_sgpr.value; - options.descriptor_set = input_info->descriptor_set; + options.user_data_count = regs.ps_regs.rsrc2.user_sgpr; + options.user_data = regs.ps_user_sgpr.value; + options.descriptor_set = input_info.descriptor_set; options.push_constant_offset = 0; - options.pixel_input_info = input_info; + options.pixel_input_info = &input_info; options.dump_ir = ShaderRecompilerTextDumpEnabled(); options.early_dump = options.dump_ir; options.dump_label = "ShaderRecompiler PS"; ShaderRecompiler::CompileResult result; std::string error; - if (!ShaderRecompiler::TryRecompile(code, options, &result, &error)) { + if (!ShaderRecompiler::TryRecompile(code, options, result, &error)) { ExitShaderRecompilerFailure("ShaderRecompiler PS", options.shader_hash, error.c_str()); } DumpShaderRecompilerOriginal("ps", options.shader_hash, code, result.decoded_dump); @@ -1487,54 +1454,48 @@ bool ShaderCompileSpirvPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegis ExitShaderRecompilerFailure("ShaderRecompiler PS", options.shader_hash, "SPIR-V validation failed"); } - input_info->stage.program = + input_info.stage.program = std::make_shared(std::move(result.program)); - input_info->stage.resources = + input_info.stage.resources = std::make_shared(std::move(result.resources)); - ApplyPixelOutputs(input_info, *input_info->stage.program); - *spirv = std::move(result.spirv); - DumpShaderRecompilerSpirv("ps", options.shader_hash, *spirv); + ApplyPixelOutputs(input_info, *input_info.stage.program); + spirv = std::move(result.spirv); + DumpShaderRecompilerSpirv("ps", options.shader_hash, spirv); if (options.dump_ir) { if (!options.early_dump) { LOGF("ShaderRecompiler PS decoded RDNA2:\n%s", result.decoded_dump.c_str()); LOGF("ShaderRecompiler PS IR:\n%s", result.ir_dump.c_str()); } - LOGF("ShaderRecompiler PS SPIR-V words=%" PRIu64 "\n", - static_cast(spirv->size())); + LOGF("ShaderRecompiler PS SPIR-V words=%" PRIu64 "\n", static_cast(spirv.size())); } return true; } -bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderComputeInputInfo* input_info, std::vector* spirv) { +bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderComputeInputInfo& input_info, std::vector& spirv) { KYTY_PROFILER_FUNCTION(profiler::colors::CyanA700); - EXIT_IF(regs == nullptr); - EXIT_IF(sh == nullptr); - EXIT_IF(input_info == nullptr); - EXIT_IF(spirv == nullptr); - - const uint64_t shader_addr = regs->cs_regs.data_addr; + const uint64_t shader_addr = regs.cs_regs.data_addr; const auto code = ShaderGetMappedCode(shader_addr, "ShaderRecompiler CS", shader_addr); ShaderRecompiler::CompileOptions options; options.stage = ShaderType::Compute; options.shader_hash = shader_addr; options.shader_base = shader_addr; - options.user_data_count = regs->cs_regs.user_sgpr; - options.user_data = regs->cs_user_sgpr.value; + options.user_data_count = regs.cs_regs.user_sgpr; + options.user_data = regs.cs_user_sgpr.value; options.descriptor_set = 0; options.push_constant_offset = 0; - options.compute_input_info = input_info; - options.wave_size = input_info->wave_size; + options.compute_input_info = &input_info; + options.wave_size = input_info.wave_size; options.dump_ir = ShaderRecompilerTextDumpEnabled(); options.early_dump = options.dump_ir; options.dump_label = "ShaderRecompiler CS"; ShaderRecompiler::CompileResult result; std::string error; - if (!ShaderRecompiler::TryRecompile(code, options, &result, &error)) { + if (!ShaderRecompiler::TryRecompile(code, options, result, &error)) { ExitShaderRecompilerFailure("ShaderRecompiler CS", options.shader_hash, error.c_str()); } DumpShaderRecompilerOriginal("cs", options.shader_hash, code, result.decoded_dump); @@ -1543,12 +1504,12 @@ bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo* regs, const HW::ShaderReg ExitShaderRecompilerFailure("ShaderRecompiler CS", options.shader_hash, "SPIR-V validation failed"); } - input_info->stage.program = + input_info.stage.program = std::make_shared(std::move(result.program)); - input_info->stage.resources = + input_info.stage.resources = std::make_shared(std::move(result.resources)); - *spirv = std::move(result.spirv); - DumpShaderRecompilerSpirv("cs", options.shader_hash, *spirv); + spirv = std::move(result.spirv); + DumpShaderRecompilerSpirv("cs", options.shader_hash, spirv); if (options.dump_ir) { if (!options.early_dump) { @@ -1556,12 +1517,12 @@ bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo* regs, const HW::ShaderReg LOGF("ShaderRecompiler CS IR:\n%s", result.ir_dump.c_str()); } LOGF("ShaderRecompiler CS SPIR-V words=%" PRIu64 " wave_size=%u\n", - static_cast(spirv->size()), options.wave_size); + static_cast(spirv.size()), options.wave_size); } return true; } -ShaderId ShaderGetIdVS(const HW::VertexShaderInfo* regs, const ShaderVertexInputInfo* input_info, +ShaderId ShaderGetIdVS(const HW::VertexShaderInfo& regs, const ShaderVertexInputInfo& input_info, bool include_bind_specialization) { KYTY_PROFILER_FUNCTION(); @@ -1569,19 +1530,19 @@ ShaderId ShaderGetIdVS(const HW::VertexShaderInfo* regs, const ShaderVertexInput ret.ids.reserve(64); - EXIT_NOT_IMPLEMENTED(regs->es_regs.data_addr == 0 || regs->gs_regs.chksum == 0); + EXIT_NOT_IMPLEMENTED(regs.es_regs.data_addr == 0 || regs.gs_regs.chksum == 0); - ret.hash0 = (regs->gs_regs.chksum >> 32u) & 0xffffffffu; - ret.crc32 = regs->gs_regs.chksum & 0xffffffffu; + ret.hash0 = (regs.gs_regs.chksum >> 32u) & 0xffffffffu; + ret.crc32 = regs.gs_regs.chksum & 0xffffffffu; - ret.ids.push_back(static_cast(input_info->fetch_external)); - ret.ids.push_back(static_cast(input_info->fetch_embedded)); - ret.ids.push_back(input_info->resources_num); - ret.ids.push_back(input_info->export_count); + ret.ids.push_back(static_cast(input_info.fetch_external)); + ret.ids.push_back(static_cast(input_info.fetch_embedded)); + ret.ids.push_back(input_info.resources_num); + ret.ids.push_back(input_info.export_count); - for (int i = 0; i < input_info->resources_num; i++) { - const auto& r = input_info->resources[i]; - const auto& rd = input_info->resources_dst[i]; + for (int i = 0; i < input_info.resources_num; i++) { + const auto& r = input_info.resources[i]; + const auto& rd = input_info.resources_dst[i]; ret.ids.push_back(rd.register_start); ret.ids.push_back(rd.registers_num); @@ -1597,10 +1558,10 @@ ShaderId ShaderGetIdVS(const HW::VertexShaderInfo* regs, const ShaderVertexInput ret.ids.push_back(static_cast(r.AddTid())); } - ret.ids.push_back(input_info->buffers_num); + ret.ids.push_back(input_info.buffers_num); - for (int i = 0; i < input_info->buffers_num; i++) { - const auto& r = input_info->buffers[i]; + for (int i = 0; i < input_info.buffers_num; i++) { + const auto& r = input_info.buffers[i]; ret.ids.push_back(r.attr_num); ret.ids.push_back(r.stride); ret.ids.push_back(r.fetch_index); @@ -1611,14 +1572,14 @@ ShaderId ShaderGetIdVS(const HW::VertexShaderInfo* regs, const ShaderVertexInput } if (include_bind_specialization) { - EXIT_IF(!input_info->stage); - ShaderAppendNativeSpecialization(&ret.ids, *input_info->stage.program); + EXIT_IF(!input_info.stage); + ShaderAppendNativeSpecialization(ret.ids, *input_info.stage.program); } return ret; } -ShaderId ShaderGetIdPS(const HW::PixelShaderInfo* regs, const ShaderPixelInputInfo* input_info, +ShaderId ShaderGetIdPS(const HW::PixelShaderInfo& regs, const ShaderPixelInputInfo& input_info, bool include_bind_specialization) { KYTY_PROFILER_FUNCTION(); @@ -1626,50 +1587,50 @@ ShaderId ShaderGetIdPS(const HW::PixelShaderInfo* regs, const ShaderPixelInputIn ret.ids.reserve(64); - ret.hash0 = (regs->ps_regs.chksum >> 32u) & 0xffffffffu; - ret.crc32 = regs->ps_regs.chksum & 0xffffffffu; + ret.hash0 = (regs.ps_regs.chksum >> 32u) & 0xffffffffu; + ret.crc32 = regs.ps_regs.chksum & 0xffffffffu; - ret.ids.push_back(input_info->descriptor_set); - ret.ids.push_back(input_info->input_num); - ret.ids.push_back(input_info->ps_system_input_base); - ret.ids.push_back(static_cast(input_info->ps_pos_x)); - ret.ids.push_back(static_cast(input_info->ps_pos_y)); - ret.ids.push_back(static_cast(input_info->ps_pos_z)); - ret.ids.push_back(static_cast(input_info->ps_pos_w)); - ret.ids.push_back(static_cast(input_info->ps_front_face)); - ret.ids.push_back(static_cast(input_info->ps_pixel_kill_enable)); - ret.ids.push_back(static_cast(input_info->ps_sample_mask_export_enable)); - ret.ids.push_back(static_cast(input_info->ps_early_z)); - ret.ids.push_back(static_cast(input_info->ps_execute_on_noop)); + ret.ids.push_back(input_info.descriptor_set); + ret.ids.push_back(input_info.input_num); + ret.ids.push_back(input_info.ps_system_input_base); + ret.ids.push_back(static_cast(input_info.ps_pos_x)); + ret.ids.push_back(static_cast(input_info.ps_pos_y)); + ret.ids.push_back(static_cast(input_info.ps_pos_z)); + ret.ids.push_back(static_cast(input_info.ps_pos_w)); + ret.ids.push_back(static_cast(input_info.ps_front_face)); + ret.ids.push_back(static_cast(input_info.ps_pixel_kill_enable)); + ret.ids.push_back(static_cast(input_info.ps_sample_mask_export_enable)); + ret.ids.push_back(static_cast(input_info.ps_early_z)); + ret.ids.push_back(static_cast(input_info.ps_execute_on_noop)); - for (auto mode: input_info->target_output_mode) { + for (auto mode: input_info.target_output_mode) { ret.ids.push_back(mode); } - for (uint32_t base = 0; base < input_info->target_export_mapping.size(); base += 4u) { + for (uint32_t base = 0; base < input_info.target_export_mapping.size(); base += 4u) { uint32_t packed = 0; for (uint32_t i = 0; i < 4u; i++) { - packed |= static_cast(input_info->target_export_mapping[base + i].packed) + packed |= static_cast(input_info.target_export_mapping[base + i].packed) << (i * 8u); } ret.ids.push_back(packed); } - ret.ids.push_back(input_info->mrt_output_mask); + ret.ids.push_back(input_info.mrt_output_mask); - for (uint32_t i = 0; i < input_info->input_num; i++) { - ret.ids.push_back(input_info->interpolator_settings[i]); + for (uint32_t i = 0; i < input_info.input_num; i++) { + ret.ids.push_back(input_info.interpolator_settings[i]); } if (include_bind_specialization) { - EXIT_IF(!input_info->stage); - ShaderAppendNativeSpecialization(&ret.ids, *input_info->stage.program); + EXIT_IF(!input_info.stage); + ShaderAppendNativeSpecialization(ret.ids, *input_info.stage.program); } return ret; } -ShaderId ShaderGetIdCS(const HW::ComputeShaderInfo* regs, const ShaderComputeInputInfo* input_info, +ShaderId ShaderGetIdCS(const HW::ComputeShaderInfo& regs, const ShaderComputeInputInfo& input_info, bool include_bind_specialization) { - const auto* src = reinterpret_cast(regs->cs_regs.data_addr); + const auto* src = reinterpret_cast(regs.cs_regs.data_addr); EXIT_NOT_IMPLEMENTED(src == nullptr); @@ -1683,27 +1644,27 @@ ShaderId ShaderGetIdCS(const HW::ComputeShaderInfo* regs, const ShaderComputeInp ret.crc32 = header->crc32; ret.ids.push_back(header->length); } else { - GetNextGenFallbackShaderId(regs->cs_regs.data_addr, &ret.hash0, &ret.crc32); - ret.ids.push_back(static_cast(regs->cs_regs.data_addr & 0xffffffffu)); - ret.ids.push_back(static_cast((regs->cs_regs.data_addr >> 32u) & 0xffffffffu)); + GetNextGenFallbackShaderId(regs.cs_regs.data_addr, ret.hash0, ret.crc32); + ret.ids.push_back(static_cast(regs.cs_regs.data_addr & 0xffffffffu)); + ret.ids.push_back(static_cast((regs.cs_regs.data_addr >> 32u) & 0xffffffffu)); } - ret.ids.push_back(input_info->workgroup_register); - ret.ids.push_back(input_info->wave_size); - ret.ids.push_back(input_info->thread_ids_num); + ret.ids.push_back(input_info.workgroup_register); + ret.ids.push_back(input_info.wave_size); + ret.ids.push_back(input_info.thread_ids_num); for (int i = 0; i < 3; i++) { - ret.ids.push_back(input_info->threads_num[i]); - ret.ids.push_back(static_cast(input_info->group_id[i])); + ret.ids.push_back(input_info.threads_num[i]); + ret.ids.push_back(static_cast(input_info.group_id[i])); } - ret.ids.push_back(static_cast(input_info->dispatch_thread_dimensions)); - for (uint32_t dim: input_info->dispatch_threads_num) { + ret.ids.push_back(static_cast(input_info.dispatch_thread_dimensions)); + for (uint32_t dim: input_info.dispatch_threads_num) { ret.ids.push_back(dim); } if (include_bind_specialization) { - EXIT_IF(!input_info->stage); - ShaderAppendNativeSpecialization(&ret.ids, *input_info->stage.program); + EXIT_IF(!input_info.stage); + ShaderAppendNativeSpecialization(ret.ids, *input_info.stage.program); } return ret; diff --git a/src/graphics/shader/shader.h b/src/graphics/shader/shader.h index 0f8327f10..753c12749 100644 --- a/src/graphics/shader/shader.h +++ b/src/graphics/shader/shader.h @@ -42,8 +42,8 @@ struct ShaderStageRuntime { // Resolves an immutable native shader plan against current user data. The prior stage is preserved // if any ReadConst, snapshot, or specialization check fails. bool ShaderMaterializeStageRuntime(std::shared_ptr program, - std::span user_data, uint64_t shader_base, - ShaderStageRuntime* stage, std::string* error); + std::span user_data, uint64_t shader_base, + ShaderStageRuntime& stage, std::string* error); struct ShaderId { uint32_t hash0 = 0; @@ -216,33 +216,33 @@ struct ShaderMappedData { void ShaderInit(); void ShaderMapUserData(uint64_t addr, const ShaderMappedData& data); -void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo* info); -void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo* info); -void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo* info); -ShaderId ShaderGetIdVS(const HW::VertexShaderInfo* regs, const ShaderVertexInputInfo* input_info, +void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo& info); +void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo& info); +void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo& info); +ShaderId ShaderGetIdVS(const HW::VertexShaderInfo& regs, const ShaderVertexInputInfo& input_info, bool include_bind_specialization); -ShaderId ShaderGetIdPS(const HW::PixelShaderInfo* regs, const ShaderPixelInputInfo* input_info, +ShaderId ShaderGetIdPS(const HW::PixelShaderInfo& regs, const ShaderPixelInputInfo& input_info, bool include_bind_specialization); -ShaderId ShaderGetIdCS(const HW::ComputeShaderInfo* regs, const ShaderComputeInputInfo* input_info, +ShaderId ShaderGetIdCS(const HW::ComputeShaderInfo& regs, const ShaderComputeInputInfo& input_info, bool include_bind_specialization); // Returned SPIR-V spans are read-only views backed by the shader program cache. -bool ShaderCompileInfoVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderLaneMaskMode lane_mask_mode, ShaderVertexInputInfo* input_info, - std::span* spirv); -bool ShaderCompileInfoPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderLaneMaskMode lane_mask_mode, const ShaderVertexInputInfo* vs_info, +bool ShaderCompileInfoVS(const HW::VertexShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderLaneMaskMode lane_mask_mode, ShaderVertexInputInfo& input_info, + std::span& spirv); +bool ShaderCompileInfoPS(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderLaneMaskMode lane_mask_mode, const ShaderVertexInputInfo& vs_info, std::span target_export_mapping, - ShaderPixelInputInfo* input_info, std::span* spirv); -bool ShaderCompileInfoCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderComputeInputInfo* input_info, std::span* spirv); -bool ShaderCompileSpirvVS(const HW::VertexShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderLaneMaskMode lane_mask_mode, ShaderVertexInputInfo* input_info, - std::vector* spirv); -bool ShaderCompileSpirvPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderLaneMaskMode lane_mask_mode, ShaderPixelInputInfo* input_info, - std::vector* spirv); -bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh, - ShaderComputeInputInfo* input_info, std::vector* spirv); + ShaderPixelInputInfo& input_info, std::span& spirv); +bool ShaderCompileInfoCS(const HW::ComputeShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderComputeInputInfo& input_info, std::span& spirv); +bool ShaderCompileSpirvVS(const HW::VertexShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderLaneMaskMode lane_mask_mode, ShaderVertexInputInfo& input_info, + std::vector& spirv); +bool ShaderCompileSpirvPS(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderLaneMaskMode lane_mask_mode, ShaderPixelInputInfo& input_info, + std::vector& spirv); +bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo& regs, const HW::ShaderRegisters& sh, + ShaderComputeInputInfo& input_info, std::vector& spirv); bool ShaderAddressValid(uint64_t addr); } // namespace Libs::Graphics diff --git a/src/graphics/shader/shaderStageRuntime.cpp b/src/graphics/shader/shaderStageRuntime.cpp index 3df5f4b1c..8cbe6f189 100644 --- a/src/graphics/shader/shaderStageRuntime.cpp +++ b/src/graphics/shader/shaderStageRuntime.cpp @@ -6,12 +6,11 @@ namespace Libs::Graphics { bool ShaderMaterializeStageRuntime(std::shared_ptr program, - std::span user_data, uint64_t shader_base, - ShaderStageRuntime* stage, std::string* error) { - if (program == nullptr || stage == nullptr) { + std::span user_data, uint64_t shader_base, + ShaderStageRuntime& stage, std::string* error) { + if (program == nullptr) { if (error != nullptr) { - *error = - program == nullptr ? "missing native shader plan" : "missing shader stage output"; + *error = "missing native shader plan"; } return false; } @@ -19,13 +18,13 @@ bool ShaderMaterializeStageRuntime(std::shared_ptr(std::move(snapshot)); - *stage = {std::move(program), std::move(resources)}; + stage = {std::move(program), std::move(resources)}; return true; } diff --git a/src/graphics/shader/shaderVertexMetadata.cpp b/src/graphics/shader/shaderVertexMetadata.cpp index 66a8b3309..69b8fb549 100644 --- a/src/graphics/shader/shaderVertexMetadata.cpp +++ b/src/graphics/shader/shaderVertexMetadata.cpp @@ -17,10 +17,7 @@ bool Fail(std::string* error, const char* message) { } // namespace bool ShaderReadVertexMetadata(const ShaderMappedData& data, uint32_t max_user_sgprs, - ShaderVertexMetadata* metadata, std::string* error) { - if (metadata == nullptr) { - return Fail(error, "missing vertex metadata output"); - } + ShaderVertexMetadata& metadata, std::string* error) { if (data.user_data == nullptr) { return Fail(error, "missing AGC user-data header"); } @@ -61,7 +58,7 @@ bool ShaderReadVertexMetadata(const ShaderMappedData& data, uint32_t max_user_sg const bool embedded = next.vertex_buffer_reg >= 0 || next.vertex_attrib_reg >= 0; if (!embedded) { - *metadata = next; + metadata = next; return true; } if (next.vertex_buffer_reg < 0 || next.vertex_attrib_reg < 0) { @@ -83,7 +80,7 @@ bool ShaderReadVertexMetadata(const ShaderMappedData& data, uint32_t max_user_sg } std::memcpy(next.input_semantics.data(), data.input_semantics, semantic_size); next.input_semantics_count = data.num_input_semantics; - *metadata = next; + metadata = next; return true; } diff --git a/src/graphics/shader/shaderVertexMetadata.h b/src/graphics/shader/shaderVertexMetadata.h index 122ca0954..4ef782d05 100644 --- a/src/graphics/shader/shaderVertexMetadata.h +++ b/src/graphics/shader/shaderVertexMetadata.h @@ -17,7 +17,7 @@ struct ShaderVertexMetadata { // Copies the small AGC metadata subset used by the vertex path after validating every guest range. bool ShaderReadVertexMetadata(const ShaderMappedData& data, uint32_t max_user_sgprs, - ShaderVertexMetadata* metadata, std::string* error); + ShaderVertexMetadata& metadata, std::string* error); } // namespace Libs::Graphics diff --git a/src/kernel/memory.cpp b/src/kernel/memory.cpp index e525cc9b0..7d1e916e3 100644 --- a/src/kernel/memory.cpp +++ b/src/kernel/memory.cpp @@ -68,7 +68,7 @@ constexpr uint64_t DEFAULT_FLEXIBLE_MEMORY_SIZE = 4ull * 1024ull * 1024ull * 102 static uint64_t g_flexible_memory_size = DEFAULT_FLEXIBLE_MEMORY_SIZE; static Graphics::GpuResourceManager& GetGpuResources() { - return *Graphics::g_render_ctx->GetGpuResources(); + return Graphics::GetRenderContext().GetGpuResources(); } static bool IsGpuAddressRange(uint64_t vaddr, uint64_t size) { @@ -883,10 +883,10 @@ void WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept { } void PrepareHostWrite(uint64_t vaddr, uint64_t size) { - if (size == 0 || Graphics::g_render_ctx == nullptr) { + if (size == 0 || !Graphics::HasRenderContext()) { return; } - Graphics::g_render_ctx->GetGpuResources()->PrepareHostWrite(vaddr, size); + Graphics::GetRenderContext().GetGpuResources().PrepareHostWrite(vaddr, size); } struct PrtAperture { diff --git a/src/loader/runtimeLinker.cpp b/src/loader/runtimeLinker.cpp index 526c31d00..edf0535d6 100644 --- a/src/loader/runtimeLinker.cpp +++ b/src/loader/runtimeLinker.cpp @@ -515,8 +515,8 @@ static bool KytyExceptionHandler(const Common::HostException::ExceptionInfo& exc EXIT("invalid access type for page fault at 0x%016" PRIx64 "\n", info->access_violation_vaddr); }(); - if (Libs::Graphics::g_render_ctx != nullptr && - Libs::Graphics::g_render_ctx->GetGpuResources()->HandleFault( + if (Libs::Graphics::HasRenderContext() && + Libs::Graphics::GetRenderContext().GetGpuResources().HandleFault( access, info->access_violation_vaddr)) { return true; } diff --git a/tests/ResourceTrackingTests.cpp b/tests/ResourceTrackingTests.cpp index 24dbcaf4a..de6b139ab 100644 --- a/tests/ResourceTrackingTests.cpp +++ b/tests/ResourceTrackingTests.cpp @@ -164,7 +164,7 @@ const StageOutput *FindOutput(const ShaderInfo &info, StageOutputKind kind, return nullptr; } -void Prepare(Program *program) { +void Prepare(Program& program) { std::string error; if (!BuildScalarProvenance(program, &error) || !BuildSrtPlan(program, &error) || !PatchSrtReads(program, &error) || @@ -186,7 +186,7 @@ void TestDenseBufferPatching() { insts = {first, atomic, write, Move(12, 4, 20), Move(16, 5, 21), Move(20, 6, 22), Move(24, 7, 23), BufferUse(28, 4)}; - Prepare(&program); + Prepare(program); Check(program.info.buffers.size() == 2, "buffer sources were not densely deduplicated"); const auto &resource = program.info.buffers[0]; @@ -201,7 +201,7 @@ void TestDenseBufferPatching() { insts[7].memory.resource_source == ScalarProvenance::Undefined, "patched instructions retained duplicate descriptor source handles"); std::string error; - Check(!TrackResources(&program, &error) && + Check(!TrackResources(program, &error) && error.find("already tracked") != std::string::npos, "resource tracking was not guarded against a second patch pass"); } @@ -219,7 +219,7 @@ void TestScalarAndVectorBufferAlias() { scalar.memory.resource = 2; program.blocks[0].instructions = {scalar, BufferUse(8, 8)}; - Prepare(&program); + Prepare(program); Check(program.info.buffers.size() == 1 && program.info.buffers[0].scalar, "scalar and vector uses of one descriptor were split"); Check(program.blocks[0].instructions[0].memory.resource == 0 && @@ -235,7 +235,7 @@ void TestBufferImageAliasIsLinkedDuringTracking() { ImageUse(12, Opcode::ImageLoad, ResourceKind::Image, Decoder::ImageDimension::Dim2D)}; - Prepare(&program); + Prepare(program); Check(program.info.buffers.size() == 2 && program.info.images.size() == 1 && program.info.buffers[0].image_alias == 0 && program.info.buffers[1].image_alias == BufferResource::NoImageAlias, @@ -265,7 +265,7 @@ void TestImagesAndSamplers() { program.blocks[0].instructions = {sample0, sample1, volume, compare, storage, storage_mip, atomic}; - Prepare(&program); + Prepare(program); Check(program.info.images.size() == 6 && program.info.samplers.size() == 1 && program.info.sampled_pairs.size() == 3, "image view classes or samplers were deduplicated incorrectly"); @@ -308,13 +308,13 @@ void TestDynamicPhiResource() { program.blocks[3].instructions = {BufferUse(8, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error), error.c_str()); const auto original_source = program.blocks[3].instructions[0].memory.resource_source; Check( - !TrackResources(&program, &error) && + !TrackResources(program, &error) && error.find("unsupported GPU selection") != std::string::npos && program.blocks[3].instructions[0].memory.resource_source == original_source && @@ -338,7 +338,7 @@ void TestTrackingRequiresCompletedSrtPlan() { program.blocks[3].instructions = {BufferUse(8, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); Check(!program.srt_plan_complete, "provenance unexpectedly marked the SRT plan complete"); const auto original_source = @@ -346,7 +346,7 @@ void TestTrackingRequiresCompletedSrtPlan() { BufferResource existing_info; existing_info.source = 777; program.info.buffers.push_back(existing_info); - Check(!TrackResources(&program, &error) && + Check(!TrackResources(program, &error) && error.find("SRT plan is not ready") != std::string::npos && program.blocks[3].instructions[0].memory.resource == 0 && program.blocks[3].instructions[0].memory.resource_source == @@ -372,10 +372,10 @@ void TestCyclicResourceIsRejected() { increment.src_count = 2; program.blocks[1].instructions = {BufferUse(4, 0), increment}; std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error), error.c_str()); - Check(!TrackResources(&program, &error) && + Check(!TrackResources(program, &error) && error.find("unsupported GPU selection") != std::string::npos && !program.resource_tracking_complete, "cyclic descriptor was patched without a bindless/direct path"); @@ -395,13 +395,13 @@ void TestUnknownSourceFailsWithoutPatching() { program.blocks[0].instructions = {valid, unsupported, BufferUse(0x44, 4)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error), error.c_str()); BufferResource existing_info; existing_info.source = 777; program.info.buffers.push_back(existing_info); - Check(!TrackResources(&program, &error), + Check(!TrackResources(program, &error), "unknown descriptor unexpectedly tracked"); Check(error.find("hash=0x0000000012345678") != std::string::npos && error.find("stage=pixel") != std::string::npos && @@ -430,11 +430,11 @@ void TestResourceLimitFailsTransactionally() { insts.push_back(BufferUse(i * 8 + 4, 0)); } std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error), error.c_str()); const auto first_source = insts[1].memory.resource_source; - Check(!TrackResources(&program, &error) && + Check(!TrackResources(program, &error) && error.find("buffer resource limit exceeded") != std::string::npos && insts[1].memory.resource_source == first_source && program.info.buffers.empty() && !program.resource_tracking_complete, @@ -448,7 +448,7 @@ void TestComputeShaderInfoCollection() { Instruction add_tid; add_tid.op = Opcode::DsReadAddtidB32; program.blocks[0].instructions = {add_tid, BufferUse(4, 0)}; - Prepare(&program); + Prepare(program); const auto buffers = program.info.buffers; const auto images = program.info.images; const auto samplers = program.info.samplers; @@ -458,7 +458,7 @@ void TestComputeShaderInfoCollection() { compute.group_id[1] = true; compute.dispatch_thread_dimensions = true; std::string error; - Check(CollectShaderInfo(&program, {.compute = &compute}, &error), + Check(CollectShaderInfo(program, {.compute = &compute}, &error), error.c_str()); Check(program.shader_info_complete && program.info.inputs.size() == 3 && FindInput(program.info, StageInputKind::WorkgroupId) != nullptr && @@ -473,10 +473,10 @@ void TestComputeShaderInfoCollection() { Program metadata_program; metadata_program.stage = ShaderType::Compute; metadata_program.blocks.resize(1); - Prepare(&metadata_program); + Prepare(metadata_program); compute = {}; compute.thread_ids_num = 2; - Check(CollectShaderInfo(&metadata_program, {.compute = &compute}, &error), + Check(CollectShaderInfo(metadata_program, {.compute = &compute}, &error), error.c_str()); Check(FindInput(metadata_program.info, StageInputKind::LocalInvocationId) != nullptr && @@ -499,12 +499,12 @@ void TestVertexShaderInfoCollection() { program.blocks[0].instructions = { attr0, attr2, Export(8, ExportTargetKind::Position), Export(12, ExportTargetKind::Parameter, 2)}; - Prepare(&program); + Prepare(program); ShaderVertexInputInfo vertex; vertex.resources_num = 3; std::string error; - Check(CollectShaderInfo(&program, {.vertex = &vertex}, &error), + Check(CollectShaderInfo(program, {.vertex = &vertex}, &error), error.c_str()); const auto *input0 = FindInput(program.info, StageInputKind::Parameter, 0); const auto *input2 = FindInput(program.info, StageInputKind::Parameter, 2); @@ -521,7 +521,7 @@ void TestVertexShaderInfoCollection() { const auto resources_complete = program.resource_tracking_complete; const auto srt_complete = program.srt_plan_complete; const auto patching_complete = program.srt_patching_complete; - Check(!CollectShaderInfo(&program, {.vertex = &vertex}, &error) && + Check(!CollectShaderInfo(program, {.vertex = &vertex}, &error) && error.find("already collected") != std::string::npos && program.info == info && program.shader_info_complete && program.resource_tracking_complete == resources_complete && @@ -539,7 +539,7 @@ void TestPixelShaderInfoCollection() { Export(8, ExportTargetKind::MrtZ, 0, 0x4), Export(12, ExportTargetKind::Mrt, 3), Export(16, ExportTargetKind::Mrt, 7, 0)}; - Prepare(&program); + Prepare(program); ShaderPixelInputInfo pixel; pixel.ps_pos_x = true; @@ -548,7 +548,7 @@ void TestPixelShaderInfoCollection() { pixel.ps_depth_export_enable = true; pixel.ps_sample_mask_export_enable = true; std::string error; - Check(CollectShaderInfo(&program, {.pixel = &pixel}, &error), + Check(CollectShaderInfo(program, {.pixel = &pixel}, &error), error.c_str()); Check(program.info.inputs.size() == 4 && FindInput(program.info, StageInputKind::FragCoord) != nullptr && @@ -567,8 +567,8 @@ void TestPixelShaderInfoCollection() { depth_program.blocks.resize(1); depth_program.blocks[0].instructions = { Export(4, ExportTargetKind::MrtZ, 0, 0x1)}; - Prepare(&depth_program); - Check(CollectShaderInfo(&depth_program, {.pixel = &pixel}, &error), + Prepare(depth_program); + Check(CollectShaderInfo(depth_program, {.pixel = &pixel}, &error), error.c_str()); Check(depth_program.info.outputs.size() == 1 && FindOutput(depth_program.info, StageOutputKind::Depth) != nullptr && @@ -585,16 +585,16 @@ void TestShaderInfoCollectionIsTransactional() { program.info.inputs.push_back(sentinel); const auto info = program.info; std::string error; - Check(!CollectShaderInfo(&program, {}, &error) && + Check(!CollectShaderInfo(program, {}, &error) && error.find("not tracked") != std::string::npos && program.info == info && !program.shader_info_complete, "pre-track shader info collection mutated program state"); - Prepare(&program); + Prepare(program); const auto tracked_info = program.info; const auto srt_complete = program.srt_plan_complete; const auto patching_complete = program.srt_patching_complete; - Check(!CollectShaderInfo(&program, {}, &error) && + Check(!CollectShaderInfo(program, {}, &error) && error.find("requires compute metadata") != std::string::npos && program.info == tracked_info && !program.shader_info_complete && program.resource_tracking_complete && @@ -602,7 +602,7 @@ void TestShaderInfoCollectionIsTransactional() { program.srt_patching_complete == patching_complete, "missing stage metadata committed incomplete shader info"); program.stage = ShaderType::Unknown; - Check(!CollectShaderInfo(&program, {}, &error) && + Check(!CollectShaderInfo(program, {}, &error) && error.find("unsupported shader stage") != std::string::npos && program.info == tracked_info && !program.shader_info_complete && program.resource_tracking_complete && @@ -622,17 +622,17 @@ void TestShaderInfoMetadataValidation() { bad_input.input_info.attr = 0; bad_input.input_info.chan = 4; vertex_program.blocks[0].instructions = {bad_input}; - Prepare(&vertex_program); + Prepare(vertex_program); ShaderVertexInputInfo vertex; vertex.resources_num = 1; const auto vertex_info = vertex_program.info; - Check(!CollectShaderInfo(&vertex_program, {.vertex = &vertex}, &error) && + Check(!CollectShaderInfo(vertex_program, {.vertex = &vertex}, &error) && error.find("vertex input reference") != std::string::npos && vertex_program.info == vertex_info && !vertex_program.shader_info_complete, "out-of-range vertex channel produced immutable malformed info"); vertex.resources_num = -1; - Check(!CollectShaderInfo(&vertex_program, {.vertex = &vertex}, &error) && + Check(!CollectShaderInfo(vertex_program, {.vertex = &vertex}, &error) && error.find("vertex resource count") != std::string::npos && vertex_program.info == vertex_info && !vertex_program.shader_info_complete, @@ -641,11 +641,11 @@ void TestShaderInfoMetadataValidation() { Program pixel_program; pixel_program.stage = ShaderType::Pixel; pixel_program.blocks.resize(1); - Prepare(&pixel_program); + Prepare(pixel_program); ShaderPixelInputInfo pixel; pixel.input_num = 33; const auto pixel_info = pixel_program.info; - Check(!CollectShaderInfo(&pixel_program, {.pixel = &pixel}, &error) && + Check(!CollectShaderInfo(pixel_program, {.pixel = &pixel}, &error) && error.find("pixel input count") != std::string::npos && pixel_program.info == pixel_info && !pixel_program.shader_info_complete, @@ -654,11 +654,11 @@ void TestShaderInfoMetadataValidation() { Program compute_program; compute_program.stage = ShaderType::Compute; compute_program.blocks.resize(1); - Prepare(&compute_program); + Prepare(compute_program); ShaderComputeInputInfo compute; compute.thread_ids_num = 4; const auto compute_info = compute_program.info; - Check(!CollectShaderInfo(&compute_program, {.compute = &compute}, &error) && + Check(!CollectShaderInfo(compute_program, {.compute = &compute}, &error) && error.find("thread ID count") != std::string::npos && compute_program.info == compute_info && !compute_program.shader_info_complete, @@ -670,16 +670,16 @@ void TestTrackingRequiresSrtPatching() { program.blocks.resize(1); program.blocks[0].instructions = {BufferUse(4, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error), error.c_str()); const auto source = program.blocks[0].instructions[0].memory.resource_source; - Check(!TrackResources(&program, &error) && + Check(!TrackResources(program, &error) && error.find("SRT reads were not patched") != std::string::npos && program.blocks[0].instructions[0].memory.resource_source == source && !program.resource_tracking_complete, "resource tracking bypassed SRT patch completion"); - Check(PatchSrtReads(&program, &error) && TrackResources(&program, &error), + Check(PatchSrtReads(program, &error) && TrackResources(program, &error), error.c_str()); } @@ -697,8 +697,8 @@ void TestDynamicSrtReadRemainsExplicit() { ResourceKind::StorageImage, Decoder::ImageDimension::Dim2D)); std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error), error.c_str()); Check(program.srt.reads.empty() && program.srt.dynamic_reads.size() == 8 && program.srt_patching_complete, @@ -708,7 +708,7 @@ void TestDynamicSrtReadRemainsExplicit() { insts[i].memory.kind == ResourceKind::ScalarBuffer, "dynamic SRT read was rewritten as an immediate flat load"); } - Check(TrackResources(&program, &error), error.c_str()); + Check(TrackResources(program, &error), error.c_str()); } void TestSrtPatchingFailureIsTransactional() { @@ -720,14 +720,14 @@ void TestSrtPatchingFailureIsTransactional() { } insts.push_back(BufferUse(0x20, 0)); std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && program.srt.reads.size() == 4, + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && program.srt.reads.size() == 4, error.c_str()); insts[0].scalar_value = ScalarProvenance::Undefined; const auto instructions = insts; const auto provenance = program.provenance; const auto srt = program.srt; - Check(!PatchSrtReads(&program, &error) && + Check(!PatchSrtReads(program, &error) && error.find("no scalar-load producer") != std::string::npos && insts == instructions && program.provenance == provenance && program.srt == srt && !program.srt_patching_complete, @@ -747,9 +747,9 @@ void TestScalarMemoryGroupsSnapshotOperands() { insts.push_back(BufferUse(8, 16)); std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && program.srt.reads.size() == 4 && - PatchSrtReads(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && program.srt.reads.size() == 4 && + PatchSrtReads(program, &error), error.c_str()); for (uint32_t i = 0; i < 4; i++) { Check(insts[i].op == Opcode::LoadSrtDword && insts[i].src[0].imm == i, @@ -774,10 +774,10 @@ void TestScalarMemoryGroupsSnapshotOperands() { insts.push_back(BufferUse(8, 20)); std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && program.srt.dynamic_reads.size() == 4 && - PatchSrtReads(&program, &error), + PatchSrtReads(program, &error), error.c_str()); for (uint32_t i = 0; i < 4; i++) { const auto value = insts[i].scalar_value; @@ -812,9 +812,9 @@ void TestSrtPatchingHandlesGvnAndMoveForwarding() { insts.push_back(BufferUse(0x64, 8)); std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && program.srt.reads.size() == 4 && - PatchSrtReads(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && program.srt.reads.size() == 4 && + PatchSrtReads(program, &error), error.c_str()); for (uint32_t i = 0; i < 8; i++) { Check(insts[i].op == Opcode::LoadSrtDword && @@ -845,9 +845,9 @@ void TestSrtPatchingHandlesCfgProducers() { program.blocks[3].instructions = {BufferUse(0x60, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && program.srt.reads.size() == 4 && - PatchSrtReads(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && program.srt.reads.size() == 4 && + PatchSrtReads(program, &error), error.c_str()); for (uint32_t block = 1; block <= 2; block++) { for (uint32_t i = 0; i < 4; i++) { @@ -867,12 +867,12 @@ void TestSrtPatchPlanValidation() { } insts.push_back(BufferUse(0x20, 0)); std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error), error.c_str()); program.srt.reads = {program.srt.reads[0], program.srt.reads[0]}; const auto instructions = insts; - Check(!PatchSrtReads(&program, &error) && + Check(!PatchSrtReads(program, &error) && error.find("dense value-to-offset bijection") != std::string::npos && insts == instructions && !program.srt_patching_complete, "duplicate SRT flat slots were accepted or partially patched"); @@ -880,11 +880,11 @@ void TestSrtPatchPlanValidation() { Program dynamic; dynamic.blocks.resize(1); dynamic.blocks[0].instructions = {BufferUse(4, 0)}; - Check(BuildScalarProvenance(&dynamic, &error) && - BuildSrtPlan(&dynamic, &error), + Check(BuildScalarProvenance(dynamic, &error) && + BuildSrtPlan(dynamic, &error), error.c_str()); dynamic.srt.dynamic_sources = {ScalarProvenance::Undefined}; - Check(!PatchSrtReads(&dynamic, &error) && + Check(!PatchSrtReads(dynamic, &error) && error.find("invalid dynamic descriptor source") != std::string::npos && !dynamic.srt_patching_complete, "undefined dynamic descriptor source was accepted"); @@ -907,7 +907,7 @@ void TestMaterializationSharesReadConstEvaluation() { insts.push_back(ImageUse(0x44, Opcode::ImageStore, ResourceKind::StorageImage, Decoder::ImageDimension::Dim2D)); - Prepare(&program); + Prepare(program); Check(program.info.images.size() == 2 && program.info.samplers.size() == 1, "materialization test did not preserve sampled/storage view topology"); Check(program.srt.reads.size() == 8 && program.srt_patching_complete, @@ -920,7 +920,7 @@ void TestMaterializationSharesReadConstEvaluation() { "immediate SRT read was not patched to its dense flat-buffer slot"); } std::string error; - Check(!PatchSrtReads(&program, &error) && + Check(!PatchSrtReads(program, &error) && error.find("already patched") != std::string::npos, "repeated SRT patching was accepted"); @@ -936,7 +936,7 @@ void TestMaterializationSharesReadConstEvaluation() { SrtRuntime runtime{user_data, 0, ReadTestMemory, &memory}; ResourceSnapshot snapshot; error.clear(); - Check(MaterializeResources(program, runtime, &snapshot, &error), + Check(MaterializeResources(program, runtime, snapshot, &error), error.c_str()); Check(snapshot.buffers.empty() && snapshot.images.size() == 2 && snapshot.samplers.size() == 1 && @@ -963,7 +963,7 @@ void TestInvalidImagesMaterializeAsNull() { sampled.blocks[0].instructions = { ImageUse(0x40, Opcode::ImageLoad, ResourceKind::Image, Decoder::ImageDimension::Dim2D)}; - Prepare(&sampled); + Prepare(sampled); Check(sampled.info.images.size() == 1 && sampled.info.samplers.empty(), "sampled-image normalization test has unexpected resource topology"); @@ -975,7 +975,7 @@ void TestInvalidImagesMaterializeAsNull() { auto descriptor = stale; descriptor[3] = (descriptor[3] & 0x0fffffffu) | (type << 28u); ResourceSnapshot snapshot; - Check(MaterializeResources(sampled, {descriptor}, &snapshot, &error) && + Check(MaterializeResources(sampled, {descriptor}, snapshot, &error) && snapshot.images.size() == 1 && std::all_of(snapshot.images[0].dwords.begin(), snapshot.images[0].dwords.end(), @@ -988,7 +988,7 @@ void TestInvalidImagesMaterializeAsNull() { valid[3] = (valid[3] & 0x0fffffffu) | (Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) << 28u); ResourceSnapshot valid_snapshot; - Check(MaterializeResources(sampled, {valid}, &valid_snapshot, &error) && + Check(MaterializeResources(sampled, {valid}, valid_snapshot, &error) && std::equal(valid.begin(), valid.end(), valid_snapshot.images[0].dwords.begin()), "valid sampled image descriptor was normalized"); @@ -1000,9 +1000,9 @@ void TestInvalidImagesMaterializeAsNull() { storage.blocks[0].instructions = { ImageUse(0x40, Opcode::ImageStore, ResourceKind::StorageImage, Decoder::ImageDimension::Dim2D)}; - Prepare(&storage); + Prepare(storage); ResourceSnapshot storage_snapshot; - Check(MaterializeResources(storage, {stale}, &storage_snapshot, &error) && + Check(MaterializeResources(storage, {stale}, storage_snapshot, &error) && std::all_of(storage_snapshot.images[0].dwords.begin(), storage_snapshot.images[0].dwords.end(), [](uint32_t word) { return word == 0; }), @@ -1019,7 +1019,7 @@ void TestMaterializationFailureIsTransactional() { insts.push_back(ImageUse(0x40, Opcode::ImageStore, ResourceKind::StorageImage, Decoder::ImageDimension::Dim2D)); - Prepare(&program); + Prepare(program); TestMemory memory; memory.fail_after = 3; @@ -1033,7 +1033,7 @@ void TestMaterializationFailureIsTransactional() { sentinel.dwords[0] = 777; snapshot.images.push_back(sentinel); std::string error; - Check(!MaterializeResources(program, runtime, &snapshot, &error) && + Check(!MaterializeResources(program, runtime, snapshot, &error) && error.find("failed at") != std::string::npos && snapshot.images.size() == 1 && snapshot.images[0].dwords[0] == 777 && @@ -1048,7 +1048,7 @@ void TestResourceSpecializationIsTypedAndTransactional() { null_program.blocks[0].instructions = { ImageUse(0x10, Opcode::ImageLoad, ResourceKind::Image, Decoder::ImageDimension::Dim3D)}; - Prepare(&null_program); + Prepare(null_program); ResourceSnapshot null_snapshot; null_snapshot.images.resize(1); null_snapshot.images[0].dword_count = 8; @@ -1056,7 +1056,7 @@ void TestResourceSpecializationIsTypedAndTransactional() { null_snapshot.images[0].dwords[2] = 0x89abcdefu; null_snapshot.images[0].dwords[3] = 0x01234567u; std::string error; - Check(SpecializeResources(&null_program, null_snapshot, &error) && + Check(SpecializeResources(null_program, null_snapshot, &error) && ValidateResourceSpecialization(null_program, null_snapshot, &error) && null_program.info.images[0].kind == ResourceKind::Image && null_program.info.images[0].dimension == Decoder::ImageDimension::Dim3D, @@ -1068,7 +1068,7 @@ void TestResourceSpecializationIsTypedAndTransactional() { program.blocks[0].instructions = { ImageUse(0x20, Opcode::ImageStore, ResourceKind::StorageImage, Decoder::ImageDimension::Dim3D)}; - Prepare(&program); + Prepare(program); ResourceSnapshot snapshot; snapshot.images.resize(1); @@ -1079,7 +1079,7 @@ void TestResourceSpecializationIsTypedAndTransactional() { Check(!ValidateResourceSnapshot(program, snapshot, &error) && error.find("image descriptor 0 has 7 dwords") != std::string::npos, "malformed resource snapshot was accepted"); - Check(!SpecializeResources(&program, snapshot, &error) && + Check(!SpecializeResources(program, snapshot, &error) && program.info == info && program.blocks[0].instructions[0].memory == memory, "failed resource specialization partially mutated the program"); @@ -1090,7 +1090,7 @@ void TestResourceSpecializationIsTypedAndTransactional() { Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) << 20u; snapshot.images[0].dwords[3] = (Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) << 28u) | 0x3acu; - Check(SpecializeResources(&program, snapshot, &error), error.c_str()); + Check(SpecializeResources(program, snapshot, &error), error.c_str()); const auto &image = program.info.images[0]; const auto &inst = program.blocks[0].instructions[0]; Check(image.kind == ResourceKind::StorageImageUint && @@ -1110,8 +1110,8 @@ void TestResourceSpecializationIsTypedAndTransactional() { ShaderComputeInputInfo compute; compute.thread_ids_num = 1; - Check(CollectShaderInfo(&program, {.compute = &compute}, &error) && - AllocateBindings(&program, {}, &error), + Check(CollectShaderInfo(program, {.compute = &compute}, &error) && + AllocateBindings(program, {}, &error), error.c_str()); const auto *binding = FindBinding(program.bindings, DescriptorBindingKind::StorageUint2D); @@ -1125,7 +1125,7 @@ void TestRuntimeSpecializationCoversBakedBufferAndAddressFields() { buffer_program.stage = ShaderType::Compute; buffer_program.blocks.resize(1); buffer_program.blocks[0].instructions = {BufferUse(0, 0)}; - Prepare(&buffer_program); + Prepare(buffer_program); ResourceSnapshot buffer_snapshot; buffer_snapshot.buffers.resize(1); @@ -1135,7 +1135,7 @@ void TestRuntimeSpecializationCoversBakedBufferAndAddressFields() { (Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) << 12u) | (2u << 21u) | (1u << 23u); std::string error; - Check(SpecializeResources(&buffer_program, buffer_snapshot, &error) && + Check(SpecializeResources(buffer_program, buffer_snapshot, &error) && ValidateResourceSpecialization(buffer_program, buffer_snapshot, &error), error.c_str()); Check(buffer_program.info.buffers[0].packed_stride == @@ -1151,8 +1151,8 @@ void TestRuntimeSpecializationCoversBakedBufferAndAddressFields() { ShaderComputeInputInfo compute; compute.thread_ids_num = 1; - Check(CollectShaderInfo(&buffer_program, {.compute = &compute}, &error) && - AllocateBindings(&buffer_program, {}, &error), + Check(CollectShaderInfo(buffer_program, {.compute = &compute}, &error) && + AllocateBindings(buffer_program, {}, &error), error.c_str()); Check(buffer_program.bindings.user_data_registers == std::vector({0, 1, 2, 3}), @@ -1175,10 +1175,10 @@ void TestRuntimeSpecializationCoversBakedBufferAndAddressFields() { raw.src_count = 1; based_program.blocks[0].instructions = { MoveImmediate(0, 16, 0x1000), MoveImmediate(4, 17, 0), raw}; - Prepare(&based_program); + Prepare(based_program); ResourceSnapshot based_snapshot; - Check(MaterializeResources(based_program, {}, &based_snapshot, &error) && - SpecializeResources(&based_program, based_snapshot, &error), + Check(MaterializeResources(based_program, {}, based_snapshot, &error) && + SpecializeResources(based_program, based_snapshot, &error), error.c_str()); auto relocated = based_snapshot; relocated.addresses[0].guest_base += 0x1000; @@ -1197,20 +1197,20 @@ void TestRuntimeSpecializationCoversBakedBufferAndAddressFields() { flat.op = Opcode::FlatLoadDword; flat.memory.kind = ResourceKind::Flat; flat_program.blocks[0].instructions = {flat}; - Prepare(&flat_program); + Prepare(flat_program); ResourceSnapshot flat_snapshot; flat_snapshot.addresses = {{0x11u, 0x10u}}; flat_snapshot.user_data = {0xdeadbeefu}; const auto prior_flat_snapshot = flat_snapshot; - Check(!MaterializeResources(flat_program, {}, &flat_snapshot, &error) && + Check(!MaterializeResources(flat_program, {}, flat_snapshot, &error) && error.find("requires runtime guest-address translation") != std::string::npos && flat_snapshot.addresses == prior_flat_snapshot.addresses && flat_snapshot.user_data == prior_flat_snapshot.user_data, "unbased flat memory without a translator did not fail transactionally"); SrtRuntime flat_runtime; flat_runtime.flat_memory_base = 0x100000000ull; - Check(MaterializeResources(flat_program, flat_runtime, &flat_snapshot, &error) && - SpecializeResources(&flat_program, flat_snapshot, &error), + Check(MaterializeResources(flat_program, flat_runtime, flat_snapshot, &error) && + SpecializeResources(flat_program, flat_snapshot, &error), error.c_str()); auto stale_flat = flat_snapshot; stale_flat.addresses[0].guest_base += 0x1000; @@ -1236,7 +1236,7 @@ void TestTrackedProgramIsImmutable() { ResourceKind::StorageImage, Decoder::ImageDimension::Dim2D)); insts.push_back(BufferUse(0x58, 12)); - Prepare(&program); + Prepare(program); Check(program.info.buffers.size() == 1 && program.info.images.size() == 2 && program.info.samplers.size() == 1 && program.info.sampled_pairs.size() == 1, @@ -1269,11 +1269,11 @@ void TestTrackedProgramIsImmutable() { }; std::string error; - Check(!BuildScalarProvenance(&program, &error) && + Check(!BuildScalarProvenance(program, &error) && error.find("after resource tracking") != std::string::npos, "post-track provenance rebuild was accepted"); CheckUnchanged(); - Check(!BuildSrtPlan(&program, &error) && + Check(!BuildSrtPlan(program, &error) && error.find("after resource tracking") != std::string::npos, "post-track SRT rebuild was accepted"); CheckUnchanged(); @@ -1295,13 +1295,13 @@ void TestNativeBindingLayout() { insts.push_back(ImageUse(20, Opcode::ImageStore, ResourceKind::StorageImageUint, Decoder::ImageDimension::Dim2DArray, 6)); - Prepare(&program); + Prepare(program); ShaderComputeInputInfo compute; compute.thread_ids_num = 1; std::string error; - Check(CollectShaderInfo(&program, {.compute = &compute}, &error) && - AllocateBindings(&program, {.descriptor_set = 3}, &error), + Check(CollectShaderInfo(program, {.compute = &compute}, &error) && + AllocateBindings(program, {.descriptor_set = 3}, &error), error.c_str()); const auto *buffers = FindBinding(program.bindings, DescriptorBindingKind::Buffers); @@ -1345,12 +1345,12 @@ void TestNativeBindingLayoutSrtAndUserDataOverflow() { ScalarLoad(i * 4, i, 16, i * 4)); } srt.blocks[0].instructions.push_back(BufferUse(0x20, 0)); - Prepare(&srt); + Prepare(srt); ShaderComputeInputInfo compute; compute.thread_ids_num = 1; std::string error; - Check(CollectShaderInfo(&srt, {.compute = &compute}, &error) && - AllocateBindings(&srt, {}, &error), + Check(CollectShaderInfo(srt, {.compute = &compute}, &error) && + AllocateBindings(srt, {}, &error), error.c_str()); const auto *flat = FindBinding(srt.bindings, DescriptorBindingKind::FlattenedSrt); @@ -1370,11 +1370,11 @@ void TestNativeBindingLayoutSrtAndUserDataOverflow() { direct.src_count = 1; overflow.blocks[0].instructions.push_back(direct); } - Check(BuildScalarProvenance(&overflow, &error) && - BuildSrtPlan(&overflow, &error) && PatchSrtReads(&overflow, &error) && - TrackResources(&overflow, &error) && - CollectShaderInfo(&overflow, {.compute = &compute}, &error) && - AllocateBindings(&overflow, {}, &error), + Check(BuildScalarProvenance(overflow, &error) && + BuildSrtPlan(overflow, &error) && PatchSrtReads(overflow, &error) && + TrackResources(overflow, &error) && + CollectShaderInfo(overflow, {.compute = &compute}, &error) && + AllocateBindings(overflow, {}, &error), error.c_str()); const auto *user_data = FindBinding(overflow.bindings, DescriptorBindingKind::UserData); @@ -1397,11 +1397,11 @@ void TestNativeBindingLayoutGds() { ShaderComputeInputInfo compute; std::string error; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error) && - TrackResources(&program, &error) && - CollectShaderInfo(&program, {.compute = &compute}, &error) && - AllocateBindings(&program, {}, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error) && + TrackResources(program, &error) && + CollectShaderInfo(program, {.compute = &compute}, &error) && + AllocateBindings(program, {}, &error), error.c_str()); const auto *gds = FindBinding(program.bindings, DescriptorBindingKind::Gds); Check(gds != nullptr && gds->binding == 0 && gds->resources.empty(), @@ -1412,10 +1412,10 @@ void TestNativeBindingLayoutGds() { lds.blocks.resize(1); append.memory.kind = ResourceKind::Lds; lds.blocks[0].instructions.push_back(append); - Check(BuildScalarProvenance(&lds, &error) && BuildSrtPlan(&lds, &error) && - PatchSrtReads(&lds, &error) && TrackResources(&lds, &error) && - CollectShaderInfo(&lds, {.compute = &compute}, &error) && - AllocateBindings(&lds, {}, &error), + Check(BuildScalarProvenance(lds, &error) && BuildSrtPlan(lds, &error) && + PatchSrtReads(lds, &error) && TrackResources(lds, &error) && + CollectShaderInfo(lds, {.compute = &compute}, &error) && + AllocateBindings(lds, {}, &error), error.c_str()); Check(FindBinding(lds.bindings, DescriptorBindingKind::Gds) == nullptr, "LDS append/consume incorrectly allocated a GDS binding"); @@ -1428,25 +1428,25 @@ void TestNativeBindingLayoutIsTransactional() { std::string error; ShaderComputeInputInfo compute; compute.thread_ids_num = 1; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error) && - TrackResources(&program, &error) && - CollectShaderInfo(&program, {.compute = &compute}, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error) && + TrackResources(program, &error) && + CollectShaderInfo(program, {.compute = &compute}, &error), error.c_str()); BindingLayout sentinel; sentinel.descriptor_set = 99; program.bindings = sentinel; - Check(!AllocateBindings(&program, {.push_constant_offset = 129}, &error) && + Check(!AllocateBindings(program, {.push_constant_offset = 129}, &error) && error.find("Vulkan minimum") != std::string::npos && program.bindings == sentinel && !program.binding_layout_complete, "failed native binding allocation partially changed the program"); - Check(!AllocateBindings(&program, {.push_constant_offset = 2}, &error) && + Check(!AllocateBindings(program, {.push_constant_offset = 2}, &error) && error.find("dword aligned") != std::string::npos && program.bindings == sentinel && !program.binding_layout_complete, "misaligned push-constant allocation partially changed the program"); - Check(AllocateBindings(&program, {}, &error), error.c_str()); + Check(AllocateBindings(program, {}, &error), error.c_str()); const auto layout = program.bindings; - Check(!AllocateBindings(&program, {}, &error) && + Check(!AllocateBindings(program, {}, &error) && error.find("already allocated") != std::string::npos && program.bindings == layout, "repeated native binding allocation was accepted or mutated layout"); @@ -1461,10 +1461,10 @@ void TestNativeBindingLayoutIsTransactional() { direct.src[0] = Sgpr(0); direct.src_count = 1; tail.blocks[0].instructions = {direct}; - Check(BuildScalarProvenance(&tail, &error) && BuildSrtPlan(&tail, &error) && - PatchSrtReads(&tail, &error) && TrackResources(&tail, &error) && - CollectShaderInfo(&tail, {.compute = &compute}, &error) && - AllocateBindings(&tail, {.push_constant_offset = 124}, &error) && + Check(BuildScalarProvenance(tail, &error) && BuildSrtPlan(tail, &error) && + PatchSrtReads(tail, &error) && TrackResources(tail, &error) && + CollectShaderInfo(tail, {.compute = &compute}, &error) && + AllocateBindings(tail, {.push_constant_offset = 124}, &error) && tail.bindings.push_constant_size == 4 && FindBinding(tail.bindings, DescriptorBindingKind::UserData) == nullptr, "valid final dword of the guaranteed push-constant range was rejected"); @@ -1499,20 +1499,20 @@ void TestNativeBindingLayoutTracksReachingUserData() { std::string error; ShaderComputeInputInfo compute; compute.thread_ids_num = 1; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error) && - TrackResources(&program, &error) && - CollectShaderInfo(&program, {.compute = &compute}, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error) && + TrackResources(program, &error) && + CollectShaderInfo(program, {.compute = &compute}, &error), error.c_str()); auto fallback = program; - Check(AllocateBindings(&program, {}, &error) && + Check(AllocateBindings(program, {}, &error) && program.bindings.user_data_registers == std::vector({4, 20}) && program.bindings.push_constant_size == 8 && FindBinding(program.bindings, DescriptorBindingKind::UserData) == nullptr, "native user-data map included a temporary or missed sparse roots"); - Check(AllocateBindings(&fallback, {.max_push_dwords = 1}, &error) && + Check(AllocateBindings(fallback, {.max_push_dwords = 1}, &error) && fallback.bindings.user_data_registers == std::vector({4, 20}) && fallback.bindings.push_constant_size == 0 && @@ -1532,13 +1532,13 @@ void TestNativeBindingLayoutRejectsUnknownShapeAndBadProvenance() { image.blocks[0].instructions = { ImageUse(4, Opcode::ImageStore, ResourceKind::StorageImage, Decoder::ImageDimension::Dim2D)}; - Prepare(&image); - Check(CollectShaderInfo(&image, {.compute = &compute}, &error), + Prepare(image); + Check(CollectShaderInfo(image, {.compute = &compute}, &error), error.c_str()); image.info.images[0].dimension = Decoder::ImageDimension::Unknown; image.bindings.descriptor_set = 77; const auto image_layout = image.bindings; - Check(!AllocateBindings(&image, {}, &error) && + Check(!AllocateBindings(image, {}, &error) && error.find("invalid image binding class") != std::string::npos && image.bindings == image_layout && !image.binding_layout_complete, "unknown image shape was defaulted or partially allocated"); @@ -1553,17 +1553,17 @@ void TestNativeBindingLayoutRejectsUnknownShapeAndBadProvenance() { direct.src[0] = Sgpr(4); direct.src_count = 1; provenance.blocks[0].instructions = {direct}; - Check(BuildScalarProvenance(&provenance, &error) && - BuildSrtPlan(&provenance, &error) && - PatchSrtReads(&provenance, &error) && - TrackResources(&provenance, &error) && - CollectShaderInfo(&provenance, {.compute = &compute}, &error), + Check(BuildScalarProvenance(provenance, &error) && + BuildSrtPlan(provenance, &error) && + PatchSrtReads(provenance, &error) && + TrackResources(provenance, &error) && + CollectShaderInfo(provenance, {.compute = &compute}, &error), error.c_str()); provenance.blocks[0].instructions[0].scalar_sources[0] = static_cast(provenance.provenance.values.size() + 1); provenance.bindings.descriptor_set = 88; const auto provenance_layout = provenance.bindings; - Check(!AllocateBindings(&provenance, {}, &error) && + Check(!AllocateBindings(provenance, {}, &error) && error.find("invalid scalar provenance reference") != std::string::npos && provenance.bindings == provenance_layout && @@ -1582,13 +1582,13 @@ void TestNativeBindingLayoutDynamicSrtDoesNotUseFlatBinding() { program.blocks[0].instructions.push_back(load); } program.blocks[0].instructions.push_back(BufferUse(0x20, 0)); - Prepare(&program); + Prepare(program); ShaderComputeInputInfo compute; compute.thread_ids_num = 1; std::string error; Check(program.srt.reads.empty() && program.srt.dynamic_reads.size() == 4 && - CollectShaderInfo(&program, {.compute = &compute}, &error) && - AllocateBindings(&program, {}, &error), + CollectShaderInfo(program, {.compute = &compute}, &error) && + AllocateBindings(program, {}, &error), error.c_str()); Check(program.bindings.user_data_registers == std::vector({16, 17, 20}) && @@ -1616,12 +1616,12 @@ void TestNativeBindingLayoutTracksRawScalarMemoryBase() { std::string error; ShaderComputeInputInfo compute; compute.thread_ids_num = 1; - Check(BuildScalarProvenance(&program, &error) && - BuildSrtPlan(&program, &error) && program.srt.reads.empty() && - program.srt.dynamic_reads.empty() && PatchSrtReads(&program, &error) && - TrackResources(&program, &error) && - CollectShaderInfo(&program, {.compute = &compute}, &error) && - AllocateBindings(&program, {}, &error), + Check(BuildScalarProvenance(program, &error) && + BuildSrtPlan(program, &error) && program.srt.reads.empty() && + program.srt.dynamic_reads.empty() && PatchSrtReads(program, &error) && + TrackResources(program, &error) && + CollectShaderInfo(program, {.compute = &compute}, &error) && + AllocateBindings(program, {}, &error), error.c_str()); const auto *address_memory = FindBinding(program.bindings, DescriptorBindingKind::AddressMemory); @@ -1653,8 +1653,8 @@ void TestRawScalarMemoryTracksReachingBaseIdentity() { MoveImmediate(12, 16, 0x2000), MoveImmediate(16, 17, 0), second}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error) && - PatchSrtReads(&program, &error) && TrackResources(&program, &error), + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error) && + PatchSrtReads(program, &error) && TrackResources(program, &error), error.c_str()); Check(program.info.addresses.size() == 2 && program.info.addresses[0].source != program.info.addresses[1].source && @@ -1665,7 +1665,7 @@ void TestRawScalarMemoryTracksReachingBaseIdentity() { std::array user_data{}; user_data[20] = 4; ResourceSnapshot snapshot; - Check(MaterializeResources(program, {user_data}, &snapshot, &error), error.c_str()); + Check(MaterializeResources(program, {user_data}, snapshot, &error), error.c_str()); Check(snapshot.addresses.size() == 2 && snapshot.addresses[0].guest_base == 0x1000 && snapshot.addresses[0].binding_base == 0x0ffc && @@ -1682,13 +1682,13 @@ void TestNativeBindingLayoutUsesExplicitFlatMemory() { load.op = Opcode::FlatLoadDword; load.memory.kind = ResourceKind::Flat; program.blocks[0].instructions = {load}; - Prepare(&program); + Prepare(program); ShaderComputeInputInfo compute; compute.thread_ids_num = 1; std::string error; - Check(CollectShaderInfo(&program, {.compute = &compute}, &error) && - AllocateBindings(&program, {}, &error), + Check(CollectShaderInfo(program, {.compute = &compute}, &error) && + AllocateBindings(program, {}, &error), error.c_str()); const auto *flat = FindBinding(program.bindings, DescriptorBindingKind::AddressMemory); @@ -1701,7 +1701,7 @@ void TestNativeBindingLayoutUsesExplicitFlatMemory() { ResourceSnapshot snapshot; SrtRuntime runtime; runtime.flat_memory_base = 0x1234567887654000ull; - Check(MaterializeResources(program, runtime, &snapshot, &error) && + Check(MaterializeResources(program, runtime, snapshot, &error) && snapshot.addresses.size() == 1 && snapshot.addresses[0].guest_base == 0x1234567887654000ull && snapshot.addresses[0].binding_base == 0x1234567887654000ull, @@ -1726,23 +1726,23 @@ void TestNativeBindingLayoutHonorsUserDataCount() { std::string error; ShaderComputeInputInfo compute; compute.thread_ids_num = 1; - Check(BuildScalarProvenance(&program, &error) && + Check(BuildScalarProvenance(program, &error) && program.provenance.values[program.blocks[0].instructions[0] .scalar_sources[0]] .op == ScalarValueOp::UserData && program.blocks[0].instructions[1].scalar_sources[0] == ScalarProvenance::Unknown && - BuildSrtPlan(&program, &error) && PatchSrtReads(&program, &error) && - TrackResources(&program, &error) && - CollectShaderInfo(&program, {.compute = &compute}, &error) && - AllocateBindings(&program, {}, &error) && + BuildSrtPlan(program, &error) && PatchSrtReads(program, &error) && + TrackResources(program, &error) && + CollectShaderInfo(program, {.compute = &compute}, &error) && + AllocateBindings(program, {}, &error) && program.bindings.user_data_registers == std::vector({7}), "stage user-data count did not bound provenance roots"); Program invalid; invalid.user_data_count = 65; invalid.blocks.resize(1); - Check(!BuildScalarProvenance(&invalid, &error) && + Check(!BuildScalarProvenance(invalid, &error) && error.find("exceeds 64") != std::string::npos, "out-of-range stage user-data count was accepted"); } @@ -1758,7 +1758,7 @@ void TestNativeBindingLayoutHonorsUserDataBase() { BufferUse(16, 8)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && + Check(BuildScalarProvenance(program, &error) && program.blocks[0].instructions[0].scalar_sources[0] == ScalarProvenance::Unknown && program.provenance.values[ @@ -1766,7 +1766,7 @@ void TestNativeBindingLayoutHonorsUserDataBase() { ScalarValueOp::UserData && program.blocks[0].instructions[3].scalar_sources[0] == ScalarProvenance::Unknown && - BuildSrtPlan(&program, &error), + BuildSrtPlan(program, &error), error.c_str()); const std::array user_data = { @@ -1774,15 +1774,15 @@ void TestNativeBindingLayoutHonorsUserDataBase() { 0, 0, 0, 0xaaaaaaaa}; DescriptorValue descriptor; const auto source = program.blocks[0].instructions.back().memory.resource_source; - Check(EvaluateDescriptorSource(program, source, 16, {user_data}, &descriptor, &error) && + Check(EvaluateDescriptorSource(program, source, 16, {user_data}, descriptor, &error) && descriptor.dwords[0] == user_data[0] && descriptor.dwords[3] == user_data[3], "vertex user-data base was not translated to runtime-local indices"); ShaderVertexInputInfo vertex; - Check(PatchSrtReads(&program, &error) && TrackResources(&program, &error) && - CollectShaderInfo(&program, {.vertex = &vertex}, &error) && - AllocateBindings(&program, {}, &error), + Check(PatchSrtReads(program, &error) && TrackResources(program, &error) && + CollectShaderInfo(program, {.vertex = &vertex}, &error) && + AllocateBindings(program, {}, &error), error.c_str()); Check(program.bindings.user_data_registers == std::vector({8, 9, 10, 11, 15}), diff --git a/tests/ScalarProvenanceTests.cpp b/tests/ScalarProvenanceTests.cpp index 944646e6b..3d802064f 100644 --- a/tests/ScalarProvenanceTests.cpp +++ b/tests/ScalarProvenanceTests.cpp @@ -141,7 +141,7 @@ void TestPerUseDescriptorDefinitions() { instructions.push_back(BufferUse(20, 0)); std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto* before = GetDescriptorSource(program, instructions[0].memory.resource_source); const auto* after = GetDescriptorSource(program, instructions[5].memory.resource_source); Check(before != nullptr && after != nullptr, "descriptor sources were not attached"); @@ -170,7 +170,7 @@ void TestCfgPhi() { program.blocks[3].instructions.push_back(BufferUse(12, 0)); std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto* source = GetDescriptorSource(program, program.blocks[3].instructions[0].memory.resource_source); Check(source != nullptr, "merged descriptor source was not attached"); @@ -180,7 +180,7 @@ void TestCfgPhi() { Check(Value(program, phi.phi_args[0]).op == ScalarValueOp::Constant && Value(program, phi.phi_args[1]).op == ScalarValueOp::Constant, "provenance phi does not reference both constant definitions"); - Check(BuildSrtPlan(&program, &error) && program.srt.dynamic_sources.size() == 1 && + Check(BuildSrtPlan(program, &error) && program.srt.dynamic_sources.size() == 1 && program.srt.dynamic_sources[0] == program.blocks[3].instructions[0].memory.resource_source, "acyclic control-flow descriptor phi was not classified dynamic"); @@ -213,7 +213,7 @@ void TestDiamondReadPathsAreDynamic() { program.blocks[3].instructions = {BufferUse(12, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); const auto source = program.blocks[3].instructions[0].memory.resource_source; Check(program.srt.reads.empty() && program.srt.dynamic_reads.empty() && program.srt.dynamic_sources.size() == 1 && program.srt.dynamic_sources[0] == source, @@ -228,7 +228,7 @@ void TestDiamondReadPathsAreDynamic() { ReadCounter counter; DescriptorValue descriptor; const SrtRuntime runtime {user_data, 0, CountedHostMemory, &counter}; - Check(!EvaluateDescriptorSource(program, source, 12, runtime, &descriptor, &error) && + Check(!EvaluateDescriptorSource(program, source, 12, runtime, descriptor, &error) && counter.reads == 0 && error.find("GPU-dynamic") != std::string::npos, "dynamic descriptor evaluation touched an inactive read path"); } @@ -253,14 +253,14 @@ void TestEquivalentConstantPhiIsStatic() { program.blocks[3].instructions = {BufferUse(12, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); const auto source = program.blocks[3].instructions[0].memory.resource_source; Check(program.srt.dynamic_sources.empty(), "equivalent constant phi was unnecessarily classified dynamic"); const std::array user_data = {}; DescriptorValue descriptor; const SrtRuntime runtime {user_data, 0, nullptr, nullptr}; - Check(EvaluateDescriptorSource(program, source, 12, runtime, &descriptor, &error) && + Check(EvaluateDescriptorSource(program, source, 12, runtime, descriptor, &error) && descriptor.dwords[0] == 2, "equivalent constant phi did not evaluate as one static value"); } @@ -274,7 +274,7 @@ void TestWideMoveInvalidatesAndCopiesBothDwords() { instructions.push_back(BufferUse(8, 0)); std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto* source = GetDescriptorSource(program, instructions.back().memory.resource_source); Check(source != nullptr && DescriptorSourceResolved(program, instructions.back().memory.resource_source), @@ -308,7 +308,7 @@ void TestScalarCarryChain() { program.blocks[0].instructions = {low, high, BufferUse(8, 4)}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto* source = GetDescriptorSource(program, program.blocks[0].instructions.back().memory.resource_source); Check(source != nullptr, "carry-chain descriptor source was not attached"); @@ -336,7 +336,7 @@ void TestReadConstDefinition() { program.blocks[0].instructions.push_back(BufferUse(8, 16)); std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto* source = GetDescriptorSource(program, program.blocks[0].instructions[1].memory.resource_source); Check(source != nullptr, "read-constant descriptor source was not attached"); @@ -369,7 +369,7 @@ void TestReadConstBufferAndValueNumbering() { program.blocks[0].instructions.push_back(BufferUse(8, 16)); std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto* source = GetDescriptorSource(program, program.blocks[0].instructions.back().memory.resource_source); Check(source != nullptr, "ReadConstBuffer source was not attached"); @@ -419,7 +419,7 @@ void TestReadLaneDescriptorSpill() { program.blocks[0].instructions.push_back(sample); std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); const auto source_id = program.blocks[0].instructions.back().memory.resource_source; const auto* source = GetDescriptorSource(program, source_id); Check(source != nullptr && DescriptorSourceResolved(program, source_id), @@ -431,7 +431,7 @@ void TestReadLaneDescriptorSpill() { user_data[26] = sizeof(table); DescriptorValue descriptor; const SrtRuntime runtime {user_data, 0, ReadHostMemory, nullptr}; - Check(EvaluateDescriptorSource(program, source_id, sample.pc, runtime, &descriptor, &error), + Check(EvaluateDescriptorSource(program, source_id, sample.pc, runtime, descriptor, &error), error.c_str()); Check(descriptor.dwords[0] == table[72], "readlane descriptor spill evaluated the overwritten scalar value"); @@ -452,7 +452,7 @@ void TestReadLaneVectorOverwriteInvalidatesSpill() { ReadLane(8, 0, 11, 0), BufferUse(12, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto source = program.blocks[0].instructions.back().memory.resource_source; Check(GetDescriptorSource(program, source) != nullptr && !DescriptorSourceResolved(program, source), @@ -475,7 +475,7 @@ void TestReadLanePhi() { program.blocks[3].instructions = {ReadLane(8, 0, 11, 0), BufferUse(12, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto* source = GetDescriptorSource(program, program.blocks[3].instructions.back().memory.resource_source); Check(source != nullptr && Value(program, source->dwords[0]).op == ScalarValueOp::Phi && @@ -498,7 +498,7 @@ void TestReadLaneLoopConvergence() { program.blocks[1].instructions = {ReadLane(4, 0, 11, 0), BufferUse(8, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto source = program.blocks[1].instructions.back().memory.resource_source; Check(DescriptorSourceResolved(program, source), "unchanged writelane spill did not converge across a loop backedge"); @@ -520,7 +520,7 @@ void TestReadLaneWideAndRelativeWritesInvalidateSpill() { ReadLane(8, 0, 12, 0), BufferUse(12, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto source = program.blocks[0].instructions.back().memory.resource_source; Check(!DescriptorSourceResolved(program, source), message); }; @@ -539,7 +539,7 @@ void TestReadLaneModuloAndDynamicLane() { modulo.blocks[0].instructions = {WriteLane(0, 11, 4, 33), ReadLane(4, 0, 11, 65), BufferUse(8, 0)}; std::string error; - Check(BuildScalarProvenance(&modulo, &error), error.c_str()); + Check(BuildScalarProvenance(modulo, &error), error.c_str()); const auto* modulo_source = GetDescriptorSource(modulo, modulo.blocks[0].instructions.back().memory.resource_source); Check(modulo_source != nullptr && @@ -554,7 +554,7 @@ void TestReadLaneModuloAndDynamicLane() { auto write = WriteLane(0, 11, 4, 0); write.src[1] = Sgpr(7); dynamic.blocks[0].instructions = {write, ReadLane(4, 0, 11, 0), BufferUse(8, 0)}; - Check(BuildScalarProvenance(&dynamic, &error), error.c_str()); + Check(BuildScalarProvenance(dynamic, &error), error.c_str()); Check(!DescriptorSourceResolved( dynamic, dynamic.blocks[0].instructions.back().memory.resource_source), "dynamic writelane selector retained unsafe lane provenance"); @@ -569,7 +569,7 @@ void TestUnresolvedSourceIsMarked() { program.blocks[0].instructions = {unknown, BufferUse(4, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto source = program.blocks[0].instructions.back().memory.resource_source; Check(GetDescriptorSource(program, source) != nullptr && !DescriptorSourceResolved(program, source), @@ -588,7 +588,7 @@ void TestUnsupportedWideWriteInvalidatesBothDwords() { BufferUse(12, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto* source = GetDescriptorSource(program, program.blocks[0].instructions.back().memory.resource_source); Check(source != nullptr && source->dwords[0] == ScalarProvenance::Unknown && @@ -611,12 +611,12 @@ void TestCyclicPhiIsUnresolved() { program.blocks[1].instructions = {BufferUse(4, 0), increment}; std::string error; - Check(BuildScalarProvenance(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error), error.c_str()); const auto source = program.blocks[1].instructions[0].memory.resource_source; Check(GetDescriptorSource(program, source) != nullptr && !DescriptorSourceResolved(program, source), "loop-carried cyclic descriptor provenance was incorrectly resolved"); - Check(BuildSrtPlan(&program, &error) && program.srt.dynamic_sources.size() == 1 && + Check(BuildSrtPlan(program, &error) && program.srt.dynamic_sources.size() == 1 && program.srt.dynamic_sources[0] == source, "SRT planning did not isolate a cyclic descriptor as a dynamic source"); } @@ -655,14 +655,14 @@ void TestNestedSrtWalk() { program.blocks[0].instructions.push_back(BufferUse(12, 16)); std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); Check(program.srt.reads.size() == 3 && program.srt.dynamic_reads.empty(), "nested SRT reads were not compacted and deduplicated"); std::vector user_data(64); SetPointer(&user_data, 4, root.data()); std::vector flat; const SrtRuntime runtime {user_data, 0, ReadHostMemory, nullptr}; - Check(WalkSrt(program, runtime, &flat, &error), error.c_str()); + Check(WalkSrt(program, runtime, flat, &error), error.c_str()); Check(flat.size() == 3 && flat.back() == child[1], "nested SRT walker read the wrong aligned dword"); } @@ -681,7 +681,7 @@ void TestDynamicReadIsNotFlattened() { program.blocks[0].instructions = {load, BufferUse(4, 16)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); Check(program.srt.reads.empty() && program.srt.dynamic_reads.size() == 1, "dynamic ReadConst was assigned a flat-buffer offset"); std::vector user_data(64); @@ -690,7 +690,7 @@ void TestDynamicReadIsNotFlattened() { DescriptorValue descriptor; const auto source = program.blocks[0].instructions[1].memory.resource_source; const SrtRuntime runtime {user_data, 0, ReadHostMemory, nullptr}; - Check(EvaluateDescriptorSource(program, source, 4, runtime, &descriptor, &error), + Check(EvaluateDescriptorSource(program, source, 4, runtime, descriptor, &error), error.c_str()); Check(descriptor.dwords[0] == table[1], "dynamic ReadConst evaluated the wrong dword"); } @@ -709,13 +709,13 @@ void TestReadConstBufferWalk() { program.blocks[0].instructions = {load, BufferUse(4, 16)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); std::vector user_data(64); SetPointer(&user_data, 4, table.data()); user_data[6] = 4; std::vector flat; const SrtRuntime runtime {user_data, 0, ReadHostMemory, nullptr}; - Check(WalkSrt(program, runtime, &flat, &error), error.c_str()); + Check(WalkSrt(program, runtime, flat, &error), error.c_str()); Check(flat.size() == 1 && flat[0] == table[0], "ReadConstBuffer walker result was wrong"); } @@ -739,14 +739,14 @@ void TestM0ScalarOffset() { program.blocks[0].instructions = {set_m0, load, BufferUse(8, 16)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); Check(program.srt.reads.size() == 1 && program.srt.dynamic_reads.empty(), "constant M0 offset was not flattened"); std::vector user_data(64); SetPointer(&user_data, 4, table.data()); std::vector flat; const SrtRuntime runtime {user_data, 0, ReadHostMemory, nullptr}; - Check(WalkSrt(program, runtime, &flat, &error), error.c_str()); + Check(WalkSrt(program, runtime, flat, &error), error.c_str()); Check(flat.size() == 1 && flat[0] == table[1], "M0 scalar offset evaluated incorrectly"); } @@ -775,12 +775,12 @@ void TestM0ArithmeticPreservesScc() { BufferUse(20, 16)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); const std::array user_data = {0xffffffffu}; const auto source = program.blocks[0].instructions.back().memory.resource_source; DescriptorValue descriptor; const SrtRuntime runtime {user_data, 0, nullptr, nullptr}; - Check(EvaluateDescriptorSource(program, source, 20, runtime, &descriptor, &error), + Check(EvaluateDescriptorSource(program, source, 20, runtime, descriptor, &error), error.c_str()); Check(descriptor.dwords[0] == 6, "arithmetic M0 destination lost its SCC carry side effect"); } @@ -795,13 +795,13 @@ void TestShaderRelativePointer() { program.blocks[0].instructions = {getpc_low, getpc_high, BufferUse(0x28, 0)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); const auto source = program.blocks[0].instructions.back().memory.resource_source; DescriptorValue descriptor; const auto shader_base = reinterpret_cast(table.data()) - 0x24; const std::array user_data = {}; const SrtRuntime runtime {user_data, shader_base, nullptr, nullptr}; - Check(EvaluateDescriptorSource(program, source, 0x28, runtime, &descriptor, &error), + Check(EvaluateDescriptorSource(program, source, 0x28, runtime, descriptor, &error), error.c_str()); const auto expected = reinterpret_cast(table.data()); Check(descriptor.dwords[0] == static_cast(expected) && @@ -827,10 +827,10 @@ void TestSmemComponentAlignment() { raw_load.memory.offset = 2; raw.blocks[0].instructions = {raw_load, BufferUse(12, 16)}; std::string error; - Check(BuildScalarProvenance(&raw, &error) && BuildSrtPlan(&raw, &error), error.c_str()); + Check(BuildScalarProvenance(raw, &error) && BuildSrtPlan(raw, &error), error.c_str()); std::vector flat; const SrtRuntime runtime {user_data, 0, ReadHostMemory, nullptr}; - Check(WalkSrt(raw, runtime, &flat, &error), error.c_str()); + Check(WalkSrt(raw, runtime, flat, &error), error.c_str()); Check(flat.size() == 1 && flat[0] == table[0], "raw S_LOAD did not clear each address component's low bits"); @@ -841,15 +841,15 @@ void TestSmemComponentAlignment() { buffer_load.memory.resource = 1; buffer.blocks[0].instructions = {buffer_load, BufferUse(12, 16)}; user_data[6] = sizeof(table); - Check(BuildScalarProvenance(&buffer, &error) && BuildSrtPlan(&buffer, &error), error.c_str()); - Check(WalkSrt(buffer, runtime, &flat, &error), error.c_str()); + Check(BuildScalarProvenance(buffer, &error) && BuildSrtPlan(buffer, &error), error.c_str()); + Check(WalkSrt(buffer, runtime, flat, &error), error.c_str()); Check(flat.size() == 1 && flat[0] == table[1], "S_BUFFER_LOAD did not align the summed final address"); buffer.blocks[0].instructions[0].src[0] = Imm(0); user_data[4] += 2; - Check(BuildScalarProvenance(&buffer, &error) && BuildSrtPlan(&buffer, &error), error.c_str()); - Check(WalkSrt(buffer, runtime, &flat, &error), error.c_str()); + Check(BuildScalarProvenance(buffer, &error) && BuildSrtPlan(buffer, &error), error.c_str()); + Check(WalkSrt(buffer, runtime, flat, &error), error.c_str()); Check(flat.size() == 1 && flat[0] == table[0], "S_BUFFER_LOAD did not clear the descriptor base low bits before " "addition"); @@ -874,16 +874,16 @@ void TestReadConstSignedAddress() { program.blocks[0].instructions = {MoveImmediate(0, 20, 4), load, BufferUse(8, 16)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); std::vector flat; const SrtRuntime runtime {user_data, 0, ReadHostMemory, nullptr}; - Check(WalkSrt(program, runtime, &flat, &error), error.c_str()); + Check(WalkSrt(program, runtime, flat, &error), error.c_str()); Check(flat.size() == 1 && flat[0] == table[0], "signed S_LOAD offset resolved the wrong SBASE-relative address"); user_data[4] = 0; user_data[5] = 0; - Check(!WalkSrt(program, runtime, &flat, &error) && + Check(!WalkSrt(program, runtime, flat, &error) && error.find("outside the 48-bit address space") != std::string::npos, "signed S_LOAD address underflow did not fail closed"); } @@ -905,7 +905,7 @@ void TestReadConstBufferBounds() { load.memory.offset = sizeof(table); program.blocks[0].instructions = {load, BufferUse(0x44, 16)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); std::vector user_data(20); SetPointer(&user_data, 4, table.data()); user_data[5] |= 4u << 16u; @@ -913,7 +913,7 @@ void TestReadConstBufferBounds() { ReadCounter counter; std::vector flat; const SrtRuntime runtime {user_data, 0, CountedHostMemory, &counter}; - Check(!WalkSrt(program, runtime, &flat, &error), + Check(!WalkSrt(program, runtime, flat, &error), "out-of-range S_BUFFER_LOAD unexpectedly succeeded"); Check(counter.reads == 0 && error.find("exceeds size=8") != std::string::npos && error.find("hash=0x0000000000001234") != std::string::npos && @@ -943,12 +943,12 @@ void TestSubBorrowPointerChain() { program.blocks[0].instructions = {low, high, MoveImmediate(8, 18, 0), MoveImmediate(12, 19, 0), BufferUse(16, 16)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); const std::array user_data = {2, 5}; DescriptorValue descriptor; const auto source = program.blocks[0].instructions.back().memory.resource_source; const SrtRuntime runtime {user_data, 0, nullptr, nullptr}; - Check(EvaluateDescriptorSource(program, source, 16, runtime, &descriptor, &error), + Check(EvaluateDescriptorSource(program, source, 16, runtime, descriptor, &error), error.c_str()); Check(descriptor.dwords[0] == 0xfffffffeu && descriptor.dwords[1] == 4, "scalar subtraction/borrow pointer chain evaluated incorrectly"); @@ -978,12 +978,12 @@ void TestCommonScalarPointerOps() { binary(Opcode::IMulU32, 18, Sgpr(2), Imm(4)), add3, BufferUse(16, 16)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); const std::array user_data = {0xf0f0u, 0x0ff0u, 7u, 9u}; DescriptorValue descriptor; const auto source = program.blocks[0].instructions.back().memory.resource_source; const SrtRuntime runtime {user_data, 0, nullptr, nullptr}; - Check(EvaluateDescriptorSource(program, source, 16, runtime, &descriptor, &error), + Check(EvaluateDescriptorSource(program, source, 16, runtime, descriptor, &error), error.c_str()); Check(descriptor.dwords[0] == (user_data[0] ^ user_data[1]) && descriptor.dwords[1] == (user_data[0] & ~user_data[1]) && @@ -1005,12 +1005,12 @@ void TestBitFieldMaskDescriptor() { BufferUse(12, 28)}; std::string error; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); DescriptorValue descriptor; const SrtRuntime runtime {{}, 0, nullptr, nullptr}; Check(EvaluateDescriptorSource(program, program.blocks[0].instructions.back().memory.resource_source, - 16, runtime, &descriptor, &error), + 16, runtime, descriptor, &error), error.c_str()); Check(descriptor.dwords[0] == 0x92u && descriptor.dwords[1] == 0x00fff000u && descriptor.dwords[2] == 0x05500000u && descriptor.dwords[3] == 0, @@ -1019,10 +1019,10 @@ void TestBitFieldMaskDescriptor() { mask.src[0] = Imm(0); program.blocks[0].instructions = {MoveImmediate(0, 28, 0x92u), mask, high, BufferUse(12, 28)}; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); Check(EvaluateDescriptorSource(program, program.blocks[0].instructions.back().memory.resource_source, - 12, runtime, &descriptor, &error), + 12, runtime, descriptor, &error), error.c_str()); Check(descriptor.dwords[1] == 0, "zero-width bit-field mask was not zero"); @@ -1030,10 +1030,10 @@ void TestBitFieldMaskDescriptor() { mask.src[1] = Imm(31); program.blocks[0].instructions = {MoveImmediate(0, 28, 0x92u), mask, high, BufferUse(12, 28)}; - Check(BuildScalarProvenance(&program, &error) && BuildSrtPlan(&program, &error), error.c_str()); + Check(BuildScalarProvenance(program, &error) && BuildSrtPlan(program, &error), error.c_str()); Check(EvaluateDescriptorSource(program, program.blocks[0].instructions.back().memory.resource_source, - 12, runtime, &descriptor, &error), + 12, runtime, descriptor, &error), error.c_str()); Check(descriptor.dwords[1] == 0x80000000u, "maximum bit-field mask count/offset evaluated incorrectly"); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 00ec32685..ca4872a99 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -621,7 +621,7 @@ CompiledShader CompileCase(const TestCase &test) { ShaderRecompiler::CompileResult result; std::string error; - if (!ShaderRecompiler::TryRecompile(test.code, options, &result, &error)) { + if (!ShaderRecompiler::TryRecompile(test.code, options, result, &error)) { Fail(test.name, "decode/IR", error.c_str()); } Require(test.name, "SPIR-V emit", !result.spirv.empty(), @@ -687,7 +687,7 @@ CompiledShader CompileFragmentCase(const GraphicsCase &test) { ShaderRecompiler::CompileResult result; std::string error; - if (!ShaderRecompiler::TryRecompile(test.fragment_code, options, &result, + if (!ShaderRecompiler::TryRecompile(test.fragment_code, options, result, &error)) { Fail(test.name, "decode/IR", error.c_str()); } @@ -882,7 +882,7 @@ public: &exact_properties) == vk::Result::eSuccess; GraphicContext context{}; context.physical_device = m_physical_device; - Require(name, "format fallback", TextureCheckFormat(&context, &image_info), + Require(name, "format fallback", TextureCheckFormat(image_info), "mutable sampled/storage RGBA8 image is unsupported"); Require(name, "format fallback", image_info.format == vk::Format::eR8G8B8A8Unorm || @@ -1073,8 +1073,9 @@ public: context.device = m_device; ResourceMutex resource_mutex; PageManager page_manager(RejectUnexpectedPageFault, nullptr); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); + TextureCache texture_cache(context, page_manager, buffer_cache, + resource_mutex); buffer_cache.SetTextureCache(texture_cache); RenderTextureVulkanImage image; image.image = image_handle; @@ -1086,42 +1087,37 @@ public: constexpr auto first_swizzle = DstSel(5, 1, 7, 0); constexpr auto second_swizzle = DstSel(7, 4, 0, 1); const auto first = texture_cache.GetSampledColorView( - &context, &image, image.format, first_swizzle, 0, 1, - vk::ImageViewType::e2D, 0, 1); + image, image.format, first_swizzle, 0, 1, vk::ImageViewType::e2D, 0, 1); const auto first_again = texture_cache.GetSampledColorView( - &context, &image, image.format, first_swizzle, 0, 1, - vk::ImageViewType::e2D, 0, 1); - const auto second = texture_cache.GetSampledColorView( - &context, &image, image.format, second_swizzle, 0, 1, - vk::ImageViewType::e2D, 0, 1); + image, image.format, first_swizzle, 0, 1, vk::ImageViewType::e2D, 0, 1); + const auto second = + texture_cache.GetSampledColorView(image, image.format, second_swizzle, + 0, 1, vk::ImageViewType::e2D, 0, 1); const auto different_mip = texture_cache.GetSampledColorView( - &context, &image, image.format, first_swizzle, 1, 1, - vk::ImageViewType::e2D, 0, 1); + image, image.format, first_swizzle, 1, 1, vk::ImageViewType::e2D, 0, 1); const auto different_layer = texture_cache.GetSampledColorView( - &context, &image, image.format, first_swizzle, 0, 1, - vk::ImageViewType::e2D, 1, 1); - const auto array_view = texture_cache.GetSampledColorView( - &context, &image, image.format, first_swizzle, 0, 1, - vk::ImageViewType::e2DArray, 0, 2); + image, image.format, first_swizzle, 0, 1, vk::ImageViewType::e2D, 1, 1); + const auto array_view = + texture_cache.GetSampledColorView(image, image.format, first_swizzle, 0, + 1, vk::ImageViewType::e2DArray, 0, 2); constexpr auto identity = DstSel(4, 5, 6, 7); const auto native_format = texture_cache.GetSampledColorView( - &context, &image, image.format, identity, 0, 1, vk::ImageViewType::e2D, - 0, 1); + image, image.format, identity, 0, 1, vk::ImageViewType::e2D, 0, 1); const auto reinterpreted_format = texture_cache.GetSampledColorView( - &context, &image, vk::Format::eR8G8B8A8Uint, identity, 0, 1, + image, vk::Format::eR8G8B8A8Uint, identity, 0, 1, vk::ImageViewType::e2D, 0, 1); const auto storage = texture_cache.GetRenderTargetStorageView( - &context, &image, image.format, 0, 1, vk::ImageViewType::e2D, 0, 1); + image, image.format, 0, 1, vk::ImageViewType::e2D, 0, 1); const auto storage_again = texture_cache.GetRenderTargetStorageView( - &context, &image, image.format, 0, 1, vk::ImageViewType::e2D, 0, 1); + image, image.format, 0, 1, vk::ImageViewType::e2D, 0, 1); const auto attachment = texture_cache.GetRenderTargetAttachmentView( - &context, &image, image.format, 0, 0, 1); + image, image.format, 0, 0, 1); const auto attachment_again = texture_cache.GetRenderTargetAttachmentView( - &context, &image, image.format, 0, 0, 1); + image, image.format, 0, 0, 1); const auto attachment_mip = texture_cache.GetRenderTargetAttachmentView( - &context, &image, image.format, 1, 0, 1); + image, image.format, 1, 0, 1); const auto attachment_array = texture_cache.GetRenderTargetAttachmentView( - &context, &image, image.format, 0, 0, 2); + image, image.format, 0, 0, 2); Require(name, "cache identity", first != nullptr && first_again == first && second != nullptr && second != first && different_mip != nullptr && @@ -1139,7 +1135,7 @@ public: "view cache omitted attachment usage, swizzle, format, type, mip, " "or layer identity"); - ImageViewOps::DestroyViews(&context, &image); + ImageViewOps::DestroyViews(image); Require(name, "view teardown", image.view_cache.views.empty(), "dynamic render-target views survived DestroyViews"); m_device.destroyImage(image_handle, nullptr); @@ -1191,8 +1187,9 @@ public: context.device = m_device; ResourceMutex resource_mutex; PageManager page_manager(RejectUnexpectedPageFault, nullptr); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); + TextureCache texture_cache(context, page_manager, buffer_cache, + resource_mutex); buffer_cache.SetTextureCache(texture_cache); DepthStencilVulkanImage image; image.image = image_handle; @@ -1204,28 +1201,28 @@ public: constexpr auto replicated = DstSel(4, 4, 4, 4); constexpr auto r001 = DstSel(4, 0, 0, 1); const auto first = texture_cache.GetDepthTargetSampledView( - &context, &image, vk::Format::eR32Sfloat, replicated, 0, 1, - vk::ImageViewType::e2D, 0, 1); + image, vk::Format::eR32Sfloat, replicated, 0, 1, vk::ImageViewType::e2D, + 0, 1); const auto first_again = texture_cache.GetDepthTargetSampledView( - &context, &image, vk::Format::eR32Sfloat, replicated, 0, 1, - vk::ImageViewType::e2D, 0, 1); + image, vk::Format::eR32Sfloat, replicated, 0, 1, vk::ImageViewType::e2D, + 0, 1); const auto different_swizzle = texture_cache.GetDepthTargetSampledView( - &context, &image, vk::Format::eR32Sfloat, r001, 0, 1, - vk::ImageViewType::e2D, 0, 1); + image, vk::Format::eR32Sfloat, r001, 0, 1, vk::ImageViewType::e2D, 0, + 1); const auto different_layer = texture_cache.GetDepthTargetSampledView( - &context, &image, vk::Format::eR32Sfloat, replicated, 0, 1, - vk::ImageViewType::e2D, 1, 1); + image, vk::Format::eR32Sfloat, replicated, 0, 1, vk::ImageViewType::e2D, + 1, 1); const auto array_view = texture_cache.GetDepthTargetSampledView( - &context, &image, vk::Format::eR32Sfloat, replicated, 0, 1, + image, vk::Format::eR32Sfloat, replicated, 0, 1, vk::ImageViewType::e2DArray, 0, 2); const auto attachment = - texture_cache.GetDepthTargetAttachmentView(&context, &image, 0, 1); + texture_cache.GetDepthTargetAttachmentView(image, 0, 1); const auto attachment_again = - texture_cache.GetDepthTargetAttachmentView(&context, &image, 0, 1); + texture_cache.GetDepthTargetAttachmentView(image, 0, 1); const auto attachment_layer = - texture_cache.GetDepthTargetAttachmentView(&context, &image, 1, 1); + texture_cache.GetDepthTargetAttachmentView(image, 1, 1); const auto attachment_array = - texture_cache.GetDepthTargetAttachmentView(&context, &image, 0, 2); + texture_cache.GetDepthTargetAttachmentView(image, 0, 2); Require( name, "cache identity", first != nullptr && first_again == first && @@ -1240,7 +1237,7 @@ public: "depth view cache omitted attachment usage, swizzle, type, or layer " "identity"); - ImageViewOps::DestroyViews(&context, &image); + ImageViewOps::DestroyViews(image); Require(name, "view teardown", image.view_cache.views.empty(), "dynamic depth-target views survived DestroyViews"); m_device.destroyImage(image_handle, nullptr); @@ -1261,8 +1258,9 @@ public: context.device = m_device; ResourceMutex resource_mutex; PageManager page_manager(RejectUnexpectedPageFault, nullptr); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); + TextureCache texture_cache(context, page_manager, buffer_cache, + resource_mutex); buffer_cache.SetTextureCache(texture_cache); VideoOutVulkanImage image; image.image = backing.image; @@ -1276,17 +1274,13 @@ public: constexpr auto bgra = DstSel(6, 5, 4, 7); constexpr auto uncommon = DstSel(5, 1, 7, 0); const auto default_view = texture_cache.GetSampledColorView( - &context, &image, image.format, identity, 0, 1, vk::ImageViewType::e2D, - 0, 1); - const auto bgra_view = - texture_cache.GetSampledColorView(&context, &image, image.format, bgra, - 0, 1, vk::ImageViewType::e2D, 0, 1); + image, image.format, identity, 0, 1, vk::ImageViewType::e2D, 0, 1); + const auto bgra_view = texture_cache.GetSampledColorView( + image, image.format, bgra, 0, 1, vk::ImageViewType::e2D, 0, 1); const auto uncommon_view = texture_cache.GetSampledColorView( - &context, &image, image.format, uncommon, 0, 1, vk::ImageViewType::e2D, - 0, 1); + image, image.format, uncommon, 0, 1, vk::ImageViewType::e2D, 0, 1); const auto uncommon_again = texture_cache.GetSampledColorView( - &context, &image, image.format, uncommon, 0, 1, vk::ImageViewType::e2D, - 0, 1); + image, image.format, uncommon, 0, 1, vk::ImageViewType::e2D, 0, 1); Require(name, "cache identity", default_view == backing.view && bgra_view != nullptr && bgra_view != default_view && uncommon_view != nullptr && @@ -1295,7 +1289,7 @@ public: "video-out sampled views did not use identity fast path and lazy " "mappings"); - ImageViewOps::DestroyViews(&context, &image); + ImageViewOps::DestroyViews(image); Require(name, "view teardown", image.view_cache.views.empty() && std::all_of(std::begin(image.image_view), @@ -1322,8 +1316,9 @@ public: EnsureRuntimeContext(); ResourceMutex resource_mutex; PageManager page_manager(RejectUnexpectedPageFault, nullptr); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(m_runtime_context, page_manager, resource_mutex); + TextureCache texture_cache(m_runtime_context, page_manager, buffer_cache, + resource_mutex); buffer_cache.SetTextureCache(texture_cache); page_manager.OnGpuMap(base, allocation_size); @@ -1342,7 +1337,7 @@ public: TileSizeAlign sampled_size{}; TileGetTextureTotalSize(format, sampled_info.width, sampled_info.height, sampled_info.depth, sampled_info.pitch, - sampled_info.levels, linear, false, &sampled_size); + sampled_info.levels, linear, false, sampled_size); sampled_info.size = sampled_size.size; Require(name, "sampled fixture", sampled_info.size != 0 && sampled_size.align != 0 && @@ -1362,12 +1357,8 @@ public: { CommandBuffer command(GraphicContext::QUEUE_GFX); - auto *sampled = texture_cache.FindTexture(&command, &m_runtime_context, - sampled_info, false); - auto *target = texture_cache.FindRenderTarget( - &command, &m_runtime_context, target_info); - Require(name, "registration", sampled != nullptr && target != nullptr, - "sampled or non-sampled image registration failed"); + (void)texture_cache.FindTexture(command, sampled_info, false); + auto& target = texture_cache.FindRenderTarget(command, target_info); const auto sampled_bytes = texture_cache.QueryRegion(sampled_info.address + 0x20, 0x20); @@ -2376,7 +2367,7 @@ public: const GpuTileInfo &info) { TileBlockLayout block{}; Require(name, "reference layout", - TileGetBlockLayout(info.family, info.bytes_per_element, &block), + TileGetBlockLayout(info.family, info.bytes_per_element, block), "CPU reference rejected GPU tile info"); const u32 tiled_width = info.tiled_width != 0 ? info.tiled_width : info.pitch; @@ -2401,9 +2392,8 @@ public: const u32 lz = z % block.block_depth; u32 local = 0, block_xor = 0; Require(name, "reference offset", - TileGetBlockOffset(block, lx, ly, lz, &local) && - TileGetBlockXor(block, bx, by, info.surface_z + bz, - &block_xor), + TileGetBlockOffset(block, lx, ly, lz, local) && + TileGetBlockXor(block, bx, by, info.surface_z + bz, block_xor), "CPU reference address lookup failed"); const uint64_t block_index = static_cast(bz) * columns * rows + by * columns + bx; @@ -2448,19 +2438,18 @@ public: u32 standard_offset = 0, prt_offset = 0, standard_3d_offset = 0, prt_3d_offset = 0, color_z = 0, depth_z = 0; bool fixed_addresses = - TileGetBlockLayout(TileBlockFamily::Standard64KB, 4, &standard) && - TileGetBlockLayout(TileBlockFamily::Prt64KB, 4, &prt) && - TileGetBlockLayout(TileBlockFamily::Standard64KB3D, 4, - &standard_3d) && - TileGetBlockLayout(TileBlockFamily::Prt64KB3D, 4, &prt_3d) && - TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, 4, &color) && - TileGetBlockLayout(TileBlockFamily::Depth64KB, 4, &depth) && - TileGetBlockOffset(standard, 64, 0, 0, &standard_offset) && - TileGetBlockOffset(prt, 64, 0, 0, &prt_offset) && - TileGetBlockOffset(standard_3d, 16, 0, 0, &standard_3d_offset) && - TileGetBlockOffset(prt_3d, 16, 0, 0, &prt_3d_offset) && - TileGetBlockXor(color, 0, 0, 1, &color_z) && - TileGetBlockXor(depth, 0, 0, 15, &depth_z); + TileGetBlockLayout(TileBlockFamily::Standard64KB, 4, standard) && + TileGetBlockLayout(TileBlockFamily::Prt64KB, 4, prt) && + TileGetBlockLayout(TileBlockFamily::Standard64KB3D, 4, standard_3d) && + TileGetBlockLayout(TileBlockFamily::Prt64KB3D, 4, prt_3d) && + TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, 4, color) && + TileGetBlockLayout(TileBlockFamily::Depth64KB, 4, depth) && + TileGetBlockOffset(standard, 64, 0, 0, standard_offset) && + TileGetBlockOffset(prt, 64, 0, 0, prt_offset) && + TileGetBlockOffset(standard_3d, 16, 0, 0, standard_3d_offset) && + TileGetBlockOffset(prt_3d, 16, 0, 0, prt_3d_offset) && + TileGetBlockXor(color, 0, 0, 1, color_z) && + TileGetBlockXor(depth, 0, 0, 15, depth_z); Require(name, "fixed address vectors", fixed_addresses && standard_offset == 0x8000 && prt_offset == 0x8100 && standard_3d_offset == 0x8000 && @@ -2504,8 +2493,7 @@ public: for (const auto &info : infos) { convert_reference(false, &cpu, tiled, info); } - GpuDetile(&m_runtime_context, tiled.data(), gpu.data(), size, size, - infos); + GpuDetile(tiled.data(), gpu.data(), size, size, infos); compare((std::string(stage) + " detile bytes").c_str(), cpu, gpu); std::vector linear(size); @@ -2515,7 +2503,7 @@ public: for (const auto &info : infos) { convert_reference(true, &cpu_tiled, linear, info); } - GpuTile(&m_runtime_context, linear.data(), gpu_tiled.data(), size, size, + GpuTile(linear.data(), gpu_tiled.data(), size, size, infos); compare((std::string(stage) + " tile bytes").c_str(), cpu_tiled, gpu_tiled); @@ -2524,7 +2512,7 @@ public: for (u32 bpe = 1; bpe <= family.max_bpe; bpe <<= 1u) { TileBlockLayout block{}; Require(name, "block layout", - TileGetBlockLayout(family.family, bpe, &block), + TileGetBlockLayout(family.family, bpe, block), "admitted family/BPE has no block layout"); const bool volume = block.block_depth > 1; const u32 width = @@ -2564,7 +2552,7 @@ public: ? 3 : 0; convert_reference(false, &cpu, tiled, info); - GpuDetile(&m_runtime_context, tiled.data(), gpu.data(), storage_size, + GpuDetile(tiled.data(), gpu.data(), storage_size, storage_size, std::span(&info, 1)); const auto family_label = [&](const char *operation) { std::ostringstream out; @@ -2580,7 +2568,7 @@ public: std::vector gpu_tiled(storage_size, 0xab); fill(&linear, 0x80u + case_index); convert_reference(true, &cpu_tiled, linear, info); - GpuTile(&m_runtime_context, linear.data(), gpu_tiled.data(), + GpuTile(linear.data(), gpu_tiled.data(), storage_size, storage_size, std::span(&info, 1)); compare(family_label("tile bytes").c_str(), cpu_tiled, gpu_tiled); @@ -2625,7 +2613,7 @@ public: Prospero::BlockCompressedBytesPerBlock(format)); TileBlockLayout block{}; Require(name, "format block", - TileGetBlockLayout(mode.family, bpe, &block), + TileGetBlockLayout(mode.family, bpe, block), "CPU-supported format has no GPU family/BPE mapping"); constexpr u32 width = 67; @@ -2645,7 +2633,7 @@ public: TextureUploadDestination::MipLevels); std::vector infos; if (!TextureBuildGpuTileInfos(total.size, regions, layout, format, 1, 1, - &infos)) { + infos)) { std::ostringstream out; out << "format=" << format << " tile=" << mode.tile << " size=" << total.size << " pitch=" << pitch; @@ -2661,7 +2649,7 @@ public: std::vector gpu(total.size, 0xab); fill(&tiled, ++case_index); convert_reference(false, &cpu, tiled, infos[0]); - GpuDetile(&m_runtime_context, tiled.data(), gpu.data(), total.size, + GpuDetile(tiled.data(), gpu.data(), total.size, total.size, infos); compare("format bytes", cpu, gpu); ++format_cases; @@ -2679,7 +2667,7 @@ public: const u32 pitch = TileGetTexturePitch(format, width, 1, tile); TileSizeAlign total{}; TileGetTextureTotalSize(format, width, height, layers, pitch, 1, tile, - false, &total); + false, total); const auto layout = TextureCalcUploadLayout(format, width, height, 1, layers, pitch, tile, total.size, true, false, name); @@ -2688,7 +2676,7 @@ public: TextureUploadDestination::MipLevels); std::vector infos; const bool built = TextureBuildGpuTileInfos(total.size, regions, layout, - format, layers, 1, &infos); + format, layers, 1, infos); Require(name, "array infos", built && infos.size() == layers && infos[0].surface_z == 0 && infos[1].surface_z == 1 && infos[2].surface_z == 2, @@ -2701,7 +2689,7 @@ public: Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float); constexpr u32 levels = 2; TileBlockLayout block{}; - Require(name, "odd mip block", TileGetBlockLayout(mode.family, 4, &block), + Require(name, "odd mip block", TileGetBlockLayout(mode.family, 4, block), "odd multi-mip format has no block layout"); const u32 width = block.block_width * 2u + 1u; const u32 height = block.block_height * 2u + 1u; @@ -2718,7 +2706,7 @@ public: std::vector infos; Require(name, "odd mip infos", TextureBuildGpuTileInfos(total.size, regions, layout, format, 1, - levels, &infos) && + levels, infos) && infos.size() == 2 && infos[1].tiled_width >= infos[1].pitch && infos[1].tiled_height >= infos[1].height && (mode.family == TileBlockFamily::Standard256B || @@ -2749,7 +2737,7 @@ public: Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float); constexpr u32 levels = 7; TileBlockLayout block{}; - Require(name, "2D tail block", TileGetBlockLayout(mode.family, 4, &block), + Require(name, "2D tail block", TileGetBlockLayout(mode.family, 4, block), "2D tail mode has no block layout"); const u32 width = block.block_width * 2u; const u32 height = block.block_height * 2u; @@ -2767,7 +2755,7 @@ public: Require(name, "2D mip tail seam", layout.first_tail_level == 2 && TextureBuildGpuTileInfos(total.size, regions, layout, format, - 1, levels, &infos) && + 1, levels, infos) && infos.size() == levels && !infos[0].tail && !infos[1].tail && std::all_of(infos.begin() + 2, infos.end(), [](const auto &info) { return info.tail; }), @@ -2787,7 +2775,7 @@ public: const u32 pitch = TileGetTexturePitch(format, width, levels, tile); TileSizeAlign total{}; TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile, - true, &total); + true, total); const auto layout = TextureCalcUploadLayout(format, width, height, levels, depth, pitch, tile, total.size, false, true, name); @@ -2795,8 +2783,8 @@ public: layout, vk::Format::eR32Sfloat, width, height, depth, levels, false, true, TextureUploadDestination::MipLevels); std::vector infos; - const bool built = TextureBuildGpuTileInfos( - total.size, regions, layout, format, depth, levels, &infos); + const bool built = TextureBuildGpuTileInfos(total.size, regions, layout, + format, depth, levels, infos); Require(name, "3D mip infos", regions.size() == depth + (depth >> 1u) && built && infos.size() == 4 && infos[0].depth == 8 && @@ -2823,7 +2811,7 @@ public: const u32 pitch = TileGetTexturePitch(format, width, levels, tile); TileSizeAlign total{}; TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile, - true, &total); + true, total); const auto layout = TextureCalcUploadLayout(format, width, height, levels, depth, pitch, tile, total.size, false, true, name); @@ -2833,7 +2821,7 @@ public: std::vector infos; Require(name, "3D BC mip infos", TextureBuildGpuTileInfos(total.size, regions, layout, format, - depth, levels, &infos) && + depth, levels, infos) && infos.size() == 4 && infos[3].pitch == 8 && infos[3].height == 16 && infos[3].tiled_width == 16 && infos[3].tiled_height == 24, @@ -2872,7 +2860,7 @@ public: TileGetTexturePitch(test.format, width, levels, test.tile); TileSizeAlign total{}; TileGetTextureTotalSize(test.format, width, height, depth, pitch, levels, - test.tile, true, &total); + test.tile, true, total); const auto layout = TextureCalcUploadLayout( test.format, width, height, levels, depth, pitch, test.tile, total.size, true, true, name); @@ -2881,7 +2869,7 @@ public: false, true, TextureUploadDestination::MipLevels); std::vector infos; const bool built = TextureBuildGpuTileInfos( - total.size, regions, layout, test.format, depth, levels, &infos); + total.size, regions, layout, test.format, depth, levels, infos); const bool uses_z = test.family == TileBlockFamily::RenderTarget64KB || test.family == TileBlockFamily::Depth64KB; Require(name, "volume family infos", @@ -2924,8 +2912,7 @@ public: constexpr u32 levels = 5; TileBlockLayout block{}; Require(name, "3D tail block", - TileGetBlockLayout(TileBlockFamily::Standard4KB3D, tail.bytes, - &block), + TileGetBlockLayout(TileBlockFamily::Standard4KB3D, tail.bytes, block), "Standard4KB3D tail format has no block layout"); const bool compressed = Prospero::BlockCompressedBytesPerBlock(tail.format) != 0; @@ -2935,7 +2922,7 @@ public: const u32 pitch = TileGetTexturePitch(tail.format, width, levels, tile); TileSizeAlign total{}; TileGetTextureTotalSize(tail.format, width, height, depth, pitch, levels, - tile, true, &total); + tile, true, total); const auto layout = TextureCalcUploadLayout(tail.format, width, height, levels, depth, pitch, tile, total.size, false, true, name); @@ -2949,7 +2936,7 @@ public: depth + std::max(depth >> 1u, 1u) + std::max(depth >> 2u, 1u) + std::max(depth >> 3u, 1u) + std::max(depth >> 4u, 1u) && TextureBuildGpuTileInfos(total.size, regions, layout, tail.format, - depth, levels, &infos) && + depth, levels, infos) && infos.size() == 6; const u32 table = std::countr_zero(tail.bytes); for (u32 level = 0; level < levels && valid; level++) { @@ -2978,7 +2965,7 @@ public: if (family == TileBlockFamily::Depth64KB && bpe == 16) continue; TileBlockLayout block{}; - Require(name, "tail layout", TileGetBlockLayout(family, bpe, &block), + Require(name, "tail layout", TileGetBlockLayout(family, bpe, block), "tail family/BPE has no block layout"); const u32 width = std::max(block.block_width / 4u, 1u); const u32 height = std::max(block.block_height / 4u, 1u); @@ -3007,9 +2994,8 @@ public: ? 2 : 0; convert_reference(false, &cpu, tiled, info); - GpuDetile(&m_runtime_context, tiled.data(), gpu.data(), - block.block_size, linear_size, - std::span(&info, 1)); + GpuDetile(tiled.data(), gpu.data(), block.block_size, + linear_size, std::span(&info, 1)); compare("tail bytes", cpu, gpu); std::vector linear(linear_size); @@ -3017,7 +3003,7 @@ public: std::vector gpu_tiled(block.block_size, 0xab); fill(&linear, 0x400u + case_index); convert_reference(true, &cpu_tiled, linear, info); - GpuTile(&m_runtime_context, linear.data(), gpu_tiled.data(), + GpuTile(linear.data(), gpu_tiled.data(), block.block_size, linear_size, std::span(&info, 1)); compare("tail tile bytes", cpu_tiled, gpu_tiled); @@ -3026,7 +3012,7 @@ public: TileBlockLayout small_block{}; Require(name, "small layout", - TileGetBlockLayout(TileBlockFamily::Standard256B, 4, &small_block), + TileGetBlockLayout(TileBlockFamily::Standard256B, 4, small_block), "small fixture layout is unavailable"); std::vector small_input(small_block.block_size); std::vector small_expected(small_block.block_size, 0); @@ -3041,14 +3027,14 @@ public: small_info.height = 1; small_info.pitch = small_block.block_width; convert_reference(false, &small_expected, small_input, small_info); - GpuDetile(&m_runtime_context, small_input.data(), small_output.data(), + GpuDetile(small_input.data(), small_output.data(), small_input.size(), small_output.size(), std::span(&small_info, 1)); compare("small detile", small_expected, small_output); - GpuTileRelease(&m_runtime_context); + GpuTileRelease(); std::fill(small_output.begin(), small_output.end(), 0xab); - GpuDetile(&m_runtime_context, small_input.data(), small_output.data(), + GpuDetile(small_input.data(), small_output.data(), small_input.size(), small_output.size(), std::span(&small_info, 1)); compare("release recovery", small_expected, small_output); @@ -3090,10 +3076,10 @@ private: static_cast(vmaCreateAllocator( &allocator_info, &m_runtime_context.allocator)), "vmaCreateAllocator"); - if (g_render_ctx == nullptr) { + if (!HasRenderContext()) { GraphicsRenderInit(); + GraphicsRenderSetContext(*new RenderContext(m_runtime_context)); } - g_render_ctx->SetGraphicCtx(&m_runtime_context); } void Init() { @@ -3196,7 +3182,7 @@ private: RequireVulkanSuccess(m_device.waitIdle(), "vkDeviceWaitIdle"); if (m_runtime_context.allocator != nullptr) { GraphicsRenderReleaseThreadCommandPools(); - Transfer::ReleaseCachedResources(&m_runtime_context); + Transfer::ReleaseCachedResources(); vmaDestroyAllocator(m_runtime_context.allocator); m_runtime_context.allocator = nullptr; } @@ -9676,7 +9662,7 @@ void CheckPs5GameExampleImageClearRuntimeShape() { ShaderRecompiler::CompileResult result; std::string error; Require("Ps5GameExampleImageClear", stage, - ShaderRecompiler::TryRecompile(code, options, &result, &error), + ShaderRecompiler::TryRecompile(code, options, result, &error), error); ValidateSpirv("Ps5GameExampleImageClear", result.spirv); return result; @@ -9694,8 +9680,8 @@ void CheckPs5GameExampleImageClearRuntimeShape() { u32 packed_clear = 0; uint64_t size = 0; Require("Ps5GameExampleImageClear", "runtime shape", - ResolveComputeImageClear(compute, 64, 1, 1, 0x61u, &descriptor, - &packed_clear, &size) && + ResolveComputeImageClear(compute, 64, 1, 1, 0x61u, descriptor, + packed_clear, size) && descriptor.Base48() == 0x10000u && size == 64u * 16u && packed_clear == 0xff000000u, "exact Prospero runtime binding did not resolve to a complete clear"); @@ -9706,16 +9692,16 @@ void CheckPs5GameExampleImageClearRuntimeShape() { std::make_shared( non_repeated); Require("Ps5GameExampleImageClear", "non-repeated clear", - !ResolveComputeImageClear(compute, 64, 1, 1, 0x61u, &descriptor, - &packed_clear, &size), + !ResolveComputeImageClear(compute, 64, 1, 1, 0x61u, descriptor, + packed_clear, size), "non-uniform uint4 data was replaced with a color clear"); compute.stage.resources = std::make_shared( positive.resources); compute.dispatch_threads_num[0] = 32; Require("Ps5GameExampleImageClear", "partial dispatch", - !ResolveComputeImageClear(compute, 32, 1, 1, 0x61u, &descriptor, - &packed_clear, &size), + !ResolveComputeImageClear(compute, 32, 1, 1, 0x61u, descriptor, + packed_clear, size), "partial buffer coverage was classified as a complete clear"); std::printf("[host] %-32s ok\n", "Ps5GameExampleImageClear"); } @@ -9777,7 +9763,7 @@ void CheckEmbeddedFetchVertexOffset() { ShaderRecompiler::CompileResult result; std::string error; Require(name, "compile", - ShaderRecompiler::TryRecompile(code, options, &result, &error), + ShaderRecompiler::TryRecompile(code, options, result, &error), error); Require(name, "fetch rewrite", vertex.resource_fetch_components[0] == 4, "encoded fetch sequence was not recognized and rewritten"); @@ -10548,19 +10534,19 @@ void CheckSampledDepthDescriptor() { void CheckBufferCacheRangeMerge() { BufferCacheRange merged{0x10000, 0x4000}; Require("BufferCacheRangeMerge", "disjoint", - !MergeOverlappingBufferCacheRange(&merged, {0x14000, 0x4000}) && + !MergeOverlappingBufferCacheRange(merged, {0x14000, 0x4000}) && merged.address == 0x10000 && merged.size == 0x4000, "adjacent range was merged"); Require("BufferCacheRangeMerge", "right growth", - MergeOverlappingBufferCacheRange(&merged, {0x12000, 0x8000}) && + MergeOverlappingBufferCacheRange(merged, {0x12000, 0x8000}) && merged.address == 0x10000 && merged.size == 0xa000, "right overlap did not grow the cache range"); Require("BufferCacheRangeMerge", "left growth", - MergeOverlappingBufferCacheRange(&merged, {0xc000, 0x8000}) && + MergeOverlappingBufferCacheRange(merged, {0xc000, 0x8000}) && merged.address == 0xc000 && merged.size == 0xe000, "left overlap did not grow the cache range"); Require("BufferCacheRangeMerge", "contained", - MergeOverlappingBufferCacheRange(&merged, {0x10000, 0x1000}) && + MergeOverlappingBufferCacheRange(merged, {0x10000, 0x1000}) && merged.address == 0xc000 && merged.size == 0xe000, "contained range changed the cache union"); Require("BufferCacheRangeMerge", "queue ownership", @@ -10992,8 +10978,7 @@ void CheckStorageTextureLinearUploadLayout() { constexpr uint32_t tile = Prospero::GpuEnumValue(Prospero::TileMode::kLinear); const auto pitch = TileGetTexturePitch(format, width, 1, tile); TileSizeAlign total{}; - TileGetTextureTotalSize(format, width, height, depth, pitch, 1, tile, false, - &total); + TileGetTextureTotalSize(format, width, height, depth, pitch, 1, tile, false, total); const auto layout = TextureCalcUploadLayout( format, width, height, 1, depth, pitch, tile, total.size, true, false, "StorageTextureLinearTest"); @@ -11025,8 +11010,7 @@ void CheckStorageTextureDepthTileUploadLayout() { TilePaddedSize padded{}; TileGetTextureSize(format, width, height, pitch, 1, tile, &slice, &level, &padded); - TileGetTextureTotalSize(format, width, height, depth, pitch, 1, tile, false, - &total); + TileGetTextureTotalSize(format, width, height, depth, pitch, 1, tile, false, total); const auto layout = TextureCalcUploadLayout( format, width, height, 1, depth, pitch, tile, total.size, true, false, "StorageTextureDepthTileTest"); @@ -11105,8 +11089,8 @@ void CheckStorageImageSwizzleSpecializationId() { rgb1_info.stage.program = std::make_shared(rgb1_program); - const auto identity_id = ShaderGetIdCS(®s, &identity_info, true); - const auto rgb1_id = ShaderGetIdCS(®s, &rgb1_info, true); + const auto identity_id = ShaderGetIdCS(regs, identity_info, true); + const auto rgb1_id = ShaderGetIdCS(regs, rgb1_info, true); Require("StorageImageSwizzleSpecializationId", "pipeline cache key", identity_id != rgb1_id && identity_id.ids.size() == rgb1_id.ids.size(), @@ -11126,7 +11110,7 @@ void CheckStorageTextureVolumeUploadLayout() { TileSizeAlign total{}; TileGetTextureTotalSize( format, width, height, depth, pitch, 1, - Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), true, &total); + Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), true, total); const auto layout = TextureCalcUploadLayout( format, width, height, 1, depth, pitch, Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), total.size, @@ -11147,7 +11131,7 @@ void CheckStorageTextureVolumeUploadLayout() { std::vector infos; Require("StorageTextureVolumeUpload", "GPU records", TextureBuildGpuTileInfos(total.size, regions, layout, format, depth, - 1, &infos) && + 1, infos) && infos.size() == depth, "3D render-target GPU records were not built"); for (const uint32_t z : {0u, 1u, depth - 1u}) { @@ -11171,7 +11155,7 @@ void CheckStorageTextureVolumeMipRegions() { const auto pitch = TileGetTexturePitch(format, width, levels, tile); TileSizeAlign total{}; TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile, - true, &total); + true, total); const auto layout = TextureCalcUploadLayout( format, width, height, levels, depth, pitch, tile, total.size, true, true, "StorageTextureVolumeMipTest"); @@ -11229,7 +11213,7 @@ void CheckColorResolveLayers() { "different array layers were treated as the same resolve subresource"); const auto copy = MakeColorResolveCopy(src, dst, 128, 64); Require("ColorResolveLayers", "region", - copy.src_image == src.vulkan_buffer && copy.src_level == 2 && + ©.src_image == src.vulkan_buffer && copy.src_level == 2 && copy.dst_level == 2 && copy.src_layer == 1 && copy.dst_layer == 3 && copy.width == 128 && copy.height == 64, "color resolve dropped its source or destination array layer"); @@ -11340,9 +11324,9 @@ void CheckStorageTextureGpuOwnedRebindState() { "StorageTextureGpuOwnedRebind", "owned", tracker.IsRegionGpuModified(base, size) && page_manager.IsMapped(base, size) && - (!HostMemoryQueryReadable(base, size, &readable) || + (!HostMemoryQueryReadable(base, size, readable) || readable < size) && - HostMemoryQueryRange(base, size, HostMemoryAccess::Mapped, &mapped) && + HostMemoryQueryRange(base, size, HostMemoryAccess::Mapped, mapped) && mapped == size && VirtualQuery(memory, &protection, sizeof(protection)) != 0 && protection.Protect == PAGE_NOACCESS, @@ -11354,7 +11338,7 @@ void CheckStorageTextureGpuOwnedRebindState() { Require("StorageTextureGpuOwnedRebind", "clean readback", !tracker.IsRegionGpuModified(base, size) && !tracker.IsRegionCpuModified(base, size) && - HostMemoryQueryReadable(base, size, &readable) && + HostMemoryQueryReadable(base, size, readable) && readable == size, "clean storage readback did not publish readable coherent backing"); tracker.MarkRegionAsGpuModified(base, size); @@ -11363,7 +11347,7 @@ void CheckStorageTextureGpuOwnedRebindState() { "StorageTextureGpuOwnedRebind", "clean reclaim", tracker.IsRegionGpuModified(base, size) && !tracker.IsRegionCpuModified(base, size) && - (!HostMemoryQueryReadable(base, size, &readable) || readable < size), + (!HostMemoryQueryReadable(base, size, readable) || readable < size), "clean storage rebind did not reclaim GPU ownership without an upload"); tracker.UnmarkRegionAsGpuModified(base, size); @@ -11379,7 +11363,7 @@ void CheckStorageTextureGpuOwnedRebindState() { dirty_ranges == 1 && upload_called && tracker.IsRegionGpuModified(base, size) && !tracker.IsRegionCpuModified(base, size) && - (!HostMemoryQueryReadable(base, size, &readable) || readable < size), + (!HostMemoryQueryReadable(base, size, readable) || readable < size), "CPU-dirty storage rebind did not refresh once and reclaim GPU " "ownership"); @@ -11428,8 +11412,8 @@ void CheckStorageTextureSampledReuse() { Require("StorageTextureSampledReuse", "exact", ClassifyStorageSampledOverlap( storage, storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, false, - true) == StorageSampledOverlap::ExactImage, + vk::Format::eR16G16B16A16Sfloat, true, + false) == StorageSampledOverlap::ExactImage, "exact GPU-owned storage image was not reusable for sampling"); auto incompatible = storage; incompatible.format = @@ -11437,28 +11421,24 @@ void CheckStorageTextureSampledReuse() { Require("StorageTextureSampledReuse", "incompatible", ClassifyStorageSampledOverlap( incompatible, storage, vk::Format::eR16G16B16A16Unorm, - vk::Format::eR16G16B16A16Sfloat, true, false, - true) == StorageSampledOverlap::Unsupported && + vk::Format::eR16G16B16A16Sfloat, true, + false) == StorageSampledOverlap::Unsupported && ClassifyStorageSampledOverlap( storage, storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, false, false, - true) == StorageSampledOverlap::Unsupported && + vk::Format::eR16G16B16A16Sfloat, false, + false) == StorageSampledOverlap::Unsupported && ClassifyStorageSampledOverlap( storage, storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, true, - true) == StorageSampledOverlap::Unsupported && - ClassifyStorageSampledOverlap( - storage, storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, false, - false) == StorageSampledOverlap::Unsupported, + vk::Format::eR16G16B16A16Sfloat, true, + true) == StorageSampledOverlap::Unsupported, "incompatible storage-image state was accepted for sampling"); auto separate = storage; separate.address += 0x400000; Require("StorageTextureSampledReuse", "separate", - ClassifyStorageSampledOverlap( - separate, storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, false, - true) == StorageSampledOverlap::None, + ClassifyStorageSampledOverlap(separate, storage, + vk::Format::eR16G16B16A16Sfloat, + vk::Format::eR16G16B16A16Sfloat, true, + false) == StorageSampledOverlap::None, "disjoint storage image was classified as an alias"); ImageInfo mip_chain{}; @@ -11488,8 +11468,8 @@ void CheckStorageTextureSampledReuse() { vk::Format::eR16G16B16A16Sfloat) && ClassifyStorageSampledOverlap( mip_chain, mip_storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, false, true, true, - false, true) == StorageSampledOverlap::RetireStorage, + vk::Format::eR16G16B16A16Sfloat, true, false, true, false, + true) == StorageSampledOverlap::RetireStorage, "captured GPU-owned level-1 storage allocation was not materialized " "before " "rebuilding its sampled chain"); @@ -11506,8 +11486,8 @@ void CheckStorageTextureSampledReuse() { vk::Format::eR16G16B16A16Sfloat) && ClassifyStorageSampledOverlap( mip_chain, tail_storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, false, true, true, - false, true) == StorageSampledOverlap::RetireStorage, + vk::Format::eR16G16B16A16Sfloat, true, false, true, false, + true) == StorageSampledOverlap::RetireStorage, "captured GPU-owned physical mip-tail block was not materialized " "before rebuilding its sampled chain"); auto malformed_mip = mip_storage; @@ -11531,19 +11511,15 @@ void CheckStorageTextureSampledReuse() { ClassifyStorageSampledOverlap( mip_chain, mip_storage, vk::Format::eR16G16B16A16Sfloat, vk::Format::eR16G16B16A16Sfloat, true, false, true, true, - true, true) == StorageSampledOverlap::Unsupported && + true) == StorageSampledOverlap::Unsupported && ClassifyStorageSampledOverlap( mip_chain, mip_storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, false, true, true, - false, false) == StorageSampledOverlap::Unsupported && + vk::Format::eR16G16B16A16Sfloat, true, false, true, false, + false) == StorageSampledOverlap::Unsupported && ClassifyStorageSampledOverlap( mip_chain, mip_storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, true, true, true, - false, true) == StorageSampledOverlap::Unsupported && - ClassifyStorageSampledOverlap( - mip_chain, mip_storage, vk::Format::eR16G16B16A16Sfloat, - vk::Format::eR16G16B16A16Sfloat, true, false, false, true, - false, true) == StorageSampledOverlap::Unsupported, + vk::Format::eR16G16B16A16Sfloat, true, true, true, false, + true) == StorageSampledOverlap::Unsupported, "malformed or unsafe mip-storage ownership was accepted"); ImageInfo ppsa02604_storage{}; @@ -11565,8 +11541,8 @@ void CheckStorageTextureSampledReuse() { Require("StorageTextureSampledReuse", "PPSA02604 sRGB view", ClassifyStorageSampledOverlap( ppsa02604_sampled, ppsa02604_storage, vk::Format::eR8G8B8A8Srgb, - vk::Format::eR8G8B8A8Unorm, true, false, - true) == StorageSampledOverlap::ExactImage, + vk::Format::eR8G8B8A8Unorm, true, + false) == StorageSampledOverlap::ExactImage, "PPSA02604 GPU-owned UNORM storage image did not accept its exact " "sRGB view"); auto alternate_swizzle = ppsa02604_storage; @@ -11575,8 +11551,8 @@ void CheckStorageTextureSampledReuse() { "StorageTextureSampledReuse", "descriptor swizzle view", ClassifyStorageSampledOverlap(alternate_swizzle, ppsa02604_storage, vk::Format::eR8G8B8A8Unorm, - vk::Format::eR8G8B8A8Unorm, true, false, - true) == StorageSampledOverlap::ExactImage, + vk::Format::eR8G8B8A8Unorm, true, + false) == StorageSampledOverlap::ExactImage, "exact storage backing rejected a distinct sampled descriptor swizzle"); ImageInfo depth_uint_storage{}; depth_uint_storage.address = 0x4a5c90000; @@ -11597,10 +11573,10 @@ void CheckStorageTextureSampledReuse() { Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float); depth_float_sampled.swizzle = DstSel(4, 0, 0, 1); Require("StorageTextureSampledReuse", "PPSA01530 R32 view", - ClassifyStorageSampledOverlap( - depth_float_sampled, depth_uint_storage, vk::Format::eR32Sfloat, - vk::Format::eR32Uint, true, false, - true) == StorageSampledOverlap::ExactImage, + ClassifyStorageSampledOverlap(depth_float_sampled, depth_uint_storage, + vk::Format::eR32Sfloat, + vk::Format::eR32Uint, true, false) == + StorageSampledOverlap::ExactImage, "PPSA01530 GPU-owned R32_UINT storage image did not accept its exact " "R32_SFLOAT view"); const auto usage = TextureFormatUsage::Sampled | TextureFormatUsage::Storage; @@ -11628,46 +11604,43 @@ void CheckStorageTextureDepthAlias() { depth.stencil_address = storage.address; depth.stencil_size = storage.size; Require("StorageTextureDepthAlias", "inactive stencil", - ClassifyStorageDepthOverlap(storage, true, false, false, true, true, + ClassifyStorageDepthOverlap(storage, true, false, false, true, depth) == DepthOverlap::RetireStorage, "inactive stencil storage ownership was not retired"); depth.stencil_access = true; Require("StorageTextureDepthAlias", "active stencil", - ClassifyStorageDepthOverlap(storage, true, false, false, true, true, + ClassifyStorageDepthOverlap(storage, true, false, false, true, depth) == DepthOverlap::Unsupported, "active stencil storage contents were discarded"); depth.stencil_access = false; storage.address = depth.address; depth.depth_access = true; Require("StorageTextureDepthAlias", "depth aspect", - ClassifyStorageDepthOverlap(storage, true, false, false, true, true, + ClassifyStorageDepthOverlap(storage, true, false, false, true, depth) == DepthOverlap::Unsupported, "depth-aspect storage contents were discarded"); Require("StorageTextureDepthAlias", "clean depth transition", - ClassifyStorageDepthOverlap(storage, false, false, false, false, true, + ClassifyStorageDepthOverlap(storage, false, false, false, false, depth) == DepthOverlap::RetireStorage, "guest-current storage image was not retired for a depth target"); - Require( - "StorageTextureDepthAlias", "depth ownership guards", - ClassifyStorageDepthOverlap(storage, false, true, false, false, true, - depth) == DepthOverlap::Unsupported && - ClassifyStorageDepthOverlap(storage, false, false, true, false, true, + Require("StorageTextureDepthAlias", "depth ownership guards", + ClassifyStorageDepthOverlap(storage, false, true, false, false, depth) == DepthOverlap::Unsupported && - ClassifyStorageDepthOverlap(storage, false, false, false, true, true, - depth) == DepthOverlap::Unsupported && - ClassifyStorageDepthOverlap(storage, false, false, false, false, - false, - depth) == DepthOverlap::Unsupported, - "incoherent storage-to-depth transition was admitted"); + ClassifyStorageDepthOverlap(storage, false, false, true, false, + depth) == DepthOverlap::Unsupported && + ClassifyStorageDepthOverlap(storage, false, false, false, true, + depth) == DepthOverlap::Unsupported, + "incoherent storage-to-depth transition was admitted"); storage.address = 0x2000000000ull; Require("StorageTextureDepthAlias", "disjoint", - ClassifyStorageDepthOverlap(storage, true, true, true, true, false, - depth) == DepthOverlap::None, + ClassifyStorageDepthOverlap(storage, true, true, true, true, depth) == + DepthOverlap::None, "disjoint storage image was classified as an alias"); std::printf("[host] %-32s ok\n", "StorageTextureDepthAlias"); } [[noreturn]] void RunStorageTextureAccessDeathCase(const char *kind) { + GraphicContext context{}; constexpr uintptr_t base = 0x0000000200300000ull; constexpr uint64_t size = 0x10000; auto *memory = VirtualAlloc(reinterpret_cast(base), size, @@ -11677,7 +11650,7 @@ void CheckStorageTextureDepthAlias() { } ResourceMutex resource_mutex; PageManager page_manager(CacheFault, nullptr); - BufferCache buffer_cache(page_manager, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); if (std::strcmp(kind, "read") == 0) { page_manager.OnGpuMap(base, size, GpuAccess::Write); buffer_cache.ValidateGpuAccess(base, size, true, true); @@ -11691,6 +11664,7 @@ void CheckStorageTextureDepthAlias() { } void CheckStorageTextureAccessPermissions() { + GraphicContext context{}; constexpr uintptr_t base = 0x0000000200300000ull; constexpr uint64_t size = 0x10000; auto *memory = VirtualAlloc(reinterpret_cast(base), size, @@ -11700,7 +11674,7 @@ void CheckStorageTextureAccessPermissions() { "fixed VirtualAlloc failed"); ResourceMutex resource_mutex; PageManager page_manager(CacheFault, nullptr); - BufferCache buffer_cache(page_manager, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); page_manager.OnGpuMap(base, size, GpuAccess::ReadWrite); buffer_cache.ValidateGpuAccess(base, size, true, true); page_manager.OnGpuUnmap(base, size, GpuAccess::ReadWrite); @@ -11737,6 +11711,7 @@ void CheckStorageTextureAccessPermissions() { } [[noreturn]] void RunMetaOverlapDeathCase(const char *kind) { + GraphicContext context{}; constexpr uint64_t address = 0x0000000200010000ull; constexpr uint64_t allocation_size = 0x10000; auto *memory = static_cast( @@ -11747,23 +11722,23 @@ void CheckStorageTextureAccessPermissions() { } ResourceMutex resource_mutex; PageManager page_manager(CacheFault, nullptr); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); + TextureCache texture_cache(context, page_manager, buffer_cache, + resource_mutex); buffer_cache.SetTextureCache(texture_cache); page_manager.OnGpuMap(address, allocation_size); - auto *ctx = reinterpret_cast(1); - texture_cache.RegisterMeta(ctx, address, 0x8000); + texture_cache.RegisterMeta(address, 0x8000); if (std::strcmp(kind, "metadata-size") == 0) { - texture_cache.RegisterMeta(ctx, address, 0x10000); + texture_cache.RegisterMeta(address, 0x10000); } else if (std::strcmp(kind, "texture") == 0) { ImageInfo info{}; info.address = address; info.size = 0x1000; info.width = 1; info.height = 1; - (void)texture_cache.FindTexture(reinterpret_cast(1), ctx, - info, false); + (void)texture_cache.FindTexture(*reinterpret_cast(1), info, + false); } else if (std::strcmp(kind, "render-target") == 0) { RenderTargetInfo info{}; info.address = address; @@ -11774,8 +11749,8 @@ void CheckStorageTextureAccessPermissions() { info.pitch = 1; info.bytes_per_element = 4; info.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kLinear); - (void)texture_cache.FindRenderTarget(reinterpret_cast(1), - ctx, info); + (void)texture_cache.FindRenderTarget(*reinterpret_cast(1), + info); } else if (std::strcmp(kind, "depth-target") == 0) { DepthTargetInfo info{}; info.address = address; @@ -11788,13 +11763,13 @@ void CheckStorageTextureAccessPermissions() { info.pitch = 1; info.bytes_per_element = 2; info.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kDepth); - (void)texture_cache.FindDepthTarget(reinterpret_cast(1), - ctx, info); + (void)texture_cache.FindDepthTarget(*reinterpret_cast(1), + info); } else if (std::strcmp(kind, "copy-stale") == 0) { if (!texture_cache.ClearMeta(address)) { std::_Exit(0x7f); } - buffer_cache.CopyBuffer(nullptr, ctx, address + 0x9000, address, 0x1000); + buffer_cache.CopyBuffer(nullptr, address + 0x9000, address, 0x1000); } else { EXIT("metadata-reuse child received an unknown mode\n"); } @@ -11883,6 +11858,7 @@ void CheckMetaOverlapDeaths() { } void CheckOverlappingMetadataViews() { + GraphicContext context{}; constexpr uintptr_t base = 0x0000000200010000ull; constexpr uint64_t allocation_size = 0x60000; constexpr uint64_t metadata_size = 0x30000; @@ -11897,14 +11873,15 @@ void CheckOverlappingMetadataViews() { ResourceMutex resource_mutex; CacheFaultContext fault_context; PageManager page_manager(CacheFault, &fault_context); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); + TextureCache texture_cache(context, page_manager, buffer_cache, + resource_mutex); fault_context.texture = &texture_cache; buffer_cache.SetTextureCache(texture_cache); page_manager.OnGpuMap(base, allocation_size); - texture_cache.RegisterMeta(nullptr, base, metadata_size); - texture_cache.RegisterMeta(nullptr, second, metadata_size); + texture_cache.RegisterMeta(base, metadata_size); + texture_cache.RegisterMeta(second, metadata_size); Require("OverlappingMetadataViews", "registration", texture_cache.IsMeta(base) && texture_cache.IsMeta(second) && texture_cache.IsMetaRange(base, metadata_size) && @@ -11932,6 +11909,7 @@ void CheckOverlappingMetadataViews() { } void CheckQueryRegionAggregation() { + GraphicContext context{}; constexpr uintptr_t base = 0x0000000200010000ull; constexpr uint64_t allocation_size = 0x10000; constexpr uint64_t metadata_size = 0x180; @@ -11945,8 +11923,9 @@ void CheckQueryRegionAggregation() { ResourceMutex resource_mutex; CacheFaultContext fault_context; PageManager page_manager(CacheFault, &fault_context); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); + TextureCache texture_cache(context, page_manager, buffer_cache, + resource_mutex); fault_context.texture = &texture_cache; buffer_cache.SetTextureCache(texture_cache); page_manager.OnGpuMap(base, allocation_size); @@ -11958,7 +11937,7 @@ void CheckQueryRegionAggregation() { !empty.metadata_bytes && !empty.gpu_metadata_bytes, "empty region reported cached ownership"); - texture_cache.RegisterMeta(nullptr, base, metadata_size); + texture_cache.RegisterMeta(base, metadata_size); const auto bytes = texture_cache.QueryRegion(base + 0x20, 0x40); const auto page_only = texture_cache.QueryRegion(base + 0x400, 0x40); const auto disjoint = texture_cache.QueryRegion(base + 0x1000, 0x40); @@ -11991,6 +11970,7 @@ void CheckQueryRegionAggregation() { } void CheckGpuMetadataReuse() { + GraphicContext context{}; constexpr uintptr_t base = 0x0000000200010000ull; constexpr uint64_t allocation_size = 0x20000; constexpr uint64_t metadata_size = 0x18000; @@ -12005,31 +11985,32 @@ void CheckGpuMetadataReuse() { ResourceMutex resource_mutex; CacheFaultContext fault_context; PageManager page_manager(CacheFault, &fault_context); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); + TextureCache texture_cache(context, page_manager, buffer_cache, + resource_mutex); fault_context.texture = &texture_cache; buffer_cache.SetTextureCache(texture_cache); page_manager.OnGpuMap(base, allocation_size); - texture_cache.RegisterMeta(nullptr, base, metadata_size, layers); + texture_cache.RegisterMeta(base, metadata_size, layers); TextureCache::MetaRangeInfo full_meta{}; TextureCache::MetaRangeInfo slice_meta{}; TextureCache::MetaRangeInfo invalid_meta{}; constexpr uint64_t slice_size = metadata_size / layers; Require("GpuMetadataReuse", "exact metadata ranges", - texture_cache.ResolveMetaRange(base, metadata_size, &full_meta) && + texture_cache.ResolveMetaRange(base, metadata_size, full_meta) && full_meta.metadata_address == base && full_meta.metadata_size == metadata_size && full_meta.full && full_meta.slice == 0 && texture_cache.ResolveMetaRange(base + slice_size, slice_size, - &slice_meta) && + slice_meta) && slice_meta.metadata_address == base && slice_meta.metadata_size == metadata_size && !slice_meta.full && slice_meta.slice == 1 && !texture_cache.ResolveMetaRange(base + 0x1000, slice_size, - &invalid_meta) && + invalid_meta) && !texture_cache.ResolveMetaRange(base + slice_size, slice_size / 2, - &invalid_meta), + invalid_meta), "whole and per-slice metadata ranges were not classified exactly"); Require("GpuMetadataReuse", "clear", texture_cache.ClearMeta(base), "metadata clear setup failed"); @@ -12040,7 +12021,7 @@ void CheckGpuMetadataReuse() { !texture_cache.QueryRegion(base, allocation_size).metadata_bytes, "metadata-only overwrite retained identity or claimed an image " "transition"); - texture_cache.RegisterMeta(nullptr, base, metadata_size, layers); + texture_cache.RegisterMeta(base, metadata_size, layers); Require("GpuMetadataReuse", "re-register", texture_cache.IsMetaRange(base, metadata_size) && texture_cache.ClearMeta(base), @@ -12297,15 +12278,14 @@ void CheckBufferImageWrites() { cleared_depth.depth_load_clear = true; Require( "BufferImageWrite", "cleared depth reinterpretation", - ClassifyDepthTargetOverlap(old_depth, true, false, true, cleared_depth) == + ClassifyDepthTargetOverlap(old_depth, true, false, cleared_depth) == DepthOverlap::DiscardTarget, "exact cleared depth allocation could not discard its old native shape"); cleared_depth.depth_load_clear = false; - Require( - "BufferImageWrite", "loaded depth reinterpretation", - ClassifyDepthTargetOverlap(old_depth, true, false, true, cleared_depth) == - DepthOverlap::Unsupported, - "loaded depth reinterpretation discarded live native contents"); + Require("BufferImageWrite", "loaded depth reinterpretation", + ClassifyDepthTargetOverlap(old_depth, true, false, cleared_depth) == + DepthOverlap::Unsupported, + "loaded depth reinterpretation discarded live native contents"); RenderTargetInfo old_color{}; old_color.address = 0x4a5cb0000ull; old_color.size = 0x10000; @@ -12316,10 +12296,10 @@ void CheckBufferImageWrites() { reinterpreted_color.format = vk::Format::eR32Uint; Require("BufferImageWrite", "clean color format recreation", ClassifyRenderTargetOverlap(old_color, false, false, false, true, - true, reinterpreted_color) == + reinterpreted_color) == RenderTargetOverlap::RetireTarget && ClassifyRenderTargetOverlap(old_color, true, false, true, true, - true, reinterpreted_color) == + reinterpreted_color) == RenderTargetOverlap::Unsupported, "clean equal-base color allocation did not preserve GPU-owned format " "failures"); @@ -12329,20 +12309,19 @@ void CheckBufferImageWrites() { auto shifted_depth = pool_depth; shifted_depth.address = old_depth.address - 0x20000; shifted_depth.stencil_address = old_depth.address; - Require("BufferImageWrite", "shifted depth-plane recreation", - ClassifyDepthTargetOverlap(pool_depth, true, false, true, - shifted_depth) == - DepthOverlap::RecreateTarget && - ClassifyDepthTargetOverlap(pool_depth, true, true, true, - shifted_depth) == - DepthOverlap::Unsupported, - "exact stencil/depth pool reuse did not require clean single-sample " - "recreation"); + Require( + "BufferImageWrite", "shifted depth-plane recreation", + ClassifyDepthTargetOverlap(pool_depth, true, false, shifted_depth) == + DepthOverlap::RecreateTarget && + ClassifyDepthTargetOverlap(pool_depth, true, true, shifted_depth) == + DepthOverlap::Unsupported, + "exact stencil/depth pool reuse did not require clean single-sample " + "recreation"); shifted_depth.samples = 8; Require( "BufferImageWrite", "multisampled depth-plane recreation", - ClassifyDepthTargetOverlap(pool_depth, true, false, true, - shifted_depth) == DepthOverlap::Unsupported, + ClassifyDepthTargetOverlap(pool_depth, true, false, shifted_depth) == + DepthOverlap::Unsupported, "multisampled depth-plane reuse bypassed the unsupported readback guard"); RenderTargetInfo pool_color{}; pool_color.address = shifted_depth.stencil_address; @@ -12351,15 +12330,15 @@ void CheckBufferImageWrites() { Require( "BufferImageWrite", "color/depth pool recreation", CanRecreateRenderTargetForDepth(pool_color, false, false, false, true, - true, shifted_depth) && + shifted_depth) && !CanRecreateRenderTargetForDepth(pool_color, false, true, false, true, - true, shifted_depth), + shifted_depth), "exact color-plane reuse did not require clean single-sample recreation"); pool_color.size *= 2; Require( "BufferImageWrite", "larger color/depth pool recreation", CanRecreateRenderTargetForDepth(pool_color, false, false, false, true, - true, shifted_depth), + shifted_depth), "equal-base page-isolated color allocation was not recreated for depth"); auto contained_depth = shifted_depth; contained_depth.address = pool_color.address + TRACKER_PAGE_SIZE; @@ -12369,17 +12348,17 @@ void CheckBufferImageWrites() { Require( "BufferImageWrite", "contained color/depth pool recreation", CanRecreateRenderTargetForDepth(pool_color, false, false, false, true, - true, contained_depth) && + contained_depth) && !CanRecreateRenderTargetForDepth(pool_color, false, false, false, - true, false, contained_depth) && + false, contained_depth) && !CanRecreateRenderTargetForDepth(pool_color, true, false, false, true, - true, contained_depth), + contained_depth), "contained depth allocation bypassed source or tracker ownership guards"); pool_color.samples = 8; Require( "BufferImageWrite", "multisampled color/depth recreation", !CanRecreateRenderTargetForDepth(pool_color, false, false, false, true, - true, shifted_depth), + shifted_depth), "multisampled color-plane reuse bypassed the unsupported readback guard"); auto multisample_depth = old_depth; multisample_depth.samples = 8; @@ -12404,49 +12383,49 @@ void CheckBufferImageWrites() { color_alias.bytes_per_element = 4; Require("BufferImageWrite", "guest-backed depth to color", CanRecreateDepthForRenderTarget(old_depth, false, false, false, true, - true, color_alias) && + color_alias) && CanRecreateDepthForRenderTarget(old_depth, true, false, true, - true, false, color_alias) && + false, color_alias) && !CanRecreateDepthForRenderTarget(old_depth, true, true, true, - true, true, color_alias), + true, color_alias), "depth-to-color recreation did not require coherent guest ownership"); Require("BufferImageWrite", "guest-current depth to color", - !CanRecreateDepthForRenderTarget(old_depth, false, false, false, true, + !CanRecreateDepthForRenderTarget(old_depth, false, false, false, false, color_alias), "stale guest backing authorized depth-to-color recreation"); auto mismatched_color = color_alias; mismatched_color.address += 0x1000; Require("BufferImageWrite", "mismatched depth to color", !CanRecreateDepthForRenderTarget(old_depth, false, false, false, true, - true, mismatched_color), + mismatched_color), "mismatched depth shape was discarded as a color allocation"); color_alias.address = pool_depth.stencil_address; Require( "BufferImageWrite", "stencil-plane depth to color", CanRecreateDepthForRenderTarget(pool_depth, false, false, false, true, - true, color_alias), + color_alias), "exact stencil-plane reuse was not treated as whole-image recreation"); auto containing_color = color_alias; containing_color.address = pool_depth.stencil_address - 0x40000; containing_color.size = 0x80000; Require("BufferImageWrite", "contained depth allocation to color", CanRecreateDepthForRenderTarget(pool_depth, false, false, false, true, - true, containing_color) && + containing_color) && !CanRecreateDepthForRenderTarget(pool_depth, false, false, false, - true, false, containing_color) && + false, containing_color) && !CanRecreateDepthForRenderTarget(pool_depth, false, false, true, - true, true, containing_color), + true, containing_color), "contained guest-current depth allocation bypassed ownership guards"); TileSizeAlign storage{}; Require("BufferImageWrite", "target layout", TileGetRenderTargetPitch(1920, 4) == 1920 && - TileGetRenderTargetSize(1920, 1080, 1920, 4, &storage) && + TileGetRenderTargetSize(1920, 1080, 1920, 4, storage) && storage.align == 0x10000 && storage.size == target_size, "render-target write fixture has an invalid tiled layout"); Require("BufferImageWrite", "PPSA02721 video layout", TileGetRenderTargetPitch(3840, 4) == 3840 && - TileGetRenderTargetSize(3840, 2160, 3840, 4, &storage) && + TileGetRenderTargetSize(3840, 2160, 3840, 4, storage) && storage.align == 0x10000 && storage.size == video_size, "4K video-out ownership fixture lost its exact tiled layout"); std::printf("[host] %-32s ok\n", "BufferImageWrite"); @@ -12457,15 +12436,15 @@ void CheckImageOverlapResolution() { VideoOutPixelFormatInfo video_format{}; Require( "ImageOverlapResolution", "existing video-out formats", - DecodeVideoOutPixelFormat(0x8000000022000000ull, &video_format) && + DecodeVideoOutPixelFormat(0x8000000022000000ull, video_format) && video_format.format == vk::Format::eR8G8B8A8Srgb && video_format.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb) && - DecodeVideoOutPixelFormat(0x8000000000000000ull, &video_format) && + DecodeVideoOutPixelFormat(0x8000000000000000ull, video_format) && video_format.format == vk::Format::eB8G8R8A8Srgb && video_format.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb) && - DecodeVideoOutPixelFormat(0x8100000022000000ull, &video_format) && + DecodeVideoOutPixelFormat(0x8100000022000000ull, video_format) && video_format.format == vk::Format::eA2B10G10R10UnormPack32 && video_format.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm), @@ -12473,7 +12452,7 @@ void CheckImageOverlapResolution() { "centralization"); Require( "ImageOverlapResolution", "B10G10R10A2 video-out format", - DecodeVideoOutPixelFormat(0x8100000000000000ull, &video_format) && + DecodeVideoOutPixelFormat(0x8100000000000000ull, video_format) && video_format.format == vk::Format::eA2R10G10B10UnormPack32 && video_format.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k10_10_10_2UNorm), @@ -12481,13 +12460,13 @@ void CheckImageOverlapResolution() { "channel order"); Require( "ImageOverlapResolution", "RGBA16 float video-out formats", - DecodeVideoOutPixelFormat(0xc001000622000000ull, &video_format) && + DecodeVideoOutPixelFormat(0xc001000622000000ull, video_format) && video_format.format == vk::Format::eR16G16B16A16Sfloat && video_format.guest_format == Prospero::GpuEnumValue( Prospero::BufferFormat::k16_16_16_16Float) && video_format.bytes_per_element == 8 && - DecodeVideoOutPixelFormat(0xc001000600000000ull, &video_format) && + DecodeVideoOutPixelFormat(0xc001000600000000ull, video_format) && video_format.bgra16, "PS5 RGBA16-float video-out formats lost their 64-bpp storage contract"); VideoOutInfo supported_video_out{}; @@ -12517,9 +12496,8 @@ void CheckImageOverlapResolution() { "video-out format validation admitted a mismatched storage element size"); Require( "ImageOverlapResolution", "video-out format guards", - !DecodeVideoOutPixelFormat(0x8100070400000000ull, &video_format) && - !DecodeVideoOutPixelFormat(0xc001070700000000ull, &video_format) && - !DecodeVideoOutPixelFormat(0x8100000000000000ull, nullptr) && !([&] { + !DecodeVideoOutPixelFormat(0x8100070400000000ull, video_format) && + !DecodeVideoOutPixelFormat(0xc001070700000000ull, video_format) && !([&] { auto mismatched = supported_video_out; mismatched.guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8Srgb); @@ -12532,19 +12510,19 @@ void CheckImageOverlapResolution() { TileGetRenderTargetPitch(1920, 1) == 2048, "R8 target did not use native 256-pixel block width"); Require("ImageOverlapResolution", "R8 render-target size", - TileGetRenderTargetSize(1920, 1080, 2048, 1, &render_target_layout) && + TileGetRenderTargetSize(1920, 1080, 2048, 1, render_target_layout) && render_target_layout.size == 0x280000 && render_target_layout.align == 0x10000, "R8 target did not use native 64-KiB block geometry"); Require( "ImageOverlapResolution", "RGBA8 render-target size", TileGetRenderTargetPitch(1920, 4) == 1920 && - TileGetRenderTargetSize(1920, 1080, 1920, 4, &render_target_layout) && + TileGetRenderTargetSize(1920, 1080, 1920, 4, render_target_layout) && render_target_layout.size == 0x870000, "RGBA8 target layout regressed"); Require("ImageOverlapResolution", "PPSA19268 render-target edge", TileGetRenderTargetPitch(120, 8) == 128 && - TileGetRenderTargetSize(120, 67, 128, 8, &render_target_layout) && + TileGetRenderTargetSize(120, 67, 128, 8, render_target_layout) && render_target_layout.size == 0x20000 && ImageRangeOverlaps(0x11029fff8ull, 1, 0x110280000ull, render_target_layout.size), @@ -12552,14 +12530,14 @@ void CheckImageOverlapResolution() { Require( "ImageOverlapResolution", "render-target layout rejection", TileGetRenderTargetPitch(1920, 3) == 0 && - !TileGetRenderTargetSize(1920, 1080, 1920, 1, &render_target_layout), + !TileGetRenderTargetSize(1920, 1080, 1920, 1, render_target_layout), "unsupported element size or mismatched pitch was admitted"); TileSizeOffset mip_levels[16]{}; TilePaddedSize mip_padded[16]{}; Require( "ImageOverlapResolution", "PPSA09076 mip-chain layout", - TileGetRenderTargetMipLayout(960, 540, 1024, 8, 10, &render_target_layout, + TileGetRenderTargetMipLayout(960, 540, 1024, 8, 10, render_target_layout, mip_levels, mip_padded) && render_target_layout.size == 0x650000 && render_target_layout.align == 0x10000 && @@ -12569,16 +12547,16 @@ void CheckImageOverlapResolution() { "native render-target mip allocation or subresource geometry regressed"); Require( "ImageOverlapResolution", "render-target mip-chain rejection", - !TileGetRenderTargetMipLayout(960, 540, 960, 8, 10, &render_target_layout, + !TileGetRenderTargetMipLayout(960, 540, 960, 8, 10, render_target_layout, nullptr, nullptr) && !TileGetRenderTargetMipLayout( - 960, 540, 1024, 3, 10, &render_target_layout, nullptr, nullptr) && + 960, 540, 1024, 3, 10, render_target_layout, nullptr, nullptr) && !TileGetRenderTargetMipLayout( - 960, 540, 1024, 8, 0, &render_target_layout, nullptr, nullptr) && + 960, 540, 1024, 8, 0, render_target_layout, nullptr, nullptr) && !TileGetRenderTargetMipLayout( - 960, 540, 1024, 8, 17, &render_target_layout, nullptr, nullptr) && + 960, 540, 1024, 8, 17, render_target_layout, nullptr, nullptr) && !TileGetRenderTargetMipLayout(4, 4, TileGetRenderTargetPitch(4, 4), 4, - 4, &render_target_layout, nullptr, + 4, render_target_layout, nullptr, nullptr), "invalid render-target mip topology was admitted"); @@ -12588,17 +12566,13 @@ void CheckImageOverlapResolution() { ImageInfo sampled_alias = sampled; sampled_alias.address += 0x1000; Require("ImageOverlapResolution", "sampled alias", - ClassifySampledOverlap(sampled_alias, sampled, false, true) == + ClassifySampledOverlap(sampled_alias, sampled, false) == SampledOverlap::ReadOnlyAlias, "read-only sampled pool alias was rejected"); Require("ImageOverlapResolution", "sampled GPU owner", - ClassifySampledOverlap(sampled_alias, sampled, true, true) == + ClassifySampledOverlap(sampled_alias, sampled, true) == SampledOverlap::Unsupported, "GPU-modified sampled alias was admitted"); - Require("ImageOverlapResolution", "sampled context", - ClassifySampledOverlap(sampled_alias, sampled, false, false) == - SampledOverlap::Unsupported, - "cross-context sampled alias was admitted"); ImageInfo dirty_info{}; dirty_info.address = 0x500100; dirty_info.size = 0x100; @@ -12651,13 +12625,13 @@ void CheckImageOverlapResolution() { Require("ImageOverlapResolution", "storage retires clean sampled backing", ClassifyStorageImageOverlap(storage_subrange, storage_subrange_size, sampled_backing, sampled_backing_size, - true, true, false, false, false) == + true, false, false, false) == StorageImageOverlap::RetireSampled, "clean sampled subrange was not retired before storage creation"); Require("ImageOverlapResolution", "storage preserves dirty sampled backing", ClassifyStorageImageOverlap(storage_subrange, storage_subrange_size, sampled_backing, sampled_backing_size, - true, true, true, false, + true, true, false, true) == StorageImageOverlap::Unsupported, "GPU-owned sampled subrange was admitted as storage backing"); ImageInfo page_left = sampled; @@ -12668,13 +12642,13 @@ void CheckImageOverlapResolution() { "ImageOverlapResolution", "sampled shared page", !ImageRangeOverlaps(same_page.address, same_page.size, page_left.address, page_left.size) && - ClassifySampledOverlap(same_page, page_left, false, true) == + ClassifySampledOverlap(same_page, page_left, false) == SampledOverlap::ReadOnlyAlias, "byte-disjoint sampled images sharing a tracker page were not aliased"); ImageInfo separate_page = same_page; separate_page.address = page_left.address + TRACKER_PAGE_SIZE; Require("ImageOverlapResolution", "sampled separate page", - ClassifySampledOverlap(separate_page, page_left, false, true) == + ClassifySampledOverlap(separate_page, page_left, false) == SampledOverlap::None, "sampled images on separate pages were aliased"); constexpr uint64_t edge_target_address = 0x108ad00100ull; @@ -12808,7 +12782,7 @@ void CheckImageOverlapResolution() { vk::ClearColorValue clear{}; Require( "ImageOverlapResolution", "RGBA8 compute clear decode", - DecodePackedColorClear(vk::Format::eR8G8B8A8Unorm, 0x80402010u, &clear) && + DecodePackedColorClear(vk::Format::eR8G8B8A8Unorm, 0x80402010u, clear) && std::abs(clear.float32[0] - 16.0f / 255.0f) < 0.000001f && std::abs(clear.float32[1] - 32.0f / 255.0f) < 0.000001f && std::abs(clear.float32[2] - 64.0f / 255.0f) < 0.000001f && @@ -12816,7 +12790,7 @@ void CheckImageOverlapResolution() { "packed RGBA8 clear did not preserve component values"); Require( "ImageOverlapResolution", "BGRA8 compute clear decode", - DecodePackedColorClear(vk::Format::eB8G8R8A8Unorm, 0x80402010u, &clear) && + DecodePackedColorClear(vk::Format::eB8G8R8A8Unorm, 0x80402010u, clear) && std::abs(clear.float32[0] - 64.0f / 255.0f) < 0.000001f && std::abs(clear.float32[1] - 32.0f / 255.0f) < 0.000001f && std::abs(clear.float32[2] - 16.0f / 255.0f) < 0.000001f, @@ -12825,7 +12799,7 @@ void CheckImageOverlapResolution() { 1023u | (512u << 10u) | (1u << 20u) | (3u << 30u); Require("ImageOverlapResolution", "RGB10 compute clear decode", DecodePackedColorClear(vk::Format::eA2B10G10R10UnormPack32, - rgb10_clear, &clear) && + rgb10_clear, clear) && clear.float32[0] == 1.0f && std::abs(clear.float32[1] - 512.0f / 1023.0f) < 0.000001f && std::abs(clear.float32[2] - 1.0f / 1023.0f) < 0.000001f && @@ -12833,38 +12807,36 @@ void CheckImageOverlapResolution() { "packed RGB10 clear did not preserve component values"); Require( "ImageOverlapResolution", "sRGB compute clear decode", - DecodePackedColorClear(vk::Format::eR8G8B8A8Srgb, 0xff808080u, &clear) && + DecodePackedColorClear(vk::Format::eR8G8B8A8Srgb, 0xff808080u, clear) && std::abs(clear.float32[0] - 0.215861f) < 0.00001f && std::abs(clear.float32[1] - 0.215861f) < 0.00001f && std::abs(clear.float32[2] - 0.215861f) < 0.00001f && clear.float32[3] == 1.0f && - !DecodePackedColorClear(vk::Format::eR16G16Unorm, 0, &clear), + !DecodePackedColorClear(vk::Format::eR16G16Unorm, 0, clear), "sRGB clear decode or unsupported-format guard regressed"); uint8_t stencil_clear = 0; Require("ImageOverlapResolution", "stencil compute clear decode", - DecodePackedStencilClear(0x7f7f7f7fu, &stencil_clear) && + DecodePackedStencilClear(0x7f7f7f7fu, stencil_clear) && stencil_clear == 0x7fu && - DecodePackedStencilClear(0, &stencil_clear) && + DecodePackedStencilClear(0, stencil_clear) && stencil_clear == 0 && - !DecodePackedStencilClear(0x0000007fu, &stencil_clear) && - !DecodePackedStencilClear(0, nullptr), + !DecodePackedStencilClear(0x0000007fu, stencil_clear), "packed stencil clear admitted non-uniform byte values"); float depth_clear = -1.0f; Require( "ImageOverlapResolution", "D32 compute clear decode", - DecodePackedDepthClear(vk::Format::eD32Sfloat, 0u, &depth_clear) && + DecodePackedDepthClear(vk::Format::eD32Sfloat, 0u, depth_clear) && depth_clear == 0.0f && DecodePackedDepthClear(vk::Format::eD32SfloatS8Uint, 0x3f800000u, - &depth_clear) && + depth_clear) && depth_clear == 1.0f && - !DecodePackedDepthClear(vk::Format::eD16Unorm, 0u, &depth_clear) && + !DecodePackedDepthClear(vk::Format::eD16Unorm, 0u, depth_clear) && !DecodePackedDepthClear(vk::Format::eD32Sfloat, 0xbf800000u, - &depth_clear) && + depth_clear) && !DecodePackedDepthClear(vk::Format::eD32Sfloat, 0x40000000u, - &depth_clear) && + depth_clear) && !DecodePackedDepthClear(vk::Format::eD32Sfloat, 0x7f800000u, - &depth_clear) && - !DecodePackedDepthClear(vk::Format::eD32Sfloat, 0u, nullptr), + depth_clear), "D32 compute clear decode admitted an unsupported format or value"); DepthTargetInfo native_clear_target{}; native_clear_target.address = 0x1158d80000ull; @@ -12907,11 +12879,11 @@ void CheckImageOverlapResolution() { target.size = sampled.size; Require( "ImageOverlapResolution", "render target reuse", - ClassifyRenderTargetOverlap(sampled, false, true, target) == + ClassifyRenderTargetOverlap(sampled, false, target) == RenderTargetOverlap::RetireSampled, "exact CPU-owned sampled allocation was not retired for a render target"); Require("ImageOverlapResolution", "render target GPU owner", - ClassifyRenderTargetOverlap(sampled, true, true, target) == + ClassifyRenderTargetOverlap(sampled, true, target) == RenderTargetOverlap::Unsupported, "GPU-owned sampled allocation was retired for a render target"); ImageInfo partial_target_sample{}; @@ -12922,17 +12894,14 @@ void CheckImageOverlapResolution() { layered_target.size = 0x60000; Require("ImageOverlapResolution", "sampled partial target transition", ClassifySampledRenderTargetOverlap(partial_target_sample, - layered_target, false, true) == + layered_target, false) == RenderTargetOverlap::RetireTarget, "sampled partial target alias was not routed through readback"); Require("ImageOverlapResolution", "sampled partial target rejection", ClassifySampledRenderTargetOverlap(partial_target_sample, - layered_target, true, true) == - RenderTargetOverlap::Unsupported && - ClassifySampledRenderTargetOverlap( - partial_target_sample, layered_target, false, false) == - RenderTargetOverlap::Unsupported, - "buffer-owned or cross-context target alias was admitted"); + layered_target, true) == + RenderTargetOverlap::Unsupported, + "buffer-owned target alias was admitted"); ImageInfo storage{}; storage.address = 0x112cd0000ull; @@ -12955,7 +12924,7 @@ void CheckImageOverlapResolution() { storage_target.tile_mode = storage.tile; Require("ImageOverlapResolution", "storage render-target native transition", ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, true, false, false, true, true, + storage, storage_target.format, true, false, false, true, storage_target) == RenderTargetOverlap::PreserveStorage, "exact GPU-owned RGBA16F storage image was not preserved for a " "render target"); @@ -12964,51 +12933,44 @@ void CheckImageOverlapResolution() { partial_storage_target.size = 0x10000; Require("ImageOverlapResolution", "clean storage render-target transition", ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, false, false, false, false, true, + storage, storage_target.format, false, false, false, false, partial_storage_target) == RenderTargetOverlap::RetireStorage, "clean storage allocation was not retired for an overlapping render " "target"); auto mismatched_storage_target = storage_target; mismatched_storage_target.width--; - Require( - "ImageOverlapResolution", "storage render-target guards", - ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, true, true, false, true, true, - storage_target) == RenderTargetOverlap::Unsupported && + Require("ImageOverlapResolution", "storage render-target guards", ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, true, false, true, true, true, + storage, storage_target.format, true, true, false, true, storage_target) == RenderTargetOverlap::Unsupported && - ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, true, false, false, true, false, - storage_target) == RenderTargetOverlap::Unsupported && - ClassifyStorageRenderTargetOverlap( - storage, vk::Format::eR32G32B32A32Sfloat, true, false, false, - true, true, storage_target) == RenderTargetOverlap::Unsupported && - ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, true, false, false, true, true, - mismatched_storage_target) == RenderTargetOverlap::Unsupported && - ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, false, false, false, true, true, - storage_target) == RenderTargetOverlap::Unsupported && - ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, true, false, false, false, true, - storage_target) == RenderTargetOverlap::Unsupported, - "unsupported storage-to-render-target transition was admitted"); + ClassifyStorageRenderTargetOverlap( + storage, storage_target.format, true, false, true, true, + storage_target) == RenderTargetOverlap::Unsupported && + ClassifyStorageRenderTargetOverlap( + storage, vk::Format::eR32G32B32A32Sfloat, true, false, false, + true, storage_target) == RenderTargetOverlap::Unsupported && + ClassifyStorageRenderTargetOverlap(storage, storage_target.format, + true, false, false, true, + mismatched_storage_target) == + RenderTargetOverlap::Unsupported && + ClassifyStorageRenderTargetOverlap( + storage, storage_target.format, false, false, false, true, + storage_target) == RenderTargetOverlap::Unsupported && + ClassifyStorageRenderTargetOverlap( + storage, storage_target.format, true, false, false, false, + storage_target) == RenderTargetOverlap::Unsupported, + "unsupported storage-to-render-target transition was admitted"); partial_storage_target.address = storage.address + storage.size; Require("ImageOverlapResolution", "storage render-target adjacency", ClassifyStorageRenderTargetOverlap( - storage, storage_target.format, false, false, false, false, true, + storage, storage_target.format, false, false, false, false, partial_storage_target) == RenderTargetOverlap::None, "byte-disjoint storage and render-target allocations were treated as " "aliases"); - Require("ImageOverlapResolution", "render target context", - ClassifyRenderTargetOverlap(sampled, false, false, target) == - RenderTargetOverlap::Unsupported, - "cross-context sampled allocation was retired for a render target"); target.address += 0x2000; target.size = 0x2000; Require("ImageOverlapResolution", "render target pool reuse", - ClassifyRenderTargetOverlap(sampled, false, true, target) == + ClassifyRenderTargetOverlap(sampled, false, target) == RenderTargetOverlap::RetireSampled, "page-contained CPU-owned sampled pool was not retired for a render " "target"); @@ -13016,29 +12978,29 @@ void CheckImageOverlapResolution() { target.size = 0x4000; Require( "ImageOverlapResolution", "render target chance overlap", - ClassifyRenderTargetOverlap(sampled, false, true, target) == + ClassifyRenderTargetOverlap(sampled, false, target) == RenderTargetOverlap::RetireSampled, "page-isolated sampled pool overlap was not retired for a render target"); target.address++; Require("ImageOverlapResolution", "render target partial page", - ClassifyRenderTargetOverlap(sampled, false, true, target) == + ClassifyRenderTargetOverlap(sampled, false, target) == RenderTargetOverlap::RetireSampled, "true byte overlap within a partial tracker page was not retired"); target.address = sampled.address + 0x6101; target.size = 0x4000; Require("ImageOverlapResolution", "render target unaligned chance overlap", - ClassifyRenderTargetOverlap(sampled, false, true, target) == + ClassifyRenderTargetOverlap(sampled, false, target) == RenderTargetOverlap::RetireSampled, "unaligned clean sampled chance overlap was not retired"); target.address = page_left.address + page_left.size; target.size = page_left.size; Require("ImageOverlapResolution", "render target shared page", - ClassifyRenderTargetOverlap(page_left, false, true, target) == + ClassifyRenderTargetOverlap(page_left, false, target) == RenderTargetOverlap::None, "byte-disjoint allocation sharing a tracker page was treated as an " "alias"); Require("ImageOverlapResolution", "sampled render-target shared page", - ClassifySampledRenderTargetOverlap(page_left, target, false, true) == + ClassifySampledRenderTargetOverlap(page_left, target, false) == RenderTargetOverlap::None, "reverse byte-disjoint tracker-page relationship was treated as an " "alias"); @@ -13046,7 +13008,7 @@ void CheckImageOverlapResolution() { target.size = sampled.size; Require( "ImageOverlapResolution", "render target adjacent", - ClassifyRenderTargetOverlap(sampled, false, true, target) == + ClassifyRenderTargetOverlap(sampled, false, target) == RenderTargetOverlap::None, "adjacent sampled and render-target allocations were treated as aliases"); @@ -13068,30 +13030,25 @@ void CheckImageOverlapResolution() { replacement_target.bytes_per_element = 8; Require("ImageOverlapResolution", "render target allocation-pool replacement", ClassifyRenderTargetOverlap(old_target, false, false, false, true, - true, replacement_target) == + replacement_target) == RenderTargetOverlap::RetireTarget, "clean same-base render-target pool allocation was not retired"); Require("ImageOverlapResolution", "render target allocation-pool GPU owner", - ClassifyRenderTargetOverlap(old_target, true, false, true, true, true, + ClassifyRenderTargetOverlap(old_target, true, false, true, true, replacement_target) == RenderTargetOverlap::Unsupported, "GPU-owned render-target pool allocation was retired"); Require("ImageOverlapResolution", "render target allocation-pool buffer owner", ClassifyRenderTargetOverlap(old_target, false, true, false, true, - true, replacement_target) == + replacement_target) == RenderTargetOverlap::Unsupported, "buffer-dirty render-target pool allocation was retired"); - Require("ImageOverlapResolution", "render target allocation-pool context", - ClassifyRenderTargetOverlap(old_target, false, false, false, false, - true, replacement_target) == - RenderTargetOverlap::Unsupported, - "cross-context render-target pool allocation was retired"); auto offset_target = replacement_target; offset_target.address += TRACKER_PAGE_SIZE; Require("ImageOverlapResolution", "render target allocation-pool offset", ClassifyRenderTargetOverlap(old_target, false, false, false, true, - true, offset_target) == + offset_target) == RenderTargetOverlap::RetireTarget, "clean offset render-target allocation was not retired"); auto contained_target = old_target; @@ -13100,9 +13057,9 @@ void CheckImageOverlapResolution() { Require("ImageOverlapResolution", "render target contained allocation-pool reuse", ClassifyRenderTargetOverlap(old_target, false, false, false, true, - true, contained_target) == + contained_target) == RenderTargetOverlap::RetireTarget && - ClassifyRenderTargetOverlap(old_target, false, false, false, true, + ClassifyRenderTargetOverlap(old_target, false, false, false, false, contained_target) == RenderTargetOverlap::Unsupported, "contained render-target allocation bypassed guest ownership guards"); @@ -13111,7 +13068,7 @@ void CheckImageOverlapResolution() { Require("ImageOverlapResolution", "render target allocation-pool partial page", ClassifyRenderTargetOverlap(old_target, false, false, false, true, - true, partial_page_target) == + partial_page_target) == RenderTargetOverlap::Unsupported, "partially shared tracker page was treated as allocation-pool " "replacement"); @@ -13123,7 +13080,7 @@ void CheckImageOverlapResolution() { "view"); Require("ImageOverlapResolution", "render target sRGB no retirement", ClassifyRenderTargetOverlap(old_target, false, false, false, true, - true, same_shape_target) == + same_shape_target) == RenderTargetOverlap::Unsupported, "compatible render-target view fell through to target retirement"); auto incompatible_same_shape_target = same_shape_target; @@ -13132,7 +13089,6 @@ void CheckImageOverlapResolution() { !IsCompatibleRenderTargetView(old_target, incompatible_same_shape_target) && ClassifyRenderTargetOverlap(old_target, false, false, false, true, - true, incompatible_same_shape_target) == RenderTargetOverlap::RetireTarget, "clean incompatible render-target format was not recreated"); @@ -13158,53 +13114,46 @@ void CheckImageOverlapResolution() { adjacent_target.address = old_target.address + old_target.size; Require( "ImageOverlapResolution", "render target allocation-pool adjacent", - ClassifyRenderTargetOverlap(old_target, false, false, false, true, true, + ClassifyRenderTargetOverlap(old_target, false, false, false, true, adjacent_target) == RenderTargetOverlap::None, "adjacent render targets were treated as allocation-pool replacement"); Require("ImageOverlapResolution", "metadata retains sampled image", - ClassifyMetaImageOverlap(true, false, false, false, false, true) == + ClassifyMetaImageOverlap(true, false, false, false, false) == MetaImageOverlap::RetainSampled, "CPU-current sampled metadata alias was rejected"); Require("ImageOverlapResolution", "metadata retires writable image", - ClassifyMetaImageOverlap(false, true, false, false, false, true) == + ClassifyMetaImageOverlap(false, true, false, false, false) == MetaImageOverlap::RetireImage, "guest-current writable image was not retired for metadata reuse"); Require("ImageOverlapResolution", "metadata rejects GPU target", - ClassifyMetaImageOverlap(false, true, true, false, false, true) == + ClassifyMetaImageOverlap(false, true, true, false, false) == MetaImageOverlap::Unsupported && - ClassifyMetaImageOverlap(false, true, false, true, false, true) == + ClassifyMetaImageOverlap(false, true, false, true, false) == MetaImageOverlap::Unsupported && - ClassifyMetaImageOverlap(false, true, false, false, true, true) == + ClassifyMetaImageOverlap(false, true, false, false, true) == MetaImageOverlap::Unsupported, "unordered or dirty writable image was admitted for metadata " "reuse"); Require("ImageOverlapResolution", "metadata rejects unsupported image", - ClassifyMetaImageOverlap(false, false, false, false, false, true) == + ClassifyMetaImageOverlap(false, false, false, false, false) == MetaImageOverlap::Unsupported, "unsupported cached image kind was admitted for metadata reuse"); - Require("ImageOverlapResolution", "metadata rejects cross-context target", - ClassifyMetaImageOverlap(false, true, false, false, false, false) == - MetaImageOverlap::Unsupported, - "cross-context writable image was retired for metadata reuse"); Require( "ImageOverlapResolution", "guest-current depth metadata pool reuse", CanRetireGuestCurrentDepthForMetadataReuse(false, false, false, false, - false, 0, true), + false, 0), "guest-current depth owner was not retired when its HTile allocation was " "reused"); - Require( - "ImageOverlapResolution", "depth metadata pool ownership guards", - !CanRetireGuestCurrentDepthForMetadataReuse(true, false, true, false, - false, 0, true) && - !CanRetireGuestCurrentDepthForMetadataReuse(false, true, false, false, - false, 0, true) && - !CanRetireGuestCurrentDepthForMetadataReuse(false, false, false, true, - true, 1, true) && - !CanRetireGuestCurrentDepthForMetadataReuse(false, false, false, - false, false, 0, false), - "GPU-owned, buffer-owned, cleared, or cross-context HTile metadata was " - "admitted for pool reuse"); + Require("ImageOverlapResolution", "depth metadata pool ownership guards", + !CanRetireGuestCurrentDepthForMetadataReuse(true, false, true, false, + false, 0) && + !CanRetireGuestCurrentDepthForMetadataReuse(false, true, false, + false, false, 0) && + !CanRetireGuestCurrentDepthForMetadataReuse(false, false, false, + true, true, 1), + "GPU-owned, buffer-owned, or cleared HTile metadata was " + "admitted for pool reuse"); ImageInfo pooled_sampled{}; pooled_sampled.address = 0x71141000; @@ -13215,20 +13164,17 @@ void CheckImageOverlapResolution() { pooled_depth.stencil_address = 0x71170000; pooled_depth.stencil_size = 0x10000; Require("ImageOverlapResolution", "guest-current sampled/depth pool alias", - CanRetireGuestCurrentDepthForSampled( - pooled_sampled, pooled_depth, false, false, false, false, true), + CanRetireGuestCurrentDepthForSampled(pooled_sampled, pooled_depth, + false, false, false, false), "guest-current contained depth target was not retired for a sampled " "allocation"); - Require( - "ImageOverlapResolution", "sampled/depth pool ownership guards", - !CanRetireGuestCurrentDepthForSampled(pooled_sampled, pooled_depth, true, - false, true, true, true) && - !CanRetireGuestCurrentDepthForSampled( - pooled_sampled, pooled_depth, false, true, false, false, true) && - !CanRetireGuestCurrentDepthForSampled( - pooled_sampled, pooled_depth, false, false, false, false, false), - "GPU-owned, buffer-owned, or cross-context sampled/depth alias was " - "admitted"); + Require("ImageOverlapResolution", "sampled/depth pool ownership guards", + !CanRetireGuestCurrentDepthForSampled(pooled_sampled, pooled_depth, + true, false, true, true) && + !CanRetireGuestCurrentDepthForSampled( + pooled_sampled, pooled_depth, false, true, false, false), + "GPU-owned or buffer-owned sampled/depth alias was " + "admitted"); ImageInfo offset_sampled{}; offset_sampled.address = 0x6c6cd000; offset_sampled.size = 0x10000; @@ -13236,28 +13182,21 @@ void CheckImageOverlapResolution() { offset_depth.address = 0x6c6d0000; offset_depth.size = 0x10000; Require("ImageOverlapResolution", "guest-current sampled to depth pool alias", - CanRetireGuestCurrentSampledForDepth(offset_sampled, offset_depth, - false, false, false, false, true, - true), + CanRetireGuestCurrentSampledForDepth( + offset_sampled, offset_depth, false, false, false, false, true), "offset guest-current sampled allocation was not retired for depth " "reuse"); Require( "ImageOverlapResolution", "sampled to depth pool ownership guards", !CanRetireGuestCurrentSampledForDepth(offset_sampled, offset_depth, true, - false, false, true, true, true) && - !CanRetireGuestCurrentSampledForDepth(offset_sampled, offset_depth, - false, true, false, false, true, - true) && - !CanRetireGuestCurrentSampledForDepth(offset_sampled, offset_depth, - false, false, true, false, true, - true) && - !CanRetireGuestCurrentSampledForDepth(offset_sampled, offset_depth, - false, false, false, false, - false, true) && - !CanRetireGuestCurrentSampledForDepth(offset_sampled, offset_depth, - false, false, false, false, - true, false), - "dirty, cross-context, or stale sampled allocation was admitted for " + false, false, true, true) && + !CanRetireGuestCurrentSampledForDepth( + offset_sampled, offset_depth, false, true, false, false, true) && + !CanRetireGuestCurrentSampledForDepth( + offset_sampled, offset_depth, false, false, true, false, true) && + !CanRetireGuestCurrentSampledForDepth( + offset_sampled, offset_depth, false, false, false, false, false), + "dirty or stale sampled allocation was admitted for " "depth reuse"); const std::array isolated_retirement{ @@ -13290,11 +13229,11 @@ void CheckImageOverlapResolution() { mip_owners.Register(2, {{mip_zero_address, mip_zero_size}}) && ClassifyStorageImageOverlap(mip_one_address, mip_one_size, mip_chain_address, mip_chain_size, - true, true, false, false, false) == + true, false, false, false) == StorageImageOverlap::RetireSampled && ClassifyStorageImageOverlap(mip_one_address, mip_one_size, mip_zero_address, mip_zero_size, true, - true, false, false, + false, false, false) == StorageImageOverlap::None, "captured full-chain and disjoint mip owners were misclassified"); std::vector mip_releases; @@ -13564,7 +13503,7 @@ void CheckNativeMsaaState() { const auto color_pitch = TileGetRenderTargetPitch(1920, 8, 3); Require("NativeMsaaState", "8x color footprint", color_pitch == 1920 && - TileGetRenderTargetSize(1920, 1080, color_pitch, 8, &color, 3) && + TileGetRenderTargetSize(1920, 1080, color_pitch, 8, color, 3) && color.align == 0x10000 && color.size == 0x07f80000, "8x R16G16B16A16 color footprint was not preserved"); @@ -13576,8 +13515,7 @@ void CheckNativeMsaaState() { TileGetDepthSize( 1920, 1080, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F), - Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), true, - &stencil, &htile, &depth, 3) && + Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), true, stencil, htile, depth, 3) && depth.align == 0x10000 && depth.size == 0x03fc0000 && stencil.align == 0x10000 && stencil.size == 0x010e0000 && htile.align == 0x8000 && htile.size == 0x00030000, @@ -13665,7 +13603,7 @@ void CheckDepthTargetFootprints() { TileGetDepthSize(1920, 1080, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16), Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), - false, &stencil, &htile, &depth) && + false, stencil, htile, depth) && depth.size == 0x480000 && depth.align == 0x10000 && stencil.size == 0x280000 && stencil.align == 0x10000 && htile.size == 0, @@ -13776,8 +13714,7 @@ void CheckDepthTargetFootprints() { Require("DepthTargetFootprints", "640x360 Z32S8 without HTile", TileGetDepthSize( 640, 360, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F), - Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), false, - &stencil, &htile, &depth), + Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), false, stencil, htile, depth), "valid non-HTile depth/stencil footprint was rejected"); Require( "DepthTargetFootprints", "640x360 Prospero block sizes", @@ -13792,8 +13729,7 @@ void CheckDepthTargetFootprints() { TileSizeAlign texture_depth{}; TileGetTextureTotalSize( Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 640, 360, 1, - depth_pitch, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth), false, - &texture_depth); + depth_pitch, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth), false, texture_depth); Require("DepthTargetFootprints", "640x360 generic depth tile", depth_pitch == 640 && texture_depth.size == 0xf0000 && texture_depth.align == 0x10000, @@ -13804,7 +13740,7 @@ void CheckDepthTargetFootprints() { TileGetDepthSize(960, 540, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F), Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), - true, &stencil, &htile, &depth) && + true, stencil, htile, depth) && depth.size == 0x280000 && depth.align == 0x10000 && stencil.size == 0xc0000 && stencil.align == 0x10000 && htile.size == 0x10000 && htile.align == 0x8000, @@ -13814,7 +13750,7 @@ void CheckDepthTargetFootprints() { TileGetDepthSize(1280, 720, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F), Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), - true, &stencil, &htile, &depth) && + true, stencil, htile, depth) && depth.size == 0x3c0000 && stencil.size == 0xf0000 && htile.size == 0x20000, "validated 1280x720 HTile footprint regressed"); @@ -13823,7 +13759,7 @@ void CheckDepthTargetFootprints() { TileGetDepthSize(3840, 2160, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F), Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), - true, &stencil, &htile, &depth) && + true, stencil, htile, depth) && depth.size == 0x1fe0000 && depth.align == 0x10000 && stencil.size == 0x870000 && stencil.align == 0x10000 && htile.size == 0xa0000 && htile.align == 0x8000, @@ -13833,23 +13769,21 @@ void CheckDepthTargetFootprints() { "DepthTargetFootprints", "invalid depth format", !TileGetDepthSize(960, 540, 0, 2, Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), - true, &stencil, &htile, &depth), + true, stencil, htile, depth), "unsupported depth format was silently admitted"); Require("DepthTargetFootprints", "invalid stencil format", !TileGetDepthSize( 960, 540, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F), - 2, true, &stencil, &htile, &depth), + 2, true, stencil, htile, depth), "unsupported stencil format was silently admitted"); Require("DepthTargetFootprints", "invalid extent", !TileGetDepthSize( 0, 540, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F), - Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), true, - &stencil, &htile, &depth) && + Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), true, stencil, htile, depth) && !TileGetDepthSize( 16385, 540, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F), - Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), true, - &stencil, &htile, &depth), + Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), true, stencil, htile, depth), "invalid HTile extent was silently admitted"); std::printf("[host] %-32s ok\n", "DepthTargetFootprints"); } @@ -13877,7 +13811,7 @@ void CheckHtileClearTargetResolution() { HtileClearTarget resolved{}; Require("HtileClearTargetResolution", "PPSA09076 descriptor-backed Z16 target", - ResolveHtileClearTarget(descriptor_backed, 0x8000, &resolved) && + ResolveHtileClearTarget(descriptor_backed, 0x8000, resolved) && resolved.address == 0xc1a98000 && resolved.size == 0x8000, "valid descriptor-proven Z16 HTile clear target was rejected"); @@ -13890,10 +13824,10 @@ void CheckHtileClearTargetResolution() { mismatched_write.z_write_base_addr += 0x10000; Require( "HtileClearTargetResolution", "descriptor-backed rejection boundaries", - !ResolveHtileClearTarget(descriptor_backed, 0x4000, &resolved) && - !ResolveHtileClearTarget(partial_extent, 0x8000, &resolved) && - !ResolveHtileClearTarget(missing_stencil, 0x8000, &resolved) && - !ResolveHtileClearTarget(mismatched_write, 0x8000, &resolved), + !ResolveHtileClearTarget(descriptor_backed, 0x4000, resolved) && + !ResolveHtileClearTarget(partial_extent, 0x8000, resolved) && + !ResolveHtileClearTarget(missing_stencil, 0x8000, resolved) && + !ResolveHtileClearTarget(mismatched_write, 0x8000, resolved), "ambiguous or inconsistent descriptor-backed HTile target was admitted"); HW::DepthRenderTarget derived{}; @@ -13917,13 +13851,12 @@ void CheckHtileClearTargetResolution() { Require( "HtileClearTargetResolution", "derived Z32S8 target", TileGetDepthSize(960, 540, 0, derived.z_info.format, - derived.stencil_info.format, true, &stencil_size, - &htile_size, &depth_size) && - ResolveHtileClearTarget(derived, htile_size.size, &resolved) && + derived.stencil_info.format, true, stencil_size, htile_size, depth_size) && + ResolveHtileClearTarget(derived, htile_size.size, resolved) && resolved.address == derived.htile_data_base_addr && resolved.size == htile_size.size && - !ResolveHtileClearTarget(derived, htile_size.size + 0x8000, - &resolved), + !ResolveHtileClearTarget(derived, htile_size.size + 0x8000, + resolved), "extent-derived HTile validation or descriptor cross-check regressed"); auto derived_z16 = derived; @@ -13936,10 +13869,9 @@ void CheckHtileClearTargetResolution() { Require( "HtileClearTargetResolution", "derived Z16 depth-only target", TileGetDepthSize(960, 540, 0, derived_z16.z_info.format, - derived_z16.stencil_info.format, true, &stencil_size, - &htile_size, &depth_size) && + derived_z16.stencil_info.format, true, stencil_size, htile_size, depth_size) && stencil_size.align == 0 && stencil_size.size == 0 && - ResolveHtileClearTarget(derived_z16, htile_size.size, &resolved) && + ResolveHtileClearTarget(derived_z16, htile_size.size, resolved) && resolved.address == derived_z16.htile_data_base_addr && resolved.size == htile_size.size, "extent-derived Z16 depth-only HTile target was rejected"); @@ -13950,10 +13882,9 @@ void CheckHtileClearTargetResolution() { Require( "HtileClearTargetResolution", "derived Z16S8 target", TileGetDepthSize(960, 540, 0, derived_z16s8.z_info.format, - derived_z16s8.stencil_info.format, true, &stencil_size, - &htile_size, &depth_size) && + derived_z16s8.stencil_info.format, true, stencil_size, htile_size, depth_size) && stencil_size.size != 0 && stencil_size.align == 0x10000 && - ResolveHtileClearTarget(derived_z16s8, htile_size.size, &resolved) && + ResolveHtileClearTarget(derived_z16s8, htile_size.size, resolved) && resolved.address == derived_z16s8.htile_data_base_addr && resolved.size == htile_size.size, "extent-derived Z16S8 HTile target was rejected"); @@ -13963,12 +13894,12 @@ void CheckHtileClearTargetResolution() { auto malformed_fragments = derived; malformed_fragments.z_info.num_samples = 4; Require("HtileClearTargetResolution", "fragment-independent metadata plane", - ResolveHtileClearTarget(derived_8x, htile_size.size, &resolved) && + ResolveHtileClearTarget(derived_8x, htile_size.size, resolved) && resolved.address == derived_8x.htile_data_base_addr && resolved.size == htile_size.size && render_sample_count(derived_8x.z_info.num_samples) == 8 && - !ResolveHtileClearTarget(malformed_fragments, htile_size.size, - &resolved), + !ResolveHtileClearTarget(malformed_fragments, htile_size.size, + resolved), "HTile clear was coupled to attachment MSAA support or admitted an " "invalid fragment field"); std::printf("[host] %-32s ok\n", "HtileClearTargetResolution"); @@ -14008,6 +13939,7 @@ void CheckCrossQueueImageLifetime() { } void CheckHostDmaMetadataReuse() { + GraphicContext context{}; constexpr uintptr_t base = 0x0000000200010000ull; constexpr uint64_t allocation_size = 0x10000; constexpr uint64_t metadata_size = 0x8000; @@ -14022,13 +13954,13 @@ void CheckHostDmaMetadataReuse() { ResourceMutex resource_mutex; CacheFaultContext fault_context; PageManager page_manager(CacheFault, &fault_context); - BufferCache buffer_cache(page_manager, resource_mutex); - TextureCache texture_cache(page_manager, buffer_cache, resource_mutex); + BufferCache buffer_cache(context, page_manager, resource_mutex); + TextureCache texture_cache(context, page_manager, buffer_cache, + resource_mutex); fault_context.texture = &texture_cache; buffer_cache.SetTextureCache(texture_cache); page_manager.OnGpuMap(base, allocation_size); - auto *ctx = reinterpret_cast(1); - texture_cache.RegisterMeta(ctx, base, metadata_size); + texture_cache.RegisterMeta(base, metadata_size); Require("HostDmaMetadataReuse", "clear", texture_cache.ClearMeta(base), "metadata clear setup failed"); @@ -14040,14 +13972,14 @@ void CheckHostDmaMetadataReuse() { Require("HostDmaMetadataReuse", "copy fault", page_manager.HandleFault(PageFaultAccess::Write, base), "copy destination did not transfer to CPU ownership"); - buffer_cache.CopyBuffer(nullptr, ctx, base, base + metadata_size, 0x1000); + buffer_cache.CopyBuffer(nullptr, base, base + metadata_size, 0x1000); Require("HostDmaMetadataReuse", "copy", std::memcmp(memory, memory + metadata_size, 0x1000) == 0, "post-clear CPU DMA copy did not publish backing"); Require("HostDmaMetadataReuse", "fill fault", page_manager.HandleFault(PageFaultAccess::Write, base + 0x1000), "fill destination did not transfer to CPU ownership"); - buffer_cache.FillBuffer(nullptr, ctx, base + 0x1000, 0x1000, 0x11223344); + buffer_cache.FillBuffer(nullptr, base + 0x1000, 0x1000, 0x11223344); Require("HostDmaMetadataReuse", "fill", reinterpret_cast(memory + 0x1000)[0] == 0x11223344 && reinterpret_cast(memory + 0x1ffc)[0] == 0x11223344, @@ -14099,7 +14031,7 @@ void CheckEmbeddedFetchLaneSpill() { ShaderRecompiler::CompileResult result; std::string error; Require("EmbeddedFetchLaneSpill", "compile", - ShaderRecompiler::TryRecompile(code, options, &result, &error), + ShaderRecompiler::TryRecompile(code, options, result, &error), error); Require("EmbeddedFetchLaneSpill", "fetch rewrite", vertex.resource_fetch_components[0] == 4, @@ -14110,25 +14042,24 @@ void CheckEmbeddedFetchLaneSpill() { void CheckReferenceClockScale() { uint64_t value = 0; Require("ReferenceClockScale", "zero", - Sync::ScaleReferenceClock(0, 3000000000ull, &value) && value == 0, + Sync::ScaleReferenceClock(0, 3000000000ull, value) && value == 0, "zero host tick did not produce a zero GPU clock"); Require("ReferenceClockScale", "fractional second", - Sync::ScaleReferenceClock(1500000000ull, 3000000000ull, &value) && + Sync::ScaleReferenceClock(1500000000ull, 3000000000ull, value) && value == 50000000ull, "host half-second did not scale to 50,000,000 ticks"); Require("ReferenceClockScale", "whole and fractional", - Sync::ScaleReferenceClock(3750000000ull, 3000000000ull, &value) && + Sync::ScaleReferenceClock(3750000000ull, 3000000000ull, value) && value == 125000000ull, "host 1.25 seconds did not scale to 125,000,000 ticks"); Require("ReferenceClockScale", "monotonic floor", - Sync::ScaleReferenceClock(3750000001ull, 3000000000ull, &value) && + Sync::ScaleReferenceClock(3750000001ull, 3000000000ull, value) && value == 125000000ull, "sub-reference-tick increment did not use a monotonic floor"); Require("ReferenceClockScale", "guards", - !Sync::ScaleReferenceClock(1, 0, &value) && - !Sync::ScaleReferenceClock(1, 1, nullptr) && - !Sync::ScaleReferenceClock(UINT64_MAX, 1, &value), - "invalid frequency, destination, or overflow was accepted"); + !Sync::ScaleReferenceClock(1, 0, value) && + !Sync::ScaleReferenceClock(UINT64_MAX, 1, value), + "invalid frequency or overflow was accepted"); std::printf("[host] %-32s ok\n", "ReferenceClockScale"); } diff --git a/tests/ShaderStageRuntimeTests.cpp b/tests/ShaderStageRuntimeTests.cpp index 746e20ca3..586c23653 100644 --- a/tests/ShaderStageRuntimeTests.cpp +++ b/tests/ShaderStageRuntimeTests.cpp @@ -58,7 +58,7 @@ void TestMappedSrtUsesDirectReaderByDefault() { auto cached_program = SrtProgram(reinterpret_cast(&dword)); ShaderStageRuntime stage; std::string error; - Check(ShaderMaterializeStageRuntime(cached_program, {}, 0, &stage, &error), error.c_str()); + Check(ShaderMaterializeStageRuntime(cached_program, {}, 0, stage, &error), error.c_str()); Check(stage.program == cached_program && stage.resources != nullptr, "cache rematerialization did not publish the mapped stage"); Check(stage.resources->flattened_srt.size() == 1 && @@ -73,7 +73,7 @@ void TestUnbasedFlatCacheHitFailsClosed() { auto prior_resources = std::make_shared(); ShaderStageRuntime stage {prior_program, prior_resources}; std::string error; - Check(!ShaderMaterializeStageRuntime(cached_program, {}, 0, &stage, &error) && + Check(!ShaderMaterializeStageRuntime(cached_program, {}, 0, stage, &error) && error.find("requires runtime guest-address translation") != std::string::npos, "unbased FLAT cache hit did not fail without a runtime translator"); Check(stage.program == prior_program && stage.resources == prior_resources, diff --git a/tests/ShaderVertexMetadataTests.cpp b/tests/ShaderVertexMetadataTests.cpp index d6a710a75..dcd30fa40 100644 --- a/tests/ShaderVertexMetadataTests.cpp +++ b/tests/ShaderVertexMetadataTests.cpp @@ -40,7 +40,7 @@ void CheckRejected(const ShaderMappedData& data, const char* text) { output.vertex_attrib_reg = 41; output.input_semantics_count = 7; std::string error; - Check(!ShaderReadVertexMetadata(data, 64, &output, &error), text); + Check(!ShaderReadVertexMetadata(data, 64, output, &error), text); Check(!error.empty(), "metadata rejection omitted its diagnostic"); Check(output.vertex_buffer_reg == 37 && output.vertex_attrib_reg == 41 && output.input_semantics_count == 7, @@ -51,7 +51,7 @@ void TestValidAndInvalidMetadata() { Fixture fixture; ShaderVertexMetadata output; std::string error; - Check(ShaderReadVertexMetadata(fixture.mapped, 64, &output, &error), + Check(ShaderReadVertexMetadata(fixture.mapped, 64, output, &error), "valid AGC vertex metadata was rejected"); Check(output.vertex_buffer_reg == 2 && output.vertex_attrib_reg == 4 && output.input_semantics_count == 1, diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index b49f86d89..8d7e25616 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -482,17 +482,20 @@ void TestNativeSubgroupPolicy() { ShaderRecompiler::IR::Program safe; safe.wave_size = 32; safe.lane_mask_mode = ShaderLaneMaskMode::NativeWave; - Check(ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eVertex, safe).mode == + Check(ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eVertex, safe).mode == ShaderSubgroupMode::Natural, "native wave32 policy changed"); safe.wave_size = 64; - Check(SelectGraphicsLaneMaskMode(context, safe.wave_size) == + Check(SelectGraphicsLaneMaskMode(safe.wave_size) == ShaderLaneMaskMode::PerInvocation && - ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eVertex, safe).mode == + ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eVertex, safe).mode == ShaderSubgroupMode::Unsupported, "wave64 graphics mismatch accepted native-wave mask lowering"); safe.lane_mask_mode = ShaderLaneMaskMode::PerInvocation; - Check(ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eVertex, safe).mode == + Check(ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eVertex, safe).mode == ShaderSubgroupMode::PerInvocationGraphics, "wave64 graphics mismatch did not select per-invocation masks"); @@ -500,12 +503,14 @@ void TestNativeSubgroupPolicy() { cross_lane.blocks.emplace_back().instructions.emplace_back().op = ShaderRecompiler::IR::Opcode::ReadLaneU32; Check(ShaderRecompiler::Spirv::ProgramRequiresExactSubgroupSize(cross_lane) && - ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eVertex, cross_lane).mode == + ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eVertex, cross_lane).mode == ShaderSubgroupMode::PerInvocationGraphics, "graphics mismatch did not select per-invocation masks"); auto cross_lane_compute = cross_lane; cross_lane_compute.lane_mask_mode = ShaderLaneMaskMode::NativeWave; - Check(ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eCompute, cross_lane_compute).mode == + Check(ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eCompute, cross_lane_compute).mode == ShaderSubgroupMode::Unsupported, "cross-lane compute mismatch bypassed the exact subgroup requirement"); @@ -521,7 +526,8 @@ void TestNativeSubgroupPolicy() { zero_bfm.src_count = 2; zero_bfm.scalar_sources[0] = 2; Check(!ShaderRecompiler::Spirv::ProgramRequiresExactSubgroupSize(zero_exec) && - ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eCompute, zero_exec).mode == + ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eCompute, zero_exec).mode == ShaderSubgroupMode::FlattenedMasks, "compile-time uniform-zero EXEC write did not stay on the mask-free path"); @@ -552,23 +558,27 @@ void TestNativeSubgroupPolicy() { ds_partial.lane_mask_mode = ShaderLaneMaskMode::NativeWave; ds_partial.blocks.emplace_back().instructions.emplace_back().op = ShaderRecompiler::IR::Opcode::DsAppend; - Check(ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eCompute, ds_partial).mode == + Check(ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eCompute, ds_partial).mode == ShaderSubgroupMode::Unsupported, "partial wave64 DS append bypassed the exact subgroup requirement"); context.max_subgroup_size = 64; const auto controlled = - ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eCompute, cross_lane_compute); + ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eCompute, cross_lane_compute); Check(controlled.mode == ShaderSubgroupMode::Controlled && controlled.required_size == 64, "supported controlled wave64 was not preferred over splitting"); context.subgroup_size = 64; context.subgroup_size_control_enabled = false; cross_lane.wave_size = 32; cross_lane.lane_mask_mode = ShaderLaneMaskMode::PerInvocation; - Check(ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eFragment, cross_lane).mode == + Check(ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eFragment, cross_lane).mode == ShaderSubgroupMode::Unsupported, "inverse graphics mismatch was accepted as one guest wave"); cross_lane_compute.wave_size = 32; - Check(ConfigureShaderSubgroup(context, vk::ShaderStageFlagBits::eCompute, cross_lane_compute).mode == + Check(ConfigureShaderSubgroup(ShaderSubgroupCapabilities {context}, + vk::ShaderStageFlagBits::eCompute, cross_lane_compute).mode == ShaderSubgroupMode::Unsupported, "inverse cross-lane compute mismatch was accepted"); } @@ -781,7 +791,7 @@ void TestNewShaderRecompilerSMovB32() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(!result.spirv.empty(), "new shader recompiler produced no SPIR-V"); Check(result.spirv.front() == 0x07230203u, "new shader recompiler did not emit SPIR-V binary"); Check(Common::ContainsStr(result.decoded_dump, "s_mov_b32 s0, 1"), @@ -818,7 +828,7 @@ void TestNewShaderRecompilerSoppMarkers() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_nop 0x00000003"), "new decoder did not decode SOPP s_nop"); Check(Common::ContainsStr(result.decoded_dump, "s_waitcnt 0x00000000"), @@ -865,7 +875,7 @@ void TestNewShaderRecompilerSopkWaitcntMarkers() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_waitcnt 0"), "new decoder did not decode SOPK waitcnt marker"); Check(Common::ContainsStr(result.decoded_dump, "s_waitcnt 65535"), @@ -895,7 +905,7 @@ void TestNewShaderRecompilerRdna2ScalarOpcodes() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_bitset1_b32 vcc_lo, 0"), "new decoder did not decode RDNA2 S_BITSET1_B32"); Check(Common::ContainsStr(result.decoded_dump, "s_setreg_b32 vcc_lo, 0x00001019"), @@ -959,7 +969,7 @@ void TestNewShaderRecompilerScalarVectorAlu() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_add_u32 s2, s0, s1"), "new decoder did not decode SOP2 add"); Check(Common::ContainsStr(result.decoded_dump, "s_addc_u32 s14, s13, 1"), @@ -1040,7 +1050,7 @@ void TestNewShaderRecompilerVop3LaneReadDestinationEncoding() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "v_readfirstlane_b32 s25, v5"), "VOP3 V_READFIRSTLANE_B32 destination was not decoded from VDST"); Check(Common::ContainsStr(result.decoded_dump, "v_readlane_b32 s26, v5, 2"), @@ -1314,7 +1324,7 @@ void TestNewShaderRecompilerMoreAluFamilies() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_movk_i32 s9"), "new decoder did not decode SOPK mov"); Check(Common::ContainsStr(result.decoded_dump, "s_cmp_gt_u32"), @@ -2020,7 +2030,7 @@ void TestNewShaderRecompilerExpandedAluBatch() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_min_u32"), "new decoder did not decode S_MIN_U32"); Check(Common::ContainsStr(result.decoded_dump, "s_mulk_i32"), @@ -2093,7 +2103,7 @@ void TestNewShaderRecompilerVop3pPackedF16() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "v_pk_add_f16 v114"), "new decoder did not decode old-backed V_PK_ADD_F16"); Check(Common::ContainsStr(result.decoded_dump, "v_pk_mul_f16 v115"), @@ -2211,7 +2221,7 @@ void TestNewShaderRecompilerStagedShaderOps() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_subb_u32 s2, s0, s1"), "new decoder did not decode RDNA2 S_SUBB_U32"); Check(Common::ContainsStr(result.decoded_dump, "s_bitset0_b32 s3, s1"), @@ -2279,7 +2289,7 @@ void TestNewShaderRecompilerBootF16UnaryOpcodes() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "v_sqrt_f16 v4.sdwa(sel=5"), "new decoder did not decode V_SQRT_F16 SDWA high-half destination"); Check(Common::ContainsStr(result.decoded_dump, "v_rndne_f16 v3"), @@ -2372,7 +2382,7 @@ void TestNewShaderRecompilerBootB16PackedAndSdwaOpcodes() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "v_lshrrev_b16 v1.sdwa(sel=4"), "new decoder did not decode low-half V_LSHRREV_B16"); Check(Common::ContainsStr(result.decoded_dump, "v_lshlrev_b16 v5.sdwa(sel=5"), @@ -2509,7 +2519,7 @@ void TestNewShaderRecompilerScalarB64Alu() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_mov_b64 s2, s0"), "new decoder did not decode old-backed S_MOV_B64"); Check(Common::ContainsStr(result.decoded_dump, "s_not_b32 s41, s0"), @@ -2662,7 +2672,7 @@ void TestNewShaderRecompilerSignedCompareAlu() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_cmp_gt_i32"), "new decoder did not decode SOPC signed compare"); Check(Common::ContainsStr(result.decoded_dump, "s_cmp_lt_i32"), @@ -2718,7 +2728,7 @@ void TestNewShaderRecompilerSignedMinShiftAlu() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_min_i32"), "new decoder did not decode S_MIN_I32"); Check(Common::ContainsStr(result.decoded_dump, "s_ashr_i32"), @@ -2768,7 +2778,7 @@ void TestNewShaderRecompilerScalarBitfieldAlu() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_cselect_b32"), "new decoder did not decode S_CSELECT_B32"); Check(Common::ContainsStr(result.decoded_dump, "s_abs_i32"), @@ -2823,7 +2833,7 @@ void CheckNewDecoderUnsupported(const uint32_t* shader, uint32_t words, const ch ShaderRecompiler::Decoder::Program program; std::string error; const std::span code {shader, words}; - Check(ShaderRecompiler::Decoder::DecodeProgram(code, &program, &error), error.c_str()); + Check(ShaderRecompiler::Decoder::DecodeProgram(code, program, &error), error.c_str()); Check(program.instructions.size() >= 2, "decoder did not return instruction plus endpgm"); const auto text = ShaderRecompiler::Decoder::ProgramToString(program); Check(Common::ContainsStr(text, family), @@ -2835,7 +2845,7 @@ void CheckNewDecoderUnsupported(const uint32_t* shader, uint32_t words, const ch options.stage = ShaderType::Compute; options.dump_ir = true; ShaderRecompiler::CompileResult result; - Check(!ShaderRecompiler::TryRecompile(code, options, &result, &error), + Check(!ShaderRecompiler::TryRecompile(code, options, result, &error), "unsupported opcode unexpectedly lowered without implementation"); Check(Common::ContainsStr(error, "no IR lowering") || Common::ContainsStr(error, "unsupported decoded"), @@ -2874,7 +2884,7 @@ void TestNewShaderRecompilerMemoryFamilyLowering() { ShaderRecompiler::CompileResult result; std::string error; - const auto compiled = ShaderRecompiler::TryRecompile(shader, options, &result, &error); + const auto compiled = ShaderRecompiler::TryRecompile(shader, options, result, &error); Check(compiled, error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_load_dword"), "new decoder did not decode SMEM dword load"); @@ -2937,7 +2947,7 @@ void TestNewShaderRecompilerImageQueryLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_get_lod"), "new decoder did not decode MIMG image get-lod query"); Check(Common::ContainsStr(result.decoded_dump, "dmask=0x3"), @@ -2995,7 +3005,7 @@ void TestNewShaderRecompilerImageSampleVariants() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_sample_l"), "new decoder did not decode IMAGE_SAMPLE_L through shared MIMG path"); Check(Common::ContainsStr(result.decoded_dump, "image_sample_b"), @@ -3077,7 +3087,7 @@ void TestNewShaderRecompilerImageSampleA16SamplerCoords() { ShaderRecompiler::CompileResult result; std::string error; - const auto compiled = ShaderRecompiler::TryRecompile(shader, options, &result, &error); + const auto compiled = ShaderRecompiler::TryRecompile(shader, options, result, &error); Check(compiled, error.c_str()); Check( Common::ContainsStr(result.decoded_dump, "image_dim=3d sample_flags=a16 addr_components=3"), @@ -3120,7 +3130,7 @@ void TestNewShaderRecompilerImageSampleOpcodeAliases() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_sample_a"), "MIMG opcode 0xa0 should decode as image_sample_a alias"); Check(Common::ContainsStr(result.decoded_dump, "image_sample_b_a"), @@ -3156,7 +3166,7 @@ void TestNewShaderRecompilerImageSampleA16ExceptionComponents() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); CheckSpirvBinaryValidates(result.spirv); return result; }; @@ -3265,7 +3275,7 @@ void TestNewShaderRecompilerImageLoadA16UintCoords() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_load"), "A16 IMAGE_LOAD did not decode"); Check(Common::ContainsStr(result.ir_dump, "ImageLoad v20"), "A16 IMAGE_LOAD did not lower to image-load IR"); @@ -3306,7 +3316,7 @@ void TestNewShaderRecompilerPixelImageSampleLodSelection() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); CheckSpirvBinaryValidates(result.spirv); return result; }; @@ -3381,7 +3391,7 @@ void TestNewShaderRecompilerImageViewDimensions() { ShaderRecompiler::CompileResult result; std::string error; - const auto compiled = ShaderRecompiler::TryRecompile(shader, options, &result, &error); + const auto compiled = ShaderRecompiler::TryRecompile(shader, options, result, &error); Check(compiled, error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_dim=2d_array"), "MIMG DIM did not decode 2D-array image view"); @@ -3430,7 +3440,7 @@ void TestNewShaderRecompilerImageGatherVariants() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_gather4_lz"), "new decoder did not decode IMAGE_GATHER4_LZ"); Check(Common::ContainsStr(result.decoded_dump, "image_gather4_lz_o"), @@ -3513,7 +3523,7 @@ void TestNewShaderRecompilerImageLoadVariants() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_load"), "new decoder did not decode MIMG image load"); Check(Common::ContainsStr(result.decoded_dump, "image_load_mip"), @@ -3557,7 +3567,7 @@ void TestNewShaderRecompilerImageStoreLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_store"), "new decoder did not decode MIMG image store"); Check(Common::ContainsStr(result.decoded_dump, "image_store_mip"), @@ -3610,7 +3620,7 @@ void TestNewShaderRecompilerStorageImage3DDescriptorVariant() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_dim=3d"), "MIMG store did not decode the RDNA2 3D instruction dimension"); const auto has_3d_store = std::any_of( @@ -3660,7 +3670,7 @@ void TestNewShaderRecompilerStorageImage2DDescriptorOverridesMimg3D() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_dim=3d"), "test MIMG store should decode as a 3D instruction"); Check(SpirvContainsTypeImage(result.spirv, SpirvDim2D, 0, 2), @@ -3701,7 +3711,7 @@ void TestNewShaderRecompilerImageAtomicLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "image_atomic_add"), "new decoder did not decode MIMG image atomic add"); Check(Common::ContainsStr(result.decoded_dump, "image_atomic_umin"), @@ -3762,7 +3772,7 @@ void TestNewShaderRecompilerVintrpLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "v_interp_p1_f32"), "new decoder did not decode VINTRP P1"); Check(Common::ContainsStr(result.decoded_dump, "v_interp_p2_f32"), @@ -3800,7 +3810,7 @@ void TestNewShaderRecompilerVintrpLowering() { options.pixel_input_info = &remapped_ps_info; ShaderRecompiler::CompileResult remapped_result; - Check(ShaderRecompiler::TryRecompile(remapped_shader, options, &remapped_result, &error), + Check(ShaderRecompiler::TryRecompile(remapped_shader, options, remapped_result, &error), error.c_str()); Check(Common::ContainsStr(remapped_result.ir_dump, "input_attr=2 input_chan=0"), "remapped VINTRP did not preserve raw pixel attribute metadata"); @@ -3823,7 +3833,7 @@ void TestNewShaderRecompilerVintrpLowering() { options.pixel_input_info = &duplicate_ps_info; ShaderRecompiler::CompileResult duplicate_result; - Check(ShaderRecompiler::TryRecompile(duplicate_location_shader, options, &duplicate_result, + Check(ShaderRecompiler::TryRecompile(duplicate_location_shader, options, duplicate_result, &error), error.c_str()); Check(ProgramInputCount(duplicate_result.program, @@ -3847,7 +3857,7 @@ void TestNewShaderRecompilerVintrpLowering() { options.pixel_input_info = &flat_ps_info; ShaderRecompiler::CompileResult flat_result; - Check(ShaderRecompiler::TryRecompile(flat_shader, options, &flat_result, &error), + Check(ShaderRecompiler::TryRecompile(flat_shader, options, flat_result, &error), error.c_str()); Check(SpirvHasDecorationValueWithDecoration(flat_result.spirv, 30u, 0u, 14u), "flat VINTRP input did not emit a Flat decoration"); @@ -3865,7 +3875,7 @@ void TestNewShaderRecompilerVintrpLowering() { options.pixel_input_info = &no_perspective_ps_info; ShaderRecompiler::CompileResult no_perspective_result; - Check(ShaderRecompiler::TryRecompile(flat_shader, options, &no_perspective_result, &error), + Check(ShaderRecompiler::TryRecompile(flat_shader, options, no_perspective_result, &error), error.c_str()); Check(SpirvHasDecorationValueWithDecoration(no_perspective_result.spirv, 30u, 0u, 13u), "no-perspective VINTRP input did not emit a NoPerspective decoration"); @@ -3966,7 +3976,7 @@ void TestNewShaderRecompilerWideMemoryLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_load_dwordx4"), "new decoder did not decode SMEM x4 load"); Check(Common::ContainsStr(result.decoded_dump, "s_buffer_load_dwordx4"), @@ -4047,7 +4057,7 @@ void TestNewShaderRecompilerBufferSignedLoadLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "buffer_load_sbyte"), "new decoder did not decode buffer signed byte load"); Check(Common::ContainsStr(result.decoded_dump, "buffer_load_sshort"), @@ -4084,7 +4094,7 @@ void TestNewShaderRecompilerBufferSubDwordStoreLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "buffer_store_byte"), "new decoder did not decode buffer byte store"); Check(Common::ContainsStr(result.decoded_dump, "buffer_store_short"), @@ -4136,7 +4146,7 @@ void TestNewShaderRecompilerMubufFormatLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "buffer_load_format_x"), "new decoder did not decode MUBUF format-x load"); Check(Common::ContainsStr(result.decoded_dump, "buffer_load_format_xyzw"), @@ -4182,7 +4192,7 @@ void TestNewShaderRecompilerFormattedStoreUsesRuntimeArrayLengthOnly() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(result.resources.buffers.size() == 1 && result.resources.buffers[0].dwords[2] == 5u, "formatted store test did not preserve descriptor NumRecords"); Check(Common::ContainsStr(result.decoded_dump, "buffer_store_format_x"), @@ -4223,7 +4233,7 @@ void TestNewShaderRecompilerTypedBufferLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "tbuffer_load_format_x"), "new decoder did not decode typed buffer format-x load"); Check(Common::ContainsStr(result.decoded_dump, "tbuffer_load_format_xy"), @@ -4276,7 +4286,7 @@ void TestNewShaderRecompilerFlatOldBackedLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "flat_load_ubyte"), "new decoder did not decode old-backed FLAT ubyte load"); Check(Common::ContainsStr(result.ir_dump, "FlatLoadUbyte v9"), @@ -4303,7 +4313,7 @@ void TestNewShaderRecompilerUnbasedFlatRequiresTranslator() { ShaderRecompiler::CompileResult result; std::string error; - Check(!ShaderRecompiler::TryRecompile(shader, options, &result, &error) && + Check(!ShaderRecompiler::TryRecompile(shader, options, result, &error) && Common::ContainsStr(error, "requires runtime guest-address translation"), "unbased FLAT compiled without an explicit translator"); } @@ -4326,7 +4336,7 @@ void TestNewShaderRecompilerFlatSignedLoadLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "flat_load_sbyte"), "new decoder did not decode flat signed byte load"); Check(Common::ContainsStr(result.decoded_dump, "flat_load_sshort"), @@ -4378,7 +4388,7 @@ void TestNewShaderRecompilerFlatStoreLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "flat_store_byte"), "new decoder did not decode flat byte store"); Check(Common::ContainsStr(result.decoded_dump, "flat_store_short"), @@ -4493,7 +4503,7 @@ void TestNewShaderRecompilerAtomicLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "buffer_atomic_swap"), "new decoder did not decode buffer atomic swap"); Check(Common::ContainsStr(result.decoded_dump, "buffer_atomic_add"), @@ -4605,7 +4615,7 @@ void TestNewShaderRecompilerDsReadWrite2Lowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "ds_write2_b32"), "new decoder did not decode old-backed DS write2"); Check(Common::ContainsStr(result.decoded_dump, "ds_read2_b32"), @@ -4671,7 +4681,7 @@ void TestNewShaderRecompilerDsSubDwordLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "ds_write_b8"), "new decoder did not decode DS byte write"); Check(Common::ContainsStr(result.decoded_dump, "ds_write_b16"), @@ -4734,7 +4744,7 @@ void TestNewShaderRecompilerDsWideAndAtomicLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "ds_write_b64"), "new decoder did not decode DS b64 write"); Check(Common::ContainsStr(result.decoded_dump, "ds_write_b96"), @@ -4794,7 +4804,7 @@ void TestNewShaderRecompilerDsSwizzleLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "ds_swizzle_b32"), "new decoder did not decode DS swizzle"); Check(Common::ContainsStr(result.decoded_dump, "offset=31"), @@ -4842,7 +4852,7 @@ void TestNewShaderRecompilerDsAddtidLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "ds_write_addtid_b32"), "new decoder did not decode DS write addtid"); Check(Common::ContainsStr(result.decoded_dump, "ds_read_addtid_b32"), @@ -4877,7 +4887,7 @@ void TestNewShaderRecompilerDsFloatMinMaxLowering() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "ds_min_f32"), "new decoder did not decode DS float min"); Check(Common::ContainsStr(result.decoded_dump, "ds_max_f32"), @@ -4910,7 +4920,7 @@ void TestNewShaderRecompilerCfgStraightLine() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "CFG:"), "CFG dump was not emitted"); Check(Common::ContainsStr(result.ir_dump, "block_0"), "straight-line CFG block missing"); Check(Common::ContainsStr(result.ir_dump, "successors=["), "CFG successors were not dumped"); @@ -4933,7 +4943,7 @@ void TestNewShaderRecompilerCfgIfElse() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "condition=scc1"), "if/else branch condition missing"); Check(SpirvContainsOpcode(result.spirv, 247), "if/else SPIR-V lacks OpSelectionMerge"); @@ -4954,7 +4964,7 @@ void TestNewShaderRecompilerCfgTerminalExitMergePS() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "mode=structured"), "terminal PS branch should stay on structured path"); Check(!Common::ContainsStr(result.ir_dump, "conditional block 0 has no structured merge"), @@ -4978,7 +4988,7 @@ void TestNewShaderRecompilerCfgPostEndTargetMergePS() { ShaderRecompiler::CompileResult result; std::string error; - const bool ok = ShaderRecompiler::TryRecompile(shader, options, &result, &error); + const bool ok = ShaderRecompiler::TryRecompile(shader, options, result, &error); if (!ok) { std::fprintf(stderr, "PostEndTargetMergePS compile error: %s\n", error.c_str()); } @@ -5012,7 +5022,7 @@ void TestNewShaderRecompilerCfgLoopBreakContinue() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "backedge"), "loop backedge was not detected"); Check(Common::ContainsStr(result.ir_dump, "loop_header=1"), "loop header was not marked"); Check(Common::ContainsStr(result.ir_dump, "continue="), @@ -5038,7 +5048,7 @@ void TestNewShaderRecompilerCfgLoopHeaderDynamicScalarBufferLoadStructured() { ShaderRecompiler::CompileResult result; std::string error; - Check(!ShaderRecompiler::TryRecompile(shader, options, &result, &error) && + Check(!ShaderRecompiler::TryRecompile(shader, options, result, &error) && Common::ContainsStr(error, "unsupported GPU selection"), "self-modifying scalar-buffer descriptor should fail explicitly"); } @@ -5060,7 +5070,7 @@ void TestNewShaderRecompilerCfgLoopHeaderBufferLoadDispatcher() { ShaderRecompiler::CompileResult result; std::string error; - Check(!ShaderRecompiler::TryRecompile(shader, options, &result, &error) && + Check(!ShaderRecompiler::TryRecompile(shader, options, result, &error) && Common::ContainsStr(error, "unsupported GPU selection"), "self-modifying vector-buffer descriptor should fail explicitly"); } @@ -5084,7 +5094,7 @@ void TestNewShaderRecompilerCfgLoopHeaderDsAppendConsumeDispatcher() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "mode=dispatcher"), "DS append/consume loop header did not select dispatcher fallback"); Check(SpirvContainsOpcode(result.spirv, 246), "DS dispatcher SPIR-V lacks OpLoopMerge"); @@ -5110,7 +5120,7 @@ void TestNewShaderRecompilerCfgSharedOuterAndLoopMerge() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "mode=structured"), "shared outer/loop merge should stay on structured path"); Check(!Common::ContainsStr(result.ir_dump, "duplicate structured merge block"), @@ -5147,7 +5157,7 @@ void TestNewShaderRecompilerCfgLoopSharedContinueSelectionMerges() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "mode=structured"), "shared loop continue selections should stay on structured path"); Check(!Common::ContainsStr(result.ir_dump, "duplicate structured merge block"), @@ -5176,7 +5186,7 @@ void TestNewShaderRecompilerCfgDuplicateMergeStructuredSplit() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "mode=structured"), "duplicate merge CFG did not stay on structured path"); Check(!Common::ContainsStr(result.ir_dump, "duplicate structured merge block"), @@ -5202,7 +5212,7 @@ void TestNewShaderRecompilerCfgIrreducibleDispatcher() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "irreducible CFG"), "irreducible CFG reason was not retained"); Check(Common::ContainsStr(result.ir_dump, "mode=dispatcher"), @@ -5273,7 +5283,7 @@ void TestNewShaderRecompilerWave32MasksExecHighStores() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_mov_b64 exec_lo, -1"), "wave32 EXEC mask regression did not decode s_mov_b64 exec, -1"); CheckSpirvBinaryValidates(result.spirv); @@ -5299,7 +5309,7 @@ void TestNewShaderRecompilerWave32VccHighScalarStores() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "SBufferLoadDword vcc_hi"), "wave32 VCC scalar regression did not lower the high VCC dword load"); CheckSpirvBinaryValidates(result.spirv); @@ -5326,7 +5336,7 @@ void TestNewShaderRecompilerCompareMaskIsFullWaveBallot() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "v_cmp_lt_u32"), "compare-mask ballot regression did not decode V_CMP_LT_U32"); Check(Common::ContainsStr(result.ir_dump, "CompareLtU32 vcc_lo"), @@ -5357,7 +5367,7 @@ void TestNewShaderRecompilerBufferLoadsGuardedByExec() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "buffer_load_dword"), "buffer load guard regression did not decode MUBUF load"); CheckSpirvBinaryValidates(result.spirv); @@ -5394,7 +5404,7 @@ void TestNewShaderRecompilerBufferAtomicsGuardedByBounds() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "buffer_atomic_add"), "buffer atomic bounds regression did not decode MUBUF atomic"); CheckSpirvBinaryValidates(result.spirv); @@ -5440,7 +5450,7 @@ void TestNewShaderRecompilerBranchConditionForms() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, c.condition), "branch condition was not preserved"); Check(SpirvContainsOpcode(result.spirv, 250), @@ -5468,7 +5478,7 @@ void TestNewShaderRecompilerSetpcBranch() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "s_setpc_b64"), "S_SETPC_B64 was not decoded"); Check(Common::ContainsStr(result.ir_dump, "successors=["), "S_SETPC_B64 did not participate in CFG"); @@ -5506,7 +5516,7 @@ void TestNewShaderRecompilerSetpcJumpTable() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "mode=dispatcher"), "S_SETPC_B64 jump table did not select dispatcher fallback"); Check(Common::ContainsStr(result.ir_dump, "indirect_targets=2"), @@ -5533,7 +5543,7 @@ void TestNewShaderRecompilerExpVertexOutputs() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.decoded_dump, "target=0x0c"), "POS export was not decoded"); Check(Common::ContainsStr(result.decoded_dump, "target=0x20"), "PARAM export was not decoded"); Check(Common::ContainsStr(result.decoded_dump, "target=0x14"), "PRIM export was not decoded"); @@ -5563,7 +5573,7 @@ void TestNewShaderRecompilerVertexSystemVgprs() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(ProgramHasInput(result.program, StageInputKind::VertexIndex), "vertex shader missing VertexIndex input"); Check(ProgramHasInput(result.program, StageInputKind::InstanceIndex), @@ -5599,7 +5609,7 @@ void TestNewShaderRecompilerVertexExportUsesLaneExecMask() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); CheckSpirvBinaryValidates(result.spirv); const auto source = DisassembleSpirvBinary(result.spirv); @@ -5610,7 +5620,7 @@ void TestNewShaderRecompilerVertexExportUsesLaneExecMask() { options.lane_mask_mode = ShaderLaneMaskMode::PerInvocation; ShaderRecompiler::CompileResult local_result; - Check(ShaderRecompiler::TryRecompile(shader, options, &local_result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, local_result, &error), error.c_str()); Check(local_result.program.lane_mask_mode == ShaderLaneMaskMode::PerInvocation, "per-invocation mask mode was not preserved in the immutable program"); CheckSpirvBinaryValidates(local_result.spirv); @@ -5641,7 +5651,7 @@ void TestNewShaderRecompilerPerInvocationMasks() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(local_shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(local_shader, options, result, &error), error.c_str()); CheckSpirvBinaryValidates(result.spirv); const auto source = DisassembleSpirvBinary(result.spirv); Check(!Common::ContainsStr(source, "OpGroupNonUniformBallot"), @@ -5663,7 +5673,7 @@ void TestNewShaderRecompilerPerInvocationMasks() { EncodeExp1(0, 1, 2, 3), // POS0 EncodeSopp(0x01), }; - Check(ShaderRecompiler::TryRecompile(wqm_shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(wqm_shader, options, result, &error), error.c_str()); CheckSpirvBinaryValidates(result.spirv); const auto wqm_source = DisassembleSpirvBinary(result.spirv); Check(Common::ContainsStr(wqm_source, "OpCapability GroupNonUniformBallot") && @@ -5678,7 +5688,7 @@ void TestNewShaderRecompilerPerInvocationMasks() { EncodeExp1(0, 1, 2, 3), // POS0 EncodeSopp(0x01), }; - Check(ShaderRecompiler::TryRecompile(cross_lane_shader, options, &result, &error), + Check(ShaderRecompiler::TryRecompile(cross_lane_shader, options, result, &error), error.c_str()); CheckSpirvBinaryValidates(result.spirv); Check(Common::ContainsStr(DisassembleSpirvBinary(result.spirv), "OpGroupNonUniformBallot"), @@ -5704,7 +5714,7 @@ void TestNewShaderRecompilerExpPixelOutputs() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(Common::ContainsStr(result.ir_dump, "mrt"), "MRT export did not reach IR"); Check(Common::ContainsStr(result.ir_dump, "mrtz"), "MRTZ export did not reach IR"); Check(Common::ContainsStr(result.ir_dump, "null"), "NULL export did not reach IR"); @@ -5754,20 +5764,20 @@ void TestRenderTargetReverseFloat16ExportMapping() { options.pixel_input_info = &identity_info; ShaderRecompiler::CompileResult identity_result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &identity_result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, identity_result, &error), error.c_str()); Check(SpirvInstructionOpcodeCount(identity_result.spirv, 79u) == 0u, "identity MRT export unexpectedly added a component shuffle"); options.pixel_input_info = &reversed_info; ShaderRecompiler::CompileResult reversed_result; - Check(ShaderRecompiler::TryRecompile(shader, options, &reversed_result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, reversed_result, &error), error.c_str()); Check(SpirvContainsVectorShuffle(reversed_result.spirv, {3u, 2u, 1u, 0u}), "reverse MRT export did not emit a WZYX component shuffle"); CheckSpirvBinaryValidates(reversed_result.spirv); HW::PixelShaderInfo regs {}; - Check(ShaderGetIdPS(®s, &identity_info, false) != - ShaderGetIdPS(®s, &reversed_info, false), + Check(ShaderGetIdPS(regs, identity_info, false) != + ShaderGetIdPS(regs, reversed_info, false), "pixel shader cache identity omitted the render-target export mapping"); regs.ps_regs.data_addr = reinterpret_cast(shader); @@ -5782,13 +5792,13 @@ void TestRenderTargetReverseFloat16ExportMapping() { mappings[0] = format.export_mapping; ShaderPixelInputInfo compiled_info {}; std::span compiled_spirv; - Check(ShaderCompileInfoPS(®s, &sh, ShaderLaneMaskMode::NativeWave, &vs_info, mappings, - &compiled_info, &compiled_spirv) && + Check(ShaderCompileInfoPS(regs, sh, ShaderLaneMaskMode::NativeWave, vs_info, mappings, + compiled_info, compiled_spirv) && compiled_info.target_export_mapping[0].IsIdentity(), "inactive reverse MRT mapping was not normalized out of the shader cache key"); sh.target_output_mode[0] = 4; - Check(ShaderCompileInfoPS(®s, &sh, ShaderLaneMaskMode::NativeWave, &vs_info, mappings, - &compiled_info, &compiled_spirv) && + Check(ShaderCompileInfoPS(regs, sh, ShaderLaneMaskMode::NativeWave, vs_info, mappings, + compiled_info, compiled_spirv) && compiled_info.target_export_mapping[0] == format.export_mapping, "active reverse MRT mapping was lost before shader specialization"); } @@ -5812,7 +5822,7 @@ void TestNewShaderRecompilerEarlyZDisabledWhenPixelKillEnabled() { ShaderRecompiler::CompileResult result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, options, &result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, options, result, &error), error.c_str()); Check(SpirvContainsOpcode(result.spirv, 252), "pixel valid-mask export should still lower to OpKill"); Check(!SpirvContainsExecutionMode(result.spirv, ExecutionModeEarlyFragmentTests), @@ -5845,7 +5855,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { ShaderRecompiler::CompileResult result; std::string error; - const auto compiled = ShaderRecompiler::TryRecompile(shader, options, &result, &error); + const auto compiled = ShaderRecompiler::TryRecompile(shader, options, result, &error); Check(compiled, error.c_str()); const auto* buffers = ShaderRecompiler::IR::FindBinding(result.program.bindings, BindingKind::Buffers); @@ -5890,7 +5900,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { const auto rejected_before = rejected_spirv; std::string rejected_error; Check(!ShaderRecompiler::Spirv::EmitProgram(malformed, result.resources, nullptr, nullptr, - nullptr, &rejected_spirv, &rejected_error) && + nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("topology") != std::string::npos, "malformed native binding plan was not rejected transactionally"); @@ -5916,7 +5926,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_spirv = rejected_before; rejected_error.clear(); Check(!ShaderRecompiler::Spirv::EmitProgram(malformed_inst, result.resources, nullptr, nullptr, - nullptr, &rejected_spirv, &rejected_error) && + nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("contract") != std::string::npos, "malformed native instruction was not rejected before fatal emitter paths"); @@ -5928,7 +5938,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_spirv = rejected_before; rejected_error.clear(); Check(!ShaderRecompiler::Spirv::EmitProgram(missing_buffer_operand, result.resources, nullptr, - nullptr, nullptr, &rejected_spirv, + nullptr, nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("contract") != std::string::npos, @@ -5941,7 +5951,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_spirv = rejected_before; rejected_error.clear(); Check(!ShaderRecompiler::Spirv::EmitProgram(extra_buffer_operand, result.resources, nullptr, - nullptr, nullptr, &rejected_spirv, + nullptr, nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("contract") != std::string::npos, @@ -5957,7 +5967,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_error.clear(); Check( !ShaderRecompiler::Spirv::EmitProgram(malformed_atomic, result.resources, nullptr, nullptr, - nullptr, &rejected_spirv, &rejected_error) && + nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("atomic") != std::string::npos, "malformed atomic instruction reached a fatal descriptor path"); @@ -5969,7 +5979,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_spirv = rejected_before; rejected_error.clear(); Check(!ShaderRecompiler::Spirv::EmitProgram(overwide_atomic, result.resources, nullptr, nullptr, - nullptr, &rejected_spirv, &rejected_error) && + nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("fixed IR storage") != std::string::npos, "overwide atomic operands reached fixed emitter storage"); @@ -5982,7 +5992,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_spirv = rejected_before; rejected_error.clear(); Check(!ShaderRecompiler::Spirv::EmitProgram(overwide_move, result.resources, nullptr, nullptr, - nullptr, &rejected_spirv, &rejected_error) && + nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("fixed IR storage") != std::string::npos, "overwide non-memory operands reached fixed emitter storage"); @@ -6003,7 +6013,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_spirv = rejected_before; rejected_error.clear(); Check(!ShaderRecompiler::Spirv::EmitProgram(malformed_image, result.resources, nullptr, nullptr, - nullptr, &rejected_spirv, &rejected_error) && + nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("sampled image") != std::string::npos, "malformed image operands reached fixed emitter storage"); @@ -6022,7 +6032,7 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_spirv = rejected_before; rejected_error.clear(); Check(!ShaderRecompiler::Spirv::EmitProgram(result.program, stale_resources, nullptr, nullptr, - nullptr, &rejected_spirv, &rejected_error) && + nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("specialized format") != std::string::npos, "stale runtime image format re-selected an absent descriptor group"); @@ -6032,20 +6042,20 @@ void TestNewShaderRecompilerNativeBindingPlan() { rejected_spirv = rejected_before; rejected_error.clear(); Check(!ShaderRecompiler::Spirv::EmitProgram(result.program, stale_dimension, nullptr, nullptr, - nullptr, &rejected_spirv, &rejected_error) && + nullptr, rejected_spirv, &rejected_error) && rejected_spirv == rejected_before && rejected_error.find("specialized dimension") != std::string::npos, "unsupported runtime image type bypassed specialization validation"); } -bool LowerProvenanceOnly(const uint32_t* code, uint32_t words, ShaderRecompiler::IR::Program* ir, +bool LowerProvenanceOnly(const uint32_t* code, uint32_t words, ShaderRecompiler::IR::Program& ir, std::string* error) { ShaderRecompiler::Decoder::Program decoded; - if (!ShaderRecompiler::Decoder::DecodeProgram(std::span {code, words}, &decoded, error)) { + if (!ShaderRecompiler::Decoder::DecodeProgram(std::span {code, words}, decoded, error)) { return false; } ShaderRecompiler::CFG::Graph cfg; - if (!ShaderRecompiler::CFG::BuildGraph(decoded, &cfg, error) || + if (!ShaderRecompiler::CFG::BuildGraph(decoded, cfg, error) || !ShaderRecompiler::IR::LowerProgram(decoded, cfg, ShaderType::Compute, 64, ir, error)) { return false; } @@ -6072,7 +6082,7 @@ void TestScalarProvenanceRealWideMoveLowering() { std::string error; ShaderRecompiler::IR::Program ir; const auto lowered = - LowerProvenanceOnly(shader, static_cast(std::size(shader)), &ir, &error); + LowerProvenanceOnly(shader, static_cast(std::size(shader)), ir, &error); Check(lowered, error.c_str()); const ShaderRecompiler::IR::Instruction* use = nullptr; @@ -6107,7 +6117,7 @@ void TestScalarProvenanceRealCarryAndScalarLoads() { std::string error; ShaderRecompiler::IR::Program carry_ir; const auto carry_lowered = LowerProvenanceOnly( - carry_shader, static_cast(std::size(carry_shader)), &carry_ir, &error); + carry_shader, static_cast(std::size(carry_shader)), carry_ir, &error); Check(carry_lowered, error.c_str()); const ShaderRecompiler::IR::DescriptorValue* carry_source = nullptr; for (const auto& block: carry_ir.blocks) { @@ -6138,7 +6148,7 @@ void TestScalarProvenanceRealCarryAndScalarLoads() { }; ShaderRecompiler::IR::Program load_ir; const auto load_lowered = LowerProvenanceOnly( - load_shader, static_cast(std::size(load_shader)), &load_ir, &error); + load_shader, static_cast(std::size(load_shader)), load_ir, &error); Check(load_lowered, error.c_str()); uint32_t uses = 0; for (const auto& block: load_ir.blocks) { @@ -6172,7 +6182,7 @@ void TestScalarProvenanceRealCarryAndScalarLoads() { error.clear(); Check(LowerProvenanceOnly(inline_sampler_shader, static_cast(std::size(inline_sampler_shader)), - &inline_sampler_ir, &error), + inline_sampler_ir, &error), error.c_str()); uint32_t sampler_source = 0; for (const auto& block: inline_sampler_ir.blocks) { @@ -6187,7 +6197,7 @@ void TestScalarProvenanceRealCarryAndScalarLoads() { Check(sampler_source >= 2 && ShaderRecompiler::IR::DescriptorSourceResolved(inline_sampler_ir, sampler_source) && ShaderRecompiler::IR::EvaluateDescriptorSource(inline_sampler_ir, sampler_source, - 0x10, runtime, &sampler, &error) && + 0x10, runtime, sampler, &error) && sampler.dwords[0] == 0 && sampler.dwords[1] == 0x00fff000u && sampler.dwords[2] == 0x09500000u && sampler.dwords[3] == 0, "real inline sampler construction was unresolved or evaluated incorrectly"); @@ -6198,7 +6208,7 @@ void TestScalarProvenanceRealCarryAndScalarLoads() { options.user_data = user_data.data(); ShaderRecompiler::CompileResult result; error.clear(); - Check(ShaderRecompiler::TryRecompile(inline_sampler_shader, options, &result, &error), + Check(ShaderRecompiler::TryRecompile(inline_sampler_shader, options, result, &error), error.c_str()); } @@ -6212,7 +6222,7 @@ void TestSrtWalkerRealSmemLowering() { std::string error; ShaderRecompiler::IR::Program ir; const auto lowered = - LowerProvenanceOnly(shader, static_cast(std::size(shader)), &ir, &error); + LowerProvenanceOnly(shader, static_cast(std::size(shader)), ir, &error); Check(lowered, error.c_str()); Check(ir.srt.reads.size() == 4 && ir.srt.dynamic_reads.empty(), "real SMEM lowering did not build four compact SRT reads"); @@ -6224,11 +6234,11 @@ void TestSrtWalkerRealSmemLowering() { user_data[9] = static_cast(address >> 32u); std::vector flat; const ShaderRecompiler::IR::SrtRuntime runtime {user_data, 0, ReadSrtHostDword, nullptr}; - const auto walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, &flat, &error); + const auto walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, flat, &error); Check(walked, error.c_str()); Check(flat.size() == table.size() && std::equal(flat.begin(), flat.end(), table.begin()), "real SMEM SRT walk did not apply component-level alignment"); - Check(ShaderRecompiler::IR::PatchSrtReads(&ir, &error), error.c_str()); + Check(ShaderRecompiler::IR::PatchSrtReads(ir, &error), error.c_str()); uint32_t patched = 0; for (const auto& block: ir.blocks) { for (const auto& inst: block.instructions) { @@ -6250,7 +6260,7 @@ void TestSrtWalkerRealSBufferLowering() { std::string error; ShaderRecompiler::IR::Program ir; const auto lowered = - LowerProvenanceOnly(shader, static_cast(std::size(shader)), &ir, &error); + LowerProvenanceOnly(shader, static_cast(std::size(shader)), ir, &error); Check(lowered, error.c_str()); Check(ir.srt.reads.size() == 4 && ir.srt.dynamic_reads.empty(), "real S_BUFFER_LOAD lowering did not build four compact reads"); @@ -6264,19 +6274,19 @@ void TestSrtWalkerRealSBufferLowering() { user_data[10] = sizeof(table); std::vector flat; const ShaderRecompiler::IR::SrtRuntime runtime {user_data, 0, ReadSrtHostDword, nullptr}; - const auto walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, &flat, &error); + const auto walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, flat, &error); Check(walked, error.c_str()); Check(flat.size() == 4 && std::equal(flat.begin(), flat.end(), table.begin() + 1), "real S_BUFFER_LOAD walk used the wrong final alignment"); user_data[10] = 4 * sizeof(uint32_t); const auto flat_before_failure = flat; - const auto bounds_walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, &flat, &error); + const auto bounds_walked = ShaderRecompiler::IR::WalkSrt(ir, runtime, flat, &error); Check(!bounds_walked && error.find("exceeds size=16") != std::string::npos, "real S_BUFFER_LOAD walk ignored descriptor bounds"); Check(flat == flat_before_failure, "failed real S_BUFFER_LOAD walk changed the prior flat snapshot"); - Check(ShaderRecompiler::IR::PatchSrtReads(&ir, &error), error.c_str()); + Check(ShaderRecompiler::IR::PatchSrtReads(ir, &error), error.c_str()); uint32_t patched = 0; for (const auto& block: ir.blocks) { for (const auto& inst: block.instructions) { @@ -6295,10 +6305,10 @@ void TestSrtWalkerRealSBufferLowering() { }; ShaderRecompiler::IR::Program negative_ir; const auto negative_lowered = LowerProvenanceOnly( - negative_shader, static_cast(std::size(negative_shader)), &negative_ir, &error); + negative_shader, static_cast(std::size(negative_shader)), negative_ir, &error); Check(negative_lowered, error.c_str()); user_data[10] = sizeof(table); - Check(!ShaderRecompiler::IR::WalkSrt(negative_ir, runtime, &flat, &error) && + Check(!ShaderRecompiler::IR::WalkSrt(negative_ir, runtime, flat, &error) && error.find("negative immediate") != std::string::npos, "real S_BUFFER_LOAD walk accepted a negative immediate"); } @@ -6314,13 +6324,13 @@ void TestScalarMemoryLoadsSnapshotOverlappingOperands() { }; std::string error; ShaderRecompiler::IR::Program ir; - Check(LowerProvenanceOnly(shader, static_cast(std::size(shader)), &ir, &error), + Check(LowerProvenanceOnly(shader, static_cast(std::size(shader)), ir, &error), error.c_str()); Check(ir.srt.reads.size() == 4 && ir.srt.dynamic_reads.empty(), opcode == 0x02 ? "overlapping S_LOAD operands were evaluated after a component write" : "overlapping S_BUFFER_LOAD operands were evaluated after a component write"); - Check(ShaderRecompiler::IR::PatchSrtReads(&ir, &error), error.c_str()); + Check(ShaderRecompiler::IR::PatchSrtReads(ir, &error), error.c_str()); uint32_t patched = 0; for (const auto& block: ir.blocks) { for (const auto& inst: block.instructions) { @@ -6346,11 +6356,11 @@ void TestScalarMemoryLoadCrossesIntoVcc() { }; std::string error; ShaderRecompiler::IR::Program ir; - Check(LowerProvenanceOnly(shader, static_cast(std::size(shader)), &ir, &error), + Check(LowerProvenanceOnly(shader, static_cast(std::size(shader)), ir, &error), error.c_str()); Check(ir.srt.reads.size() == 4 && ir.srt.dynamic_reads.empty(), "wide SMEM destination crossing into VCC lost scalar provenance"); - Check(ShaderRecompiler::IR::PatchSrtReads(&ir, &error), error.c_str()); + Check(ShaderRecompiler::IR::PatchSrtReads(ir, &error), error.c_str()); uint32_t patched = 0; for (const auto& block: ir.blocks) { for (const auto& inst: block.instructions) { @@ -6375,10 +6385,10 @@ void TestResourceTrackingRealDensePatching() { std::string error; ShaderRecompiler::IR::Program ir; const auto lowered = - LowerProvenanceOnly(shader, static_cast(std::size(shader)), &ir, &error); + LowerProvenanceOnly(shader, static_cast(std::size(shader)), ir, &error); Check(lowered, error.c_str()); - Check(ShaderRecompiler::IR::PatchSrtReads(&ir, &error), error.c_str()); - const auto tracked = ShaderRecompiler::IR::TrackResources(&ir, &error); + Check(ShaderRecompiler::IR::PatchSrtReads(ir, &error), error.c_str()); + const auto tracked = ShaderRecompiler::IR::TrackResources(ir, &error); Check(tracked, error.c_str()); Check(ir.info.buffers.size() == 2 && ir.info.images.size() == 2 && ir.info.samplers.size() == 1, "real resource tracking produced the wrong dense list sizes"); @@ -6416,20 +6426,20 @@ void TestLowerProgramResetsAnalysisState() { const uint32_t first_shader[] = {EncodeMubuf0(0x0c), EncodeMubuf1(0, 0, 1), EncodeSopp(0x01)}; std::string error; ShaderRecompiler::IR::Program ir; - Check(LowerProvenanceOnly(first_shader, static_cast(std::size(first_shader)), &ir, + Check(LowerProvenanceOnly(first_shader, static_cast(std::size(first_shader)), ir, &error), error.c_str()); - Check(ShaderRecompiler::IR::PatchSrtReads(&ir, &error), error.c_str()); - Check(ShaderRecompiler::IR::TrackResources(&ir, &error), error.c_str()); + Check(ShaderRecompiler::IR::PatchSrtReads(ir, &error), error.c_str()); + Check(ShaderRecompiler::IR::TrackResources(ir, &error), error.c_str()); ShaderComputeInputInfo compute; - Check(ShaderRecompiler::IR::CollectShaderInfo(&ir, {.compute = &compute}, &error), + Check(ShaderRecompiler::IR::CollectShaderInfo(ir, {.compute = &compute}, &error), error.c_str()); Check(ir.resource_tracking_complete && ir.shader_info_complete && !ir.info.buffers.empty(), "analysis-reset fixture did not reach completed state"); ir.shader_hash = 0xdeadbeef; const uint32_t second_shader[] = {EncodeSopp(0x01)}; - Check(LowerProvenanceOnly(second_shader, static_cast(std::size(second_shader)), &ir, + Check(LowerProvenanceOnly(second_shader, static_cast(std::size(second_shader)), ir, &error), error.c_str()); Check(!ir.resource_tracking_complete && !ir.shader_info_complete && ir.srt_plan_complete && @@ -6455,7 +6465,7 @@ void TestNewShaderRecompilerStageInputInfo() { ShaderRecompiler::CompileResult cs_result; std::string error; - Check(ShaderRecompiler::TryRecompile(shader, cs_options, &cs_result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, cs_options, cs_result, &error), error.c_str()); Check(ProgramHasInput(cs_result.program, StageInputKind::WorkgroupId), "compute WorkgroupId input missing from reflection"); Check(ProgramHasInput(cs_result.program, StageInputKind::LocalInvocationId), @@ -6478,7 +6488,7 @@ void TestNewShaderRecompilerStageInputInfo() { vs_options.stage = ShaderType::Vertex; ShaderRecompiler::CompileResult vs_result; - Check(ShaderRecompiler::TryRecompile(shader, vs_options, &vs_result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, vs_options, vs_result, &error), error.c_str()); Check(ProgramHasInput(vs_result.program, StageInputKind::VertexIndex), "vertex VertexIndex input missing from reflection"); Check(ProgramHasInput(vs_result.program, StageInputKind::InstanceIndex), @@ -6501,7 +6511,7 @@ void TestNewShaderRecompilerStageInputInfo() { ps_options.pixel_input_info = &ps_info; ShaderRecompiler::CompileResult ps_result; - Check(ShaderRecompiler::TryRecompile(shader, ps_options, &ps_result, &error), error.c_str()); + Check(ShaderRecompiler::TryRecompile(shader, ps_options, ps_result, &error), error.c_str()); Check(ProgramHasInput(ps_result.program, StageInputKind::FragCoord), "pixel FragCoord input missing from reflection"); Check(ProgramInputCount(ps_result.program, StageInputKind::Parameter) == 2, @@ -6522,7 +6532,7 @@ void TestNewShaderRecompilerStageInputInfo() { ps_options.pixel_input_info = &ps_pos_y_info; ShaderRecompiler::CompileResult ps_pos_y_result; - Check(ShaderRecompiler::TryRecompile(shader, ps_options, &ps_pos_y_result, &error), + Check(ShaderRecompiler::TryRecompile(shader, ps_options, ps_pos_y_result, &error), error.c_str()); Check(ProgramHasInput(ps_pos_y_result.program, StageInputKind::FragCoord), "pixel POS_Y-only FragCoord input missing from reflection"); @@ -6546,7 +6556,7 @@ void TestNewShaderRecompilerPixelPipelineEntry() { HW::ShaderRegisters sh {}; ShaderPixelInputInfo input_info {}; std::vector spirv; - Check(ShaderCompileSpirvPS(®s, &sh, ShaderLaneMaskMode::NativeWave, &input_info, &spirv), + Check(ShaderCompileSpirvPS(regs, sh, ShaderLaneMaskMode::NativeWave, input_info, spirv), "new pixel shader recompiler wrapper did not produce SPIR-V"); Check(!spirv.empty(), "new pixel shader recompiler wrapper returned empty SPIR-V"); Check(spirv.front() == 0x07230203u, @@ -6579,8 +6589,7 @@ void TestNewShaderRecompilerPixelPipelineEntry() { ShaderPixelInputInfo vcc_input {}; std::vector vcc_spirv; - Check(ShaderCompileSpirvPS(&vcc_regs, &sh, ShaderLaneMaskMode::NativeWave, &vcc_input, - &vcc_spirv), + Check(ShaderCompileSpirvPS(vcc_regs, sh, ShaderLaneMaskMode::NativeWave, vcc_input, vcc_spirv), "VCC raw-load pointer was lost"); CheckSpirvBinaryValidates(vcc_spirv); } @@ -6610,8 +6619,8 @@ void TestPixelProgramCacheDescriptorSetIdentity() { const std::array identity_mappings {}; ShaderPixelInputInfo ps_info {}; std::span spirv; - Check(ShaderCompileInfoPS(®s, &sh, ShaderLaneMaskMode::NativeWave, &vs_info, - identity_mappings, &ps_info, &spirv), + Check(ShaderCompileInfoPS(regs, sh, ShaderLaneMaskMode::NativeWave, vs_info, + identity_mappings, ps_info, spirv), "pixel program-cache transition failed to compile"); const auto expected_set = has_vs_descriptors ? 1u : 0u; Check(ps_info.descriptor_set == expected_set && ps_info.stage.program != nullptr && @@ -6638,8 +6647,7 @@ void TestPixelProgramCacheDescriptorSetIdentity() { const std::array identity_mappings {}; ShaderPixelInputInfo ps_info {}; std::span spirv; - Check(ShaderCompileInfoPS(&mask_regs, &sh, mode, &vs_info, identity_mappings, &ps_info, - &spirv), + Check(ShaderCompileInfoPS(mask_regs, sh, mode, vs_info, identity_mappings, ps_info, spirv), "pixel lane-mask cache transition failed to compile"); Check(ps_info.stage.program != nullptr && ps_info.stage.program->lane_mask_mode == mode, "pixel program cache reused a different lane-mask lowering"); @@ -6681,7 +6689,7 @@ void TestNewShaderRecompilerFlatUserPointerProvenance() { ShaderRecompiler::CompileResult result; std::string error; - const bool compiled = ShaderRecompiler::TryRecompile(shader, options, &result, &error); + const bool compiled = ShaderRecompiler::TryRecompile(shader, options, result, &error); Check(compiled, error.c_str()); Check(result.program.info.addresses.size() == 1 && result.program.info.addresses[0].source != @@ -6715,7 +6723,7 @@ void TestNewShaderRecompilerFlatAddressProvenanceBoundaries() { ShaderRecompiler::CompileResult result; std::string error; const bool compiled = - ShaderRecompiler::TryRecompile(segmented_shader, options, &result, &error); + ShaderRecompiler::TryRecompile(segmented_shader, options, result, &error); Check(compiled, error.c_str()); Check(result.program.info.addresses.size() == 2, "segmented address resources were not tracked independently");