graphics: refactoring #2

This commit is contained in:
nmzik committed 2026-07-21 07:37:52 +02:00
1 parent b51d4322cc
commit 0a5f78c727
137 files changed
+10019 -10682

No files matched your search

@@ -20,15 +20,18 @@ class CommandScheduler {
public: public:
static constexpr int BuffersNum = 8; 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; } void SetQueue(int queue) { m_queue = queue; }
int Queue() const { return m_queue; } int Queue() const { return m_queue; }
bool Active() const { return m_current >= 0 && m_current < BuffersNum; } bool Active() const { return m_current >= 0 && m_current < BuffersNum; }
void CheckActive() const { EXIT_IF(!Active()); } void CheckActive() const { EXIT_IF(!Active()); }
CommandBuffer* Current() const { RenderCommandBuffer& Current() const {
CheckActive(); CheckActive();
EXIT_IF(m_buffers[m_current] == nullptr); EXIT_IF(m_buffers[m_current] == nullptr);
return m_buffers[m_current]; return *m_buffers[m_current];
} }
void Init() { void Init() {
@@ -37,10 +40,10 @@ public:
} }
for (auto& buf: m_buffers) { for (auto& buf: m_buffers) {
EXIT_IF(buf != nullptr); EXIT_IF(buf != nullptr);
buf = new CommandBuffer(m_queue); buf = new RenderCommandBuffer(m_queue, m_registers, m_user_config, m_shaders);
} }
m_current = 0; m_current = 0;
Current()->Begin(); Current().Begin();
} }
void Flush() { void Flush() {
@@ -48,18 +51,17 @@ public:
BeginNext(); BeginNext();
} }
CommandBuffer* FlushAndGetSubmitted() { CommandBuffer& FlushAndGetSubmitted() {
auto* submitted = SubmitCurrent(); auto& submitted = SubmitCurrent();
BeginNext(); BeginNext();
return submitted; return submitted;
} }
void CopyBuffers(std::array<CommandBuffer*, BuffersNum>* out) const { void CopyBuffers(std::array<CommandBuffer*, BuffersNum>& out) const {
EXIT_IF(out == nullptr);
for (int i = 0; i < BuffersNum; i++) { for (int i = 0; i < BuffersNum; i++) {
auto* buf = m_buffers[i]; auto* buf = m_buffers[i];
EXIT_IF(buf == nullptr); EXIT_IF(buf == nullptr);
(*out)[i] = buf; out[i] = buf;
} }
} }
@@ -81,27 +83,30 @@ public:
if (!Active()) { if (!Active()) {
return; return;
} }
Current()->WaitForFenceAndReset(); Current().WaitForFenceAndReset();
Current()->Begin(); Current().Begin();
} }
private: private:
CommandBuffer* SubmitCurrent() { CommandBuffer& SubmitCurrent() {
auto* submitted = Current(); auto& submitted = Current();
submitted->End(); submitted.End();
submitted->Execute(); submitted.Execute();
return submitted; return submitted;
} }
void BeginNext() { void BeginNext() {
m_current = (m_current + 1) % BuffersNum; m_current = (m_current + 1) % BuffersNum;
Current()->WaitForFenceAndReset(); Current().WaitForFenceAndReset();
Current()->Begin(); Current().Begin();
} }
CommandBuffer* m_buffers[BuffersNum] = {}; RenderCommandBuffer* m_buffers[BuffersNum] = {};
int m_current = -1; int m_current = -1;
int m_queue = -1; int m_queue = -1;
HW::Context& m_registers;
HW::UserConfig& m_user_config;
HW::Shader& m_shaders;
}; };
class CommandProcessor { class CommandProcessor {
@@ -113,7 +118,7 @@ public:
int64_t flip_arg = 0; int64_t flip_arg = 0;
}; };
CommandProcessor() = default; CommandProcessor(): m_scheduler(m_ctx, m_ucfg, m_sh_ctx) {}
~CommandProcessor() { KYTY_NOT_IMPLEMENTED; } ~CommandProcessor() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(CommandProcessor); KYTY_CLASS_NO_COPY(CommandProcessor);
@@ -145,9 +150,9 @@ public:
void RunLock() { m_run_mutex.Lock(); } void RunLock() { m_run_mutex.Lock(); }
void RunUnlock() { m_run_mutex.Unlock(); } void RunUnlock() { m_run_mutex.Unlock(); }
HW::Context* GetCtx() { return &m_ctx; } HW::Context& GetCtx() { return m_ctx; }
HW::UserConfig* GetUcfg() { return &m_ucfg; } HW::UserConfig& GetUcfg() { return m_ucfg; }
HW::Shader* GetShCtx() { return &m_sh_ctx; } HW::Shader& GetShCtx() { return m_sh_ctx; }
void SetIndexType(uint32_t index_type_and_size); void SetIndexType(uint32_t index_type_and_size);
void SetIndexBaseAddress(uint64_t index_base_addr); void SetIndexBaseAddress(uint64_t index_base_addr);
@@ -244,12 +249,9 @@ private:
uint32_t interrupt_context_id); uint32_t interrupt_context_id);
void FinishCommandProcessors(); void FinishCommandProcessors();
CommandBuffer* CurrentBuffer() { return m_scheduler.Current(); } RenderCommandBuffer& CurrentBuffer() { return m_scheduler.Current(); }
void CheckBuffer() const { m_scheduler.CheckActive(); } void CheckBuffer() const { m_scheduler.CheckActive(); }
GpuResourceManager* GetGpuResources() const { GpuResourceManager& GetGpuResources() const { return GetRenderContext().GetGpuResources(); }
EXIT_IF(g_render_ctx == nullptr);
return g_render_ctx->GetGpuResources();
}
HW::Context m_ctx; HW::Context m_ctx;
HW::UserConfig m_ucfg; HW::UserConfig m_ucfg;
@@ -10,17 +10,17 @@ namespace Libs::Graphics {
class CommandProcessor; 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); 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); 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); 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); uint32_t);
using hw_ctx_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_uc_indirect_func_t = void (*)(CommandProcessor&, uint32_t, uint32_t);
using hw_sh_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<hw_ctx_parser_func_t, Pm4::CX_NUM> g_hw_ctx_func; extern const std::array<hw_ctx_parser_func_t, Pm4::CX_NUM> g_hw_ctx_func;
extern hw_ctx_indirect_func_t g_hw_ctx_indirect_func[Pm4::CX_NUM]; extern hw_ctx_indirect_func_t g_hw_ctx_indirect_func[Pm4::CX_NUM];
@@ -36,136 +36,136 @@ void GraphicsInitJmpTablesCxIndirect();
void GraphicsInitJmpTablesShIndirect(); void GraphicsInitJmpTablesShIndirect();
void GraphicsInitJmpTablesUcIndirect(); void GraphicsInitJmpTablesUcIndirect();
uint32_t HwCtxSetRenderControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, 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 HwCtxSetDepthMetadataRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
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);
uint32_t HwCtxSetStencilClear(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 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 HwCtxSetScreenScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthRenderTarget(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t HwCtxSetDepthRenderTarget(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t); uint32_t);
uint32_t HwCtxSetStencilInfo(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 HwCtxSetDepthHtileSurface(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
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);
uint32_t HwCtxSetWindowOffset(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 HwCtxSetModeControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPolyOffsetRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t HwCtxSetPolyOffsetRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
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);
uint32_t HwCtxSetLineControl(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 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 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 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 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 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 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 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 HwCtxSetVtxControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPaScExtendedControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t HwCtxSetPaScExtendedControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t); uint32_t);
uint32_t HwCtxSetAlphaToMask(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 HwCtxSetDrawPayloadControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t); uint32_t);
uint32_t HwCtxSetPrimitiveIdReset(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 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 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 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 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 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 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 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 HwCtxSetViewportZ(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetViewportScaleOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t HwCtxSetViewportScaleOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t); uint32_t);
uint32_t HwShSetPsUserSgpr(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 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 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 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 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 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 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 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 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 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 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 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 HwUcSetObjectId(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetTextureGradientFactors(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t HwUcSetTextureGradientFactors(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t); uint32_t);
uint32_t HwUcSetIaMultiVgtParam(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 HwUcSetMultiPrimIbReset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetBorderColorTableAddr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t HwUcSetBorderColorTableAddr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t); uint32_t);
uint32_t HwUcSetGeIndexOffset(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 CpOpReleaseMem(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
} // namespace Libs::Graphics } // namespace Libs::Graphics
File diff suppressed because it is too large. Load diff
+30 -33
View File
@@ -122,8 +122,8 @@ public:
void WaitForIdle(); void WaitForIdle();
bool IsIdle(); bool IsIdle();
void SetCp(CommandProcessor* cp) { void SetCp(CommandProcessor& cp) {
m_cp = cp; m_cp = &cp;
Start(); Start();
} }
@@ -171,8 +171,8 @@ public:
void WaitForIdle(); void WaitForIdle();
bool IsIdle(); bool IsIdle();
void SetCp(CommandProcessor* cp) { void SetCp(CommandProcessor& cp) {
m_cp = cp; m_cp = &cp;
Start(); Start();
} }
@@ -382,7 +382,7 @@ void Gpu::Init() {
m_gfx_cp = new CommandProcessor; m_gfx_cp = new CommandProcessor;
m_gfx_ring = new GraphicsRing; m_gfx_ring = new GraphicsRing;
m_gfx_cp->SetQueue(GraphicContext::QUEUE_GFX); 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); EXIT_IF(GraphicContext::QUEUE_COMPUTE_NUM < 8);
} }
@@ -400,7 +400,7 @@ ComputeRing* Gpu::GetRing(uint32_t ring_id) {
if (m_compute_ring[v] == nullptr) { if (m_compute_ring[v] == nullptr) {
m_compute_ring[v] = new ComputeRing; m_compute_ring[v] = new ComputeRing;
m_compute_ring[v]->SetQueueId(queue_id); 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]; return m_compute_ring[v];
@@ -475,14 +475,12 @@ void CommandProcessor::BufferFlush() {
} }
void CommandProcessor::BufferFlushAndWait() { void CommandProcessor::BufferFlushAndWait() {
CommandBuffer* submitted = nullptr; auto& submitted = [&]() -> CommandBuffer& {
{
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
submitted = m_scheduler.FlushAndGetSubmitted(); return m_scheduler.FlushAndGetSubmitted();
} }();
submitted->WaitForFence(); submitted.WaitForFence();
} }
void CommandProcessor::BufferWait() { void CommandProcessor::BufferWait() {
@@ -493,7 +491,7 @@ void CommandProcessor::BufferWait() {
std::array<CommandBuffer*, CommandScheduler::BuffersNum> buffers {}; std::array<CommandBuffer*, CommandScheduler::BuffersNum> buffers {};
{ {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
m_scheduler.CopyBuffers(&buffers); m_scheduler.CopyBuffers(buffers);
} }
for (auto* buf: buffers) { for (auto* buf: buffers) {
@@ -691,13 +689,13 @@ 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); EXIT("unsupported dmaData destination selector 0x%02" PRIx8 "\n", dst_sel);
} }
if (src_sel == 2) { if (src_sel == 2) {
GetGpuResources()->FillBuffer( GetGpuResources().FillBuffer(
CurrentBuffer(), dst_address_or_offset, num_bytes, CurrentBuffer(), dst_address_or_offset, num_bytes,
static_cast<uint32_t>(src_address_or_offset_or_immediate & 0xffffffffu)); static_cast<uint32_t>(src_address_or_offset_or_immediate & 0xffffffffu));
return; return;
} }
if (src_memory) { if (src_memory) {
GetGpuResources()->CopyBuffer(CurrentBuffer(), dst_address_or_offset, GetGpuResources().CopyBuffer(CurrentBuffer(), dst_address_or_offset,
src_address_or_offset_or_immediate, num_bytes); src_address_or_offset_or_immediate, num_bytes);
return; return;
} }
@@ -960,11 +958,11 @@ void CommandProcessor::Run(uint32_t* data, uint32_t num_dw) {
KYTY_PROFILER_BLOCK("CommandProcessor::Run"); KYTY_PROFILER_BLOCK("CommandProcessor::Run");
struct RunScope { 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; } ~RunScope() { g_current_run_cp = prev; }
CommandProcessor* prev; CommandProcessor* prev;
} run_scope(this); } run_scope(*this);
auto* cmd = data; auto* cmd = data;
auto dw = num_dw; 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); 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); // 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", "\n",
vertex_offset_add, first_instance); vertex_offset_add, first_instance);
} }
RenderDrawIndex(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, m_index_type_and_size, RenderDrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr,
index_count, index_addr, flags, type, instance_count, flags, type, instance_count, render_target_slice_offset, vertex_offset_add,
render_target_slice_offset, vertex_offset_add, first_instance); first_instance);
} }
void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_count, 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<const void*>( auto* index_addr = reinterpret_cast<const void*>(
m_index_base_addr + static_cast<uint64_t>(index_offset) * index_size); m_index_base_addr + static_cast<uint64_t>(index_offset) * index_size);
RenderDrawIndex(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, m_index_type_and_size, RenderDrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr,
index_count, index_addr, flags, 1, m_num_instances); flags, 1, m_num_instances);
} }
void CommandProcessor::DrawIndirect(uint32_t data_offset, uint32_t draw_initiator, bool indexed) { 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, RenderDispatchDirect(m_submit_id, CurrentBuffer(), thread_group_x, thread_group_y,
thread_group_y, thread_group_z, mode); thread_group_z, mode);
} }
constexpr uint32_t DispatchInitiatorUseThreadDimensions = 1u << 5u; constexpr uint32_t DispatchInitiatorUseThreadDimensions = 1u << 5u;
@@ -1442,9 +1440,8 @@ void CommandProcessor::DrawIndexAuto(uint32_t index_count, uint32_t flags,
CheckBuffer(); CheckBuffer();
RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, index_count, RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), index_count, flags,
flags, render_target_slice_offset, instance_count, first_vertex, render_target_slice_offset, instance_count, first_vertex, first_instance);
first_instance);
} }
void CommandProcessor::WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index) { void CommandProcessor::WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index) {
@@ -1778,7 +1775,7 @@ void CommandProcessor::Flip() {
LOGF("CommandProcessor::Flip()\n"); LOGF("CommandProcessor::Flip()\n");
} }
auto* command = CurrentBuffer(); auto& command = CurrentBuffer();
auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index, auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg); m_flip.flip_mode, m_flip.flip_arg);
Sync::WriteAtEndOfPipeOnlyFlip(m_submit_id, command, m_flip.handle, m_flip.index, 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)); 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, auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg); m_flip.flip_mode, m_flip.flip_arg);
Sync::WriteAtEndOfPipeWithFlip32(m_submit_id, command, static_cast<uint32_t*>(dst_gpu_addr), Sync::WriteAtEndOfPipeWithFlip32(m_submit_id, command, static_cast<uint32_t*>(dst_gpu_addr),
@@ -1827,7 +1824,7 @@ void CommandProcessor::FlipWithInterrupt(uint32_t eop_event_type, uint32_t cache
EXIT("unknown event type\n"); EXIT("unknown event type\n");
} }
std::memcpy(dst_gpu_addr, &value, sizeof(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, auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg); m_flip.flip_mode, m_flip.flip_arg);
Sync::WriteAtEndOfPipeWithInterruptWriteBackFlip32( Sync::WriteAtEndOfPipeWithInterruptWriteBackFlip32(
@@ -1843,10 +1840,10 @@ void CommandProcessor::PrepareCpuFlip() {
EXIT("invalid graphics-thread CPU flip preparation\n"); EXIT("invalid graphics-thread CPU flip preparation\n");
} }
struct RunScope { 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() { g_current_run_cp = nullptr; }
}; };
RunScope run_scope(this); RunScope run_scope(*this);
auto prepared_id = Presentation::DisplayBufferPrepareNextFlipOnGpu(CurrentBuffer()); auto prepared_id = Presentation::DisplayBufferPrepareNextFlipOnGpu(CurrentBuffer());
m_scheduler.Flush(); m_scheduler.Flush();
+93 -95
View File
@@ -404,33 +404,33 @@ struct TextureBlockLayout {
uint32_t block_size; 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; uint32_t width_log2 = 0, height_log2 = 0;
if (tile == 1 && Gen5Standard256BLayout(format, &out->bytes, &out->texel_width, if (tile == 1 && Gen5Standard256BLayout(format, &out.bytes, &out.texel_width,
&out->texel_height, &width_log2, &height_log2)) { &out.texel_height, &width_log2, &height_log2)) {
out->block_size = 256; out.block_size = 256;
} else if (tile == 5 && Gen5Standard4KBLayout(format, &out->bytes, &out->texel_width, } else if (tile == 5 && Gen5Standard4KBLayout(format, &out.bytes, &out.texel_width,
&out->texel_height, &width_log2, &height_log2)) { &out.texel_height, &width_log2, &height_log2)) {
out->block_size = 4096; out.block_size = 4096;
} else if ((tile == 9 || tile == 17) && } 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)) { &width_log2, &height_log2)) {
out->block_size = 65536; out.block_size = 65536;
} else if (tile == 24 || tile == 27) { } else if (tile == 24 || tile == 27) {
out->bytes = Prospero::NumBytesPerElement(format); out.bytes = Prospero::NumBytesPerElement(format);
out->texel_width = out->texel_height = 1; out.texel_width = out.texel_height = 1;
if (out->bytes == 0 || (tile == 24 && out->bytes > 8) || if (out.bytes == 0 || (tile == 24 && out.bytes > 8) ||
!Gen5Thin64KBBlockSizeFromElementBytes(out->bytes, &out->block_width, !Gen5Thin64KBBlockSizeFromElementBytes(out.bytes, &out.block_width,
&out->block_height)) { &out.block_height)) {
return false; return false;
} }
out->block_size = 65536; out.block_size = 65536;
return true; return true;
} else { } else {
return false; return false;
} }
out->block_width = 1u << width_log2; out.block_width = 1u << width_log2;
out->block_height = 1u << height_log2; out.block_height = 1u << height_log2;
return true; 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, bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height, uint32_t depth,
uint32_t levels, uint32_t tile, TileVolumeLayout* out) { uint32_t levels, uint32_t tile, TileVolumeLayout& out) {
if (out == nullptr || width == 0 || height == 0 || depth == 0 || levels == 0 || levels > 16) { if (width == 0 || height == 0 || depth == 0 || levels == 0 || levels > 16) {
return false; return false;
} }
TextureBlockLayout element {}; TextureBlockLayout element {};
if (!GetTextureBlockLayout(format, tile, &element)) return false; if (!GetTextureBlockLayout(format, tile, element)) return false;
TileBlockFamily family = TileBlockFamily::Count; TileBlockFamily family = TileBlockFamily::Count;
switch (tile) { switch (tile) {
@@ -541,15 +541,15 @@ bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height
default: return false; default: return false;
} }
TileBlockLayout block {}; TileBlockLayout block {};
if (!TileGetBlockLayout(family, element.bytes, &block)) return false; if (!TileGetBlockLayout(family, element.bytes, block)) return false;
*out = {}; out = {};
out->family = family; out.family = family;
out->bytes_per_element = element.bytes; out.bytes_per_element = element.bytes;
out->texel_width = element.texel_width; out.texel_width = element.texel_width;
out->texel_height = element.texel_height; out.texel_height = element.texel_height;
out->block_depth = block.block_depth; out.block_depth = block.block_depth;
out->first_tail_level = levels; out.first_tail_level = levels;
const uint32_t width0 = (width + element.texel_width - 1u) / element.texel_width; 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 uint32_t height0 = (height + element.texel_height - 1u) / element.texel_height;
const bool thick4 = family == TileBlockFamily::Standard4KB3D; 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); const uint32_t mip_height = std::max(ShiftCeil(height0, level), 1u);
if (levels > 1 && mip_width <= tail_width && mip_height <= tail_height && if (levels > 1 && mip_width <= tail_width && mip_height <= tail_height &&
levels - level <= max_tail) { levels - level <= max_tail) {
out->first_tail_level = level; out.first_tail_level = level;
out->block_slice_size += block.block_size; out.block_slice_size += block.block_size;
break; break;
} }
out->level_widths[level] = AlignUp(mip_width, block.block_width); out.level_widths[level] = AlignUp(mip_width, block.block_width);
out->level_heights[level] = AlignUp(mip_height, block.block_height); out.level_heights[level] = AlignUp(mip_height, block.block_height);
out->level_sizes[level] = static_cast<uint64_t>(block.block_depth) * out.level_sizes[level] = static_cast<uint64_t>(block.block_depth) *
out->level_widths[level] * out->level_heights[level] * out.level_widths[level] * out.level_heights[level] *
element.bytes; 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); const auto bytes_log2 = std::countr_zero(element.bytes);
for (uint32_t level = out->first_tail_level; level < levels; ++level) { for (uint32_t level = out.first_tail_level; level < levels; ++level) {
const auto index = level - out->first_tail_level; const auto index = level - out.first_tail_level;
const auto tail = thick4 ? GEN5_MIP_TAIL_LOCATIONS_THICK_4KB[bytes_log2][index] const auto tail = thick4 ? GEN5_MIP_TAIL_LOCATIONS_THICK_4KB[bytes_log2][index]
: (thick64 ? GEN5_MIP_TAIL_LOCATIONS_THICK_64KB[bytes_log2][index] : (thick64 ? GEN5_MIP_TAIL_LOCATIONS_THICK_64KB[bytes_log2][index]
: GEN5_MIP_TAIL_LOCATIONS_THIN_64KB[bytes_log2][index]); : GEN5_MIP_TAIL_LOCATIONS_THIN_64KB[bytes_log2][index]);
out->level_sizes[level] = block.block_size; out.level_sizes[level] = block.block_size;
out->level_widths[level] = block.block_width; out.level_widths[level] = block.block_width;
out->level_heights[level] = block.block_height; out.level_heights[level] = block.block_height;
out->tail_x[level] = tail.x; out.tail_x[level] = tail.x;
out->tail_y[level] = tail.y; out.tail_y[level] = tail.y;
} }
uint64_t offset = out->first_tail_level < levels ? block.block_size : 0; uint64_t offset = out.first_tail_level < levels ? block.block_size : 0;
for (int32_t l = static_cast<int32_t>(out->first_tail_level) - 1; l >= 0; --l) { for (int32_t l = static_cast<int32_t>(out.first_tail_level) - 1; l >= 0; --l) {
out->level_offsets[l] = offset; out.level_offsets[l] = offset;
offset += out->level_sizes[l]; offset += out.level_sizes[l];
} }
out->total_size = out->block_slice_size * ShiftCeil(depth, std::countr_zero(block.block_depth)); out.total_size = out.block_slice_size * ShiftCeil(depth, std::countr_zero(block.block_depth));
return offset == out->block_slice_size; return offset == out.block_slice_size;
} }
static uint32_t Gen5Standard4KBOffsetInBlock(uint32_t x, uint32_t y, uint32_t bytes_per_element) { 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); static constexpr uint32_t Depth64KB64YOffsetBytes(uint32_t y);
bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element, bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element,
TileBlockLayout* layout) { TileBlockLayout& layout) {
if (layout == nullptr || !std::has_single_bit(bytes_per_element) || bytes_per_element > 16) { if (!std::has_single_bit(bytes_per_element) || bytes_per_element > 16) {
return false; return false;
} }
@@ -1121,15 +1121,14 @@ bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element,
result.block_size) { result.block_size) {
return false; return false;
} }
*layout = result; layout = result;
return true; return true;
} }
bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, uint32_t z, bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, uint32_t z,
uint32_t* byte_offset) { uint32_t& byte_offset) {
TileBlockLayout expected {}; TileBlockLayout expected {};
if (byte_offset == nullptr || if (!TileGetBlockLayout(layout.family, layout.bytes_per_element, expected) ||
!TileGetBlockLayout(layout.family, layout.bytes_per_element, &expected) ||
layout.block_size != expected.block_size || layout.block_width != expected.block_width || layout.block_size != expected.block_size || layout.block_width != expected.block_width ||
layout.block_height != expected.block_height || layout.block_height != expected.block_height ||
layout.block_depth != expected.block_depth || x >= layout.block_width || 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) { if (offset >= layout.block_size || offset % layout.bytes_per_element != 0) {
return false; return false;
} }
*byte_offset = offset; byte_offset = offset;
return true; return true;
} }
bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y, 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); return TileGetBlockXor(layout, block_x, block_y, 0, byte_offset);
} }
bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y, 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 {}; TileBlockLayout expected {};
if (byte_offset == nullptr || if (!TileGetBlockLayout(layout.family, layout.bytes_per_element, expected) ||
!TileGetBlockLayout(layout.family, layout.bytes_per_element, &expected) ||
layout.block_size != expected.block_size || layout.block_width != expected.block_width || layout.block_size != expected.block_size || layout.block_width != expected.block_width ||
layout.block_height != expected.block_height || layout.block_height != expected.block_height ||
layout.block_depth != expected.block_depth) { layout.block_depth != expected.block_depth) {
@@ -1246,7 +1244,7 @@ bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t b
block_y > UINT32_MAX / layout.block_height) { block_y > UINT32_MAX / layout.block_height) {
return false; return false;
} }
*byte_offset = Depth64KB64XOffsetBytes(block_x * layout.block_width) ^ byte_offset = Depth64KB64XOffsetBytes(block_x * layout.block_width) ^
Depth64KB64YOffsetBytes(block_y * layout.block_height); Depth64KB64YOffsetBytes(block_y * layout.block_height);
} else if (layout.family == TileBlockFamily::RenderTarget64KB) { } else if (layout.family == TileBlockFamily::RenderTarget64KB) {
if (block_x > UINT32_MAX / layout.block_width || if (block_x > UINT32_MAX / layout.block_width ||
@@ -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 x = block_x * layout.block_width;
const auto y = block_y * layout.block_height; const auto y = block_y * layout.block_height;
switch (layout.bytes_per_element) { switch (layout.bytes_per_element) {
case 1: *byte_offset = Gen5RenderTargetOffsetInBlock<uint8_t>(x, y); break; case 1: byte_offset = Gen5RenderTargetOffsetInBlock<uint8_t>(x, y); break;
case 2: *byte_offset = Gen5RenderTargetOffsetInBlock<uint16_t>(x, y); break; case 2: byte_offset = Gen5RenderTargetOffsetInBlock<uint16_t>(x, y); break;
case 4: *byte_offset = Gen5RenderTargetOffsetInBlock<uint32_t>(x, y); break; case 4: byte_offset = Gen5RenderTargetOffsetInBlock<uint32_t>(x, y); break;
case 8: *byte_offset = Gen5RenderTargetOffsetInBlock<uint64_t>(x, y); break; case 8: byte_offset = Gen5RenderTargetOffsetInBlock<uint64_t>(x, y); break;
case 16: *byte_offset = Gen5RenderTargetOffsetInBlock<Uint128>(x, y); break; case 16: byte_offset = Gen5RenderTargetOffsetInBlock<Uint128>(x, y); break;
default: return false; default: return false;
} }
} else { } else {
*byte_offset = 0; byte_offset = 0;
} }
if (layout.family == TileBlockFamily::RenderTarget64KB || if (layout.family == TileBlockFamily::RenderTarget64KB ||
layout.family == TileBlockFamily::Depth64KB) { layout.family == TileBlockFamily::Depth64KB) {
*byte_offset ^= ((block_z & 8u) << 5u) ^ ((block_z & 4u) << 7u) ^ ((block_z & 2u) << 9u) ^ byte_offset ^= ((block_z & 8u) << 5u) ^ ((block_z & 4u) << 7u) ^ ((block_z & 2u) << 9u) ^
((block_z & 1u) << 11u); ((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) { static constexpr uint32_t Depth64KB8XOffsetBytes(uint32_t x) {
@@ -1362,8 +1360,8 @@ static_assert(Depth64KB32XOffsetBytes(2) == 0x0010u);
static_assert(Depth64KB32YOffsetBytes(1) == 0x0008u); static_assert(Depth64KB32YOffsetBytes(1) == 0x0008u);
static_assert((Depth64KB32XOffsetBytes(3) ^ Depth64KB32YOffsetBytes(5)) == 0x009cu); static_assert((Depth64KB32XOffsetBytes(3) ^ Depth64KB32YOffsetBytes(5)) == 0x009cu);
bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign* htile_size) { bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& htile_size) {
*htile_size = {}; htile_size = {};
if (width == 0 || width > 16384 || height == 0 || height > 16384) { if (width == 0 || width > 16384 || height == 0 || height > 16384) {
return false; return false;
} }
@@ -1374,13 +1372,13 @@ bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign* htile_size
if (size == 0 || size > UINT32_MAX) { if (size == 0 || size > UINT32_MAX) {
return false; return false;
} }
*htile_size = {static_cast<uint32_t>(size), 32768}; htile_size = {static_cast<uint32_t>(size), 32768};
return true; return true;
} }
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format, bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format,
uint32_t stencil_format, bool htile, TileSizeAlign* stencil_size, uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size,
TileSizeAlign* htile_size, TileSizeAlign* depth_size, TileSizeAlign& htile_size, TileSizeAlign& depth_size,
uint32_t num_fragments_log2) { uint32_t num_fragments_log2) {
EXIT_IF(pitch != 0); EXIT_IF(pitch != 0);
// Prospero derives uncompressed depth/stencil as independent 64 KiB block surfaces. // 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 AlignUp(height, stencil_block_height) * fragments
: 0; : 0;
TileSizeAlign calculated_htile {}; 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) { if (depth_bytes_total <= UINT32_MAX && stencil_bytes_total <= UINT32_MAX && htile_valid) {
*depth_size = {static_cast<uint32_t>(depth_bytes_total), 65536}; depth_size = {static_cast<uint32_t>(depth_bytes_total), 65536};
*stencil_size = stencil_format == 1 stencil_size = stencil_format == 1
? TileSizeAlign {static_cast<uint32_t>(stencil_bytes_total), 65536} ? TileSizeAlign {static_cast<uint32_t>(stencil_bytes_total), 65536}
: TileSizeAlign {}; : TileSizeAlign {};
*htile_size = calculated_htile; htile_size = calculated_htile;
return true; return true;
} }
} }
*depth_size = TileSizeAlign(); depth_size = TileSizeAlign();
*htile_size = TileSizeAlign(); htile_size = TileSizeAlign();
*stencil_size = TileSizeAlign(); stencil_size = TileSizeAlign();
return false; 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, 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) { uint32_t num_fragments_log2) {
*total_size = {}; total_size = {};
uint32_t block_width = 0; uint32_t block_width = 0;
uint32_t block_height = 0; uint32_t block_height = 0;
if (height == 0 || pitch == 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) { if (size == 0 || size > UINT32_MAX) {
return false; return false;
} }
total_size->size = static_cast<uint32_t>(size); total_size.size = static_cast<uint32_t>(size);
total_size->align = 65536; total_size.align = 65536;
return true; return true;
} }
bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch, bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch,
uint32_t bytes_per_element, uint32_t levels, uint32_t bytes_per_element, uint32_t levels,
TileSizeAlign* total_size, TileSizeOffset* level_sizes, TileSizeAlign& total_size, TileSizeOffset* level_sizes,
TilePaddedSize* padded_size) { TilePaddedSize* padded_size) {
*total_size = {}; total_size = {};
if (width == 0 || height == 0 || levels == 0 || levels > 16 || if (width == 0 || height == 0 || levels == 0 || levels > 16 ||
pitch != TileGetRenderTargetPitch(width, bytes_per_element)) { pitch != TileGetRenderTargetPitch(width, bytes_per_element)) {
return false; return false;
@@ -1494,9 +1492,9 @@ bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitc
default: return false; default: return false;
} }
TileGetTextureSize(format, width, height, pitch, levels, TileGetTextureSize(format, width, height, pitch, levels,
Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), total_size, Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), &total_size,
level_sizes, padded_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, 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 {}; TextureBlockLayout block {};
if (GetTextureBlockLayout(format, tile, &block)) { if (GetTextureBlockLayout(format, tile, block)) {
if (tile == 1) { if (tile == 1) {
SetMicroMipLayout(block, width, height, levels, total_size, level_sizes, padded_size); SetMicroMipLayout(block, width, height, levels, total_size, level_sizes, padded_size);
} else { } 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, 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, uint32_t pitch, uint32_t levels, uint32_t tile, bool volume_texture,
TileSizeAlign* total_size) { TileSizeAlign& total_size) {
EXIT_NOT_IMPLEMENTED(depth == 0); EXIT_NOT_IMPLEMENTED(depth == 0);
if (volume_texture) { if (volume_texture) {
TileVolumeLayout volume {}; 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); EXIT_NOT_IMPLEMENTED(volume.total_size > UINT32_MAX);
total_size->size = static_cast<uint32_t>(volume.total_size); total_size.size = static_cast<uint32_t>(volume.total_size);
total_size->align = tile == 5 ? 4096u : 65536u; total_size.align = tile == 5 ? 4096u : 65536u;
return; return;
} }
} }
TileSizeAlign slice_size {}; TileSizeAlign slice_size {};
TileGetTextureSize(format, width, height, pitch, levels, tile, &slice_size, nullptr, nullptr); 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<uint64_t>(slice_size.size) * depth; const uint64_t total = static_cast<uint64_t>(slice_size.size) * depth;
EXIT_NOT_IMPLEMENTED(total > 0xffffffffull); EXIT_NOT_IMPLEMENTED(total > 0xffffffffull);
total_size->size = static_cast<uint32_t>(total); total_size.size = static_cast<uint32_t>(total);
} }
uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t levels, uint32_t tile) { uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t levels, uint32_t tile) {
+11 -11
View File
@@ -65,41 +65,41 @@ struct TileVolumeLayout {
}; };
bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element, 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, 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, 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, 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 TileIsStandard256BTextureSupported(uint32_t format);
bool TileIsStandard4KBTextureSupported(uint32_t format); bool TileIsStandard4KBTextureSupported(uint32_t format);
bool TileIsStandard64KBTextureSupported(uint32_t format); bool TileIsStandard64KBTextureSupported(uint32_t format);
bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, 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, bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format,
uint32_t stencil_format, bool htile, TileSizeAlign* stencil_size, uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size,
TileSizeAlign* htile_size, TileSizeAlign* depth_size, TileSizeAlign& htile_size, TileSizeAlign& depth_size,
uint32_t num_fragments_log2 = 0); uint32_t num_fragments_log2 = 0);
uint32_t TileGetRenderTargetPitch(uint32_t width, uint32_t bytes_per_element, uint32_t TileGetRenderTargetPitch(uint32_t width, uint32_t bytes_per_element,
uint32_t num_fragments_log2 = 0); uint32_t num_fragments_log2 = 0);
uint32_t TileGetDepthPitch(uint32_t width, uint32_t bytes_per_element, uint32_t TileGetDepthPitch(uint32_t width, uint32_t bytes_per_element,
uint32_t num_fragments_log2 = 0); uint32_t num_fragments_log2 = 0);
bool TileGetRenderTargetSize(uint32_t width, uint32_t height, uint32_t pitch, 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); uint32_t num_fragments_log2 = 0);
bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch, bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch,
uint32_t bytes_per_element, uint32_t levels, uint32_t bytes_per_element, uint32_t levels,
TileSizeAlign* total_size, TileSizeOffset* level_sizes, TileSizeAlign& total_size, TileSizeOffset* level_sizes,
TilePaddedSize* padded_size); TilePaddedSize* padded_size);
void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch, void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch,
uint32_t levels, uint32_t tile, TileSizeAlign* total_size, uint32_t levels, uint32_t tile, TileSizeAlign* total_size,
TileSizeOffset* level_sizes, TilePaddedSize* padded_size); TileSizeOffset* level_sizes, TilePaddedSize* padded_size);
void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, 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, 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); uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t levels, uint32_t tile);
} // namespace Libs::Graphics } // namespace Libs::Graphics
+112 -107
View File
@@ -21,6 +21,7 @@
#include <array> #include <array>
#include <bit> #include <bit>
#include <cstring> #include <cstring>
#include <memory>
#include <vector> #include <vector>
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -86,17 +87,17 @@ struct Resources {
void* mapped = nullptr; void* mapped = nullptr;
}; };
bool CheckedAdd(uint64_t a, uint64_t b, uint64_t* result) { bool CheckedAdd(uint64_t a, uint64_t b, uint64_t& result) {
return b <= UINT64_MAX - a && (*result = a + b, true); return b <= UINT64_MAX - a && (result = a + b, true);
} }
bool CheckedMultiply(uint64_t a, uint64_t b, uint64_t* result) { bool CheckedMultiply(uint64_t a, uint64_t b, uint64_t& result) {
return (a == 0 || b <= UINT64_MAX / a) && (*result = a * b, true); 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; 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) { 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); command.pipelineBarrier(src_stage, dst_stage, {}, 0, nullptr, 1, &barrier, 0, nullptr);
} }
class Tiler final { class TileCompute final {
public: public:
void Run(bool to_tiled, GraphicContext* context, const void* input, void* output, explicit TileCompute(GraphicContext& graphics): graphics(graphics) {}
uint64_t tiled_capacity, uint64_t linear_capacity, std::span<const GpuTileInfo> infos, void Run(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
const GpuTileRecord& record); const GpuTileRecord& record);
void Release(GraphicContext* context); void Release();
private: private:
void Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capacity, void Prepare(bool to_tiled, uint64_t tiled_capacity, uint64_t linear_capacity,
uint64_t linear_capacity, std::span<const GpuTileInfo> infos, std::span<const GpuTileInfo> infos, std::vector<Dispatch>& dispatches) const;
std::vector<Dispatch>* dispatches) const; void Init();
void Init(GraphicContext* context);
void CreatePipelines(std::span<const Dispatch> dispatches); void CreatePipelines(std::span<const Dispatch> dispatches);
void CreatePipeline(uint32_t pipeline_slot); void CreatePipeline(uint32_t pipeline_slot);
void Resize(uint64_t staging_size, uint64_t linear_size); 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, void Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const Dispatch> dispatches, uint64_t linear_capacity, std::span<const Dispatch> dispatches,
const GpuTileRecord& record); const GpuTileRecord& record);
void Destroy(Resources* target) const; void Destroy(Resources& target) const;
Common::Mutex mutex; GraphicContext& graphics;
GraphicContext* ctx = nullptr;
Resources resources; Resources resources;
}; };
Tiler g_tiler; Common::Mutex g_tiler_mutex;
std::unique_ptr<TileCompute> g_tiler;
void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capacity, void TileCompute::Prepare(bool to_tiled, uint64_t tiled_capacity, uint64_t linear_capacity,
uint64_t linear_capacity, std::span<const GpuTileInfo> infos, std::span<const GpuTileInfo> infos,
std::vector<Dispatch>* dispatches) const { std::vector<Dispatch>& dispatches) const {
EXIT_IF(context == nullptr || g_render_ctx == nullptr || EXIT_IF(infos.empty() || tiled_capacity == 0 || linear_capacity == 0);
g_render_ctx->GetGraphicCtx() != context || infos.empty() || tiled_capacity == 0 || const auto& limits = graphics.GetPhysicalDeviceProperties().limits;
linear_capacity == 0);
const auto& limits = context->GetPhysicalDeviceProperties().limits;
EXIT_NOT_IMPLEMENTED(tiled_capacity > UINT32_MAX || linear_capacity > UINT32_MAX || EXIT_NOT_IMPLEMENTED(tiled_capacity > UINT32_MAX || linear_capacity > UINT32_MAX ||
AlignToDword(tiled_capacity) > limits.maxStorageBufferRange || AlignToDword(tiled_capacity) > limits.maxStorageBufferRange ||
AlignToDword(linear_capacity) > limits.maxStorageBufferRange); AlignToDword(linear_capacity) > limits.maxStorageBufferRange);
dispatches->clear(); dispatches.clear();
dispatches->reserve(infos.size()); dispatches.reserve(infos.size());
for (const auto& info: infos) { for (const auto& info: infos) {
TileBlockLayout block {}; TileBlockLayout block {};
const uint32_t tiled_width = info.tiled_width != 0 ? info.tiled_width : info.pitch; 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; const uint32_t tiled_height = info.tiled_height != 0 ? info.tiled_height : info.height;
EXIT_NOT_IMPLEMENTED( 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.height == 0 || info.depth == 0 || info.pitch < info.width ||
(!info.tail && (tiled_width < info.width || tiled_height < info.height)) || (!info.tail && (tiled_width < info.width || tiled_height < info.height)) ||
!IsRangeValid(info.linear_offset, info.linear_size, linear_capacity) || !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)); (block.block_depth == 1 && info.depth != 1));
uint64_t elements = 0, pitch_bytes = 0; uint64_t elements = 0, pitch_bytes = 0;
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(info.width, info.height, &elements) || EXIT_NOT_IMPLEMENTED(!CheckedMultiply(info.width, info.height, elements) ||
!CheckedMultiply(elements, info.depth, &elements) || !CheckedMultiply(elements, info.depth, elements) ||
!CheckedMultiply(info.pitch, info.bytes_per_element, &pitch_bytes) || !CheckedMultiply(info.pitch, info.bytes_per_element, pitch_bytes) ||
elements > UINT32_MAX || pitch_bytes > UINT32_MAX); elements > UINT32_MAX || pitch_bytes > UINT32_MAX);
uint64_t slice_bytes = info.linear_slice_stride; uint64_t slice_bytes = info.linear_slice_stride;
EXIT_NOT_IMPLEMENTED(slice_bytes == 0 && 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; 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) || (info.depth > 1 && slice_bytes < minimum_slice) ||
!CheckedAddProduct(&linear_used, info.depth - 1u, slice_bytes) || !CheckedAddProduct(linear_used, info.depth - 1u, slice_bytes) ||
!CheckedAddProduct(&linear_used, info.height - 1u, pitch_bytes) || !CheckedAddProduct(linear_used, info.height - 1u, pitch_bytes) ||
!CheckedAddProduct(&linear_used, info.width, info.bytes_per_element) || !CheckedAddProduct(linear_used, info.width, info.bytes_per_element) ||
linear_used > info.linear_size || slice_bytes > UINT32_MAX); linear_used > info.linear_size || slice_bytes > UINT32_MAX);
const uint64_t columns = const uint64_t columns =
@@ -203,7 +202,7 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac
const uint64_t rows = const uint64_t rows =
(static_cast<uint64_t>(tiled_height) + block.block_height - 1u) / block.block_height; (static_cast<uint64_t>(tiled_height) + block.block_height - 1u) / block.block_height;
uint64_t blocks_per_slice = 0; 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 || columns > UINT32_MAX || blocks_per_slice > UINT32_MAX ||
rows * block.block_height > UINT32_MAX); rows * block.block_height > UINT32_MAX);
if (info.tail) { if (info.tail) {
@@ -217,8 +216,8 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac
const uint64_t slices = const uint64_t slices =
(static_cast<uint64_t>(info.depth) + block.block_depth - 1u) / block.block_depth; (static_cast<uint64_t>(info.depth) + block.block_depth - 1u) / block.block_depth;
uint64_t tiled_used = 0; uint64_t tiled_used = 0;
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(blocks_per_slice, slices, &tiled_used) || EXIT_NOT_IMPLEMENTED(!CheckedMultiply(blocks_per_slice, slices, tiled_used) ||
!CheckedMultiply(tiled_used, block.block_size, &tiled_used) || !CheckedMultiply(tiled_used, block.block_size, tiled_used) ||
tiled_used > info.tiled_size); tiled_used > info.tiled_size);
} }
const uint32_t alignment = std::min(info.bytes_per_element, 4u); 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_x = info.tail_x;
dispatch.push.tail_y = info.tail_y; dispatch.push.tail_y = info.tail_y;
dispatch.push.tail = info.tail; dispatch.push.tail = info.tail;
dispatches->push_back(dispatch); dispatches.push_back(dispatch);
} }
} }
void Tiler::Destroy(Resources* target) const { void TileCompute::Destroy(Resources& target) const {
if (ctx == nullptr) { if (target.mapped != nullptr) {
return; graphics.UnmapMemory(target.staging.memory);
} }
if (target->mapped != nullptr) { if (target.staging.buffer != nullptr) {
VulkanUnmapMemory(ctx, &target->staging.memory); graphics.DeleteBuffer(target.staging);
} }
if (target->staging.buffer != nullptr) { if (target.linear.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &target->staging); graphics.DeleteBuffer(target.linear);
} }
if (target->linear.buffer != nullptr) { for (auto pipeline: target.pipelines) {
VulkanDeleteBuffer(ctx, &target->linear);
}
for (auto pipeline: target->pipelines) {
if (pipeline != nullptr) { if (pipeline != nullptr) {
ctx->device.destroyPipeline(pipeline, nullptr); graphics.device.destroyPipeline(pipeline, nullptr);
} }
} }
if (target->descriptor_pool != nullptr) { if (target.descriptor_pool != nullptr) {
ctx->device.destroyDescriptorPool(target->descriptor_pool, nullptr); graphics.device.destroyDescriptorPool(target.descriptor_pool, nullptr);
} }
if (target->pipeline_layout != nullptr) { if (target.pipeline_layout != nullptr) {
ctx->device.destroyPipelineLayout(target->pipeline_layout, nullptr); graphics.device.destroyPipelineLayout(target.pipeline_layout, nullptr);
} }
if (target->descriptor_layout != nullptr) { if (target.descriptor_layout != nullptr) {
ctx->device.destroyDescriptorSetLayout(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) { if (resources.pipeline_layout != nullptr) {
EXIT_IF(ctx != context);
return; return;
} }
EXIT_IF(context == nullptr || context->device == nullptr || context->allocator == nullptr); EXIT_IF(graphics.device == nullptr || graphics.allocator == nullptr);
ctx = context;
std::array<vk::DescriptorSetLayoutBinding, 2> bindings {}; std::array<vk::DescriptorSetLayoutBinding, 2> bindings {};
for (uint32_t i = 0; i < bindings.size(); i++) { for (uint32_t i = 0; i < bindings.size(); i++) {
bindings[i] = {i, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute, bindings[i] = {i, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute,
@@ -293,7 +287,7 @@ void Tiler::Init(GraphicContext* context) {
descriptor_info.sType = vk::StructureType::eDescriptorSetLayoutCreateInfo; descriptor_info.sType = vk::StructureType::eDescriptorSetLayoutCreateInfo;
descriptor_info.bindingCount = static_cast<uint32_t>(bindings.size()); descriptor_info.bindingCount = static_cast<uint32_t>(bindings.size());
descriptor_info.pBindings = bindings.data(); descriptor_info.pBindings = bindings.data();
RequireVulkanSuccess(ctx->device.createDescriptorSetLayout(&descriptor_info, nullptr, RequireVulkanSuccess(graphics.device.createDescriptorSetLayout(&descriptor_info, nullptr,
&resources.descriptor_layout), &resources.descriptor_layout),
"create GPU tiler descriptor layout"); "create GPU tiler descriptor layout");
@@ -305,7 +299,7 @@ void Tiler::Init(GraphicContext* context) {
layout_info.pushConstantRangeCount = 1; layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = &push_range; layout_info.pPushConstantRanges = &push_range;
RequireVulkanSuccess( RequireVulkanSuccess(
ctx->device.createPipelineLayout(&layout_info, nullptr, &resources.pipeline_layout), graphics.device.createPipelineLayout(&layout_info, nullptr, &resources.pipeline_layout),
"create GPU tiler pipeline layout"); "create GPU tiler pipeline layout");
vk::DescriptorPoolSize pool_size {vk::DescriptorType::eStorageBuffer, 2}; vk::DescriptorPoolSize pool_size {vk::DescriptorType::eStorageBuffer, 2};
vk::DescriptorPoolCreateInfo pool_info {}; vk::DescriptorPoolCreateInfo pool_info {};
@@ -314,18 +308,19 @@ void Tiler::Init(GraphicContext* context) {
pool_info.poolSizeCount = 1; pool_info.poolSizeCount = 1;
pool_info.pPoolSizes = &pool_size; pool_info.pPoolSizes = &pool_size;
RequireVulkanSuccess( RequireVulkanSuccess(
ctx->device.createDescriptorPool(&pool_info, nullptr, &resources.descriptor_pool), graphics.device.createDescriptorPool(&pool_info, nullptr, &resources.descriptor_pool),
"create GPU tiler descriptor pool"); "create GPU tiler descriptor pool");
vk::DescriptorSetAllocateInfo set_info {}; vk::DescriptorSetAllocateInfo set_info {};
set_info.sType = vk::StructureType::eDescriptorSetAllocateInfo; set_info.sType = vk::StructureType::eDescriptorSetAllocateInfo;
set_info.descriptorPool = resources.descriptor_pool; set_info.descriptorPool = resources.descriptor_pool;
set_info.descriptorSetCount = 1; set_info.descriptorSetCount = 1;
set_info.pSetLayouts = &resources.descriptor_layout; set_info.pSetLayouts = &resources.descriptor_layout;
RequireVulkanSuccess(ctx->device.allocateDescriptorSets(&set_info, &resources.descriptor_set), RequireVulkanSuccess(
graphics.device.allocateDescriptorSets(&set_info, &resources.descriptor_set),
"allocate GPU tiler 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 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_direction_index = pipeline_slot / BYTES_PER_ELEMENT_COUNT;
const uint32_t family_index = family_direction_index % FAMILY_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.codeSize = SHADERS[family_index].words * sizeof(uint32_t);
module_info.pCode = SHADERS[family_index].code; module_info.pCode = SHADERS[family_index].code;
vk::ShaderModule module = nullptr; 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"); "create GPU tiler shader module");
vk::PipelineShaderStageCreateInfo stage {}; vk::PipelineShaderStageCreateInfo stage {};
stage.sType = vk::StructureType::ePipelineShaderStageCreateInfo; stage.sType = vk::StructureType::ePipelineShaderStageCreateInfo;
@@ -352,13 +347,14 @@ void Tiler::CreatePipeline(uint32_t pipeline_slot) {
info.stage = stage; info.stage = stage;
info.layout = resources.pipeline_layout; info.layout = resources.pipeline_layout;
vk::Pipeline pipeline = nullptr; vk::Pipeline pipeline = nullptr;
const auto result = ctx->device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline); const auto result =
ctx->device.destroyShaderModule(module, nullptr); graphics.device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline);
graphics.device.destroyShaderModule(module, nullptr);
RequireVulkanSuccess(result, "create GPU tiler pipeline"); RequireVulkanSuccess(result, "create GPU tiler pipeline");
resources.pipelines[pipeline_slot] = pipeline; resources.pipelines[pipeline_slot] = pipeline;
} }
void Tiler::CreatePipelines(std::span<const Dispatch> dispatches) { void TileCompute::CreatePipelines(std::span<const Dispatch> dispatches) {
for (const auto& dispatch: dispatches) { for (const auto& dispatch: dispatches) {
if (resources.pipelines[dispatch.pipeline_slot] == nullptr) { if (resources.pipelines[dispatch.pipeline_slot] == nullptr) {
CreatePipeline(dispatch.pipeline_slot); CreatePipeline(dispatch.pipeline_slot);
@@ -366,18 +362,19 @@ void Tiler::CreatePipelines(std::span<const Dispatch> dispatches) {
} }
} }
void Tiler::CreateBuffer(uint64_t size, bool mapped, VulkanBuffer* buffer, void** data) const { void TileCompute::CreateBuffer(uint64_t size, bool mapped, VulkanBuffer& buffer,
buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer | void** data) const {
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; buffer.usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferSrc |
buffer->memory.property = vk::BufferUsageFlagBits::eTransferDst;
buffer.memory.property =
mapped mapped
? vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent ? vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent
: vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eDeviceLocal); : vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eDeviceLocal);
VulkanCreateBuffer(ctx, size, buffer); graphics.CreateBuffer(size, buffer);
if (mapped) VulkanMapMemory(ctx, &buffer->memory, data); 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 && if (resources.staging.buffer_size >= staging_size &&
resources.linear.buffer_size >= linear_size) { resources.linear.buffer_size >= linear_size) {
return; return;
@@ -386,17 +383,17 @@ void Tiler::Resize(uint64_t staging_size, uint64_t linear_size) {
linear_size = std::max(linear_size, resources.linear.buffer_size); linear_size = std::max(linear_size, resources.linear.buffer_size);
VulkanBuffer staging {}, linear {}; VulkanBuffer staging {}, linear {};
void* mapped = nullptr; void* mapped = nullptr;
CreateBuffer(staging_size, true, &staging, &mapped); CreateBuffer(staging_size, true, staging, &mapped);
CreateBuffer(linear_size, false, &linear, nullptr); CreateBuffer(linear_size, false, linear, nullptr);
if (resources.mapped != nullptr) VulkanUnmapMemory(ctx, &resources.staging.memory); if (resources.mapped != nullptr) graphics.UnmapMemory(resources.staging.memory);
if (resources.staging.buffer != nullptr) VulkanDeleteBuffer(ctx, &resources.staging); if (resources.staging.buffer != nullptr) graphics.DeleteBuffer(resources.staging);
if (resources.linear.buffer != nullptr) VulkanDeleteBuffer(ctx, &resources.linear); if (resources.linear.buffer != nullptr) graphics.DeleteBuffer(resources.linear);
resources.staging = staging; resources.staging = staging;
resources.linear = linear; resources.linear = linear;
resources.mapped = mapped; resources.mapped = mapped;
} }
void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity, void TileCompute::Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const Dispatch> dispatches, uint64_t linear_capacity, std::span<const Dispatch> dispatches,
const GpuTileRecord& record) { const GpuTileRecord& record) {
const uint64_t tiled_size = AlignToDword(tiled_capacity); const uint64_t tiled_size = AlignToDword(tiled_capacity);
@@ -423,7 +420,7 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til
writes[i].descriptorType = vk::DescriptorType::eStorageBuffer; writes[i].descriptorType = vk::DescriptorType::eStorageBuffer;
writes[i].pBufferInfo = &buffer_info[i]; writes[i].pBufferInfo = &buffer_info[i];
} }
ctx->device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, graphics.device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0,
nullptr); nullptr);
CommandBuffer command(GraphicContext::QUEUE_UTIL); CommandBuffer command(GraphicContext::QUEUE_UTIL);
@@ -446,7 +443,7 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
} }
if (to_tiled && record) { if (to_tiled && record) {
record(&command, &resources.linear); record(command, resources.linear);
Barrier(vk_command, resources.linear.buffer, Barrier(vk_command, resources.linear.buffer,
vk::AccessFlagBits::eTransferWrite | vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferWrite | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eShaderRead, vk::PipelineStageFlagBits::eAllCommands, 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); &resources.descriptor_set, 0, nullptr);
const uint64_t limit = const uint64_t limit =
static_cast<uint64_t>( static_cast<uint64_t>(
ctx->GetPhysicalDeviceProperties().limits.maxComputeWorkGroupCount[0]) * graphics.GetPhysicalDeviceProperties().limits.maxComputeWorkGroupCount[0]) *
GROUP_SIZE; GROUP_SIZE;
for (const auto& dispatch: dispatches) { for (const auto& dispatch: dispatches) {
vk_command.bindPipeline(vk::PipelineBindPoint::eCompute, 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::eComputeShader,
vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eHost); vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eHost);
if (!to_tiled && record) { if (!to_tiled && record) {
record(&command, &resources.linear); record(command, resources.linear);
} }
if (!to_tiled && output != nullptr) { if (!to_tiled && output != nullptr) {
const vk::BufferCopy copy {0, 0, linear_size}; 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, void TileCompute::Run(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
uint64_t tiled_capacity, uint64_t linear_capacity, uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
std::span<const GpuTileInfo> infos, const GpuTileRecord& record) { const GpuTileRecord& record) {
Common::LockGuard lock(mutex);
EXIT_IF((to_tiled && (output == nullptr || (input == nullptr && !record))) || EXIT_IF((to_tiled && (output == nullptr || (input == nullptr && !record))) ||
(!to_tiled && (input == nullptr || (output == nullptr && !record)))); (!to_tiled && (input == nullptr || (output == nullptr && !record))));
std::vector<Dispatch> dispatches; std::vector<Dispatch> dispatches;
Prepare(to_tiled, context, tiled_capacity, linear_capacity, infos, &dispatches); Prepare(to_tiled, tiled_capacity, linear_capacity, infos, dispatches);
Init(context); Init();
CreatePipelines(dispatches); CreatePipelines(dispatches);
const uint64_t staging_size = const uint64_t staging_size =
std::max(AlignToDword(tiled_capacity), AlignToDword(linear_capacity)); 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); Execute(to_tiled, input, output, tiled_capacity, linear_capacity, dispatches, record);
} }
void Tiler::Release(GraphicContext* context) { void TileCompute::Release() {
Common::LockGuard lock(mutex); Destroy(resources);
EXIT_IF(ctx != nullptr && context != ctx);
Destroy(&resources);
ctx = nullptr;
} }
} // namespace } // 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<const GpuTileInfo> infos, uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
const GpuTileRecord& after) { 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<TileCompute>(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<const GpuTileInfo> infos, uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
const GpuTileRecord& before) { 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<TileCompute>(GetRenderContext().GetGraphics());
}
g_tiler->Run(true, linear, tiled, tiled_capacity, linear_capacity, infos, before);
} }
void GpuTileRelease(GraphicContext* ctx) { void GpuTileRelease() {
g_tiler.Release(ctx); Common::LockGuard lock(g_tiler_mutex);
if (g_tiler) {
g_tiler->Release();
g_tiler.reset();
}
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
+4 -4
View File
@@ -32,14 +32,14 @@ struct GpuTileInfo {
uint32_t surface_z = 0; uint32_t surface_z = 0;
}; };
using GpuTileRecord = std::function<void(CommandBuffer*, VulkanBuffer*)>; using GpuTileRecord = std::function<void(CommandBuffer&, VulkanBuffer&)>;
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<const GpuTileInfo> infos, uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
const GpuTileRecord& after = {}); 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<const GpuTileInfo> infos, uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
const GpuTileRecord& before = {}); const GpuTileRecord& before = {});
void GpuTileRelease(GraphicContext* ctx); void GpuTileRelease();
} // namespace Libs::Graphics } // namespace Libs::Graphics
+17
View File
@@ -16,6 +16,9 @@
namespace Libs::Graphics { namespace Libs::Graphics {
class CommandBuffer; class CommandBuffer;
struct VulkanBuffer;
struct VulkanImage;
struct VulkanMemory;
struct VulkanSwapchain { struct VulkanSwapchain {
~VulkanSwapchain(); ~VulkanSwapchain();
@@ -43,6 +46,20 @@ struct VulkanCommandPool {
}; };
struct GraphicContext: public VulkanInstance { 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<vk::ExtensionProperties>& available_extensions,
std::vector<const char*>& device_extensions);
void LoadHardwareRayTracingFunctions() const;
uint32_t screen_width = 0; uint32_t screen_width = 0;
uint32_t screen_height = 0; uint32_t screen_height = 0;
std::array<Common::Mutex, QUEUES_NUM> queue_mutexes; std::array<Common::Mutex, QUEUES_NUM> queue_mutexes;
+6 -9
View File
@@ -30,11 +30,8 @@ bool IsAccessible(DWORD protect, HostMemoryAccess access) {
} // namespace } // namespace
bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAccess access, bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAccess access,
uint64_t* accessible_size) { uint64_t& accessible_size) {
if (accessible_size == nullptr) { accessible_size = 0;
return false;
}
*accessible_size = 0;
if (addr == 0 || requested_size == 0) { if (addr == 0 || requested_size == 0) {
return false; return false;
} }
@@ -87,11 +84,11 @@ bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAcce
(void)access; (void)access;
#endif #endif
*accessible_size = current - addr; accessible_size = current - addr;
return *accessible_size != 0; 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); return HostMemoryQueryRange(addr, requested_size, HostMemoryAccess::Read, readable_size);
} }
@@ -104,7 +101,7 @@ bool HostMemoryRangeIsReadable(uint64_t addr, uint64_t size) {
return false; return false;
} }
uint64_t readable_size = 0; 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 } // namespace Libs::Graphics
+2 -2
View File
@@ -8,8 +8,8 @@ namespace Libs::Graphics {
enum class HostMemoryAccess { Read, Mapped }; enum class HostMemoryAccess { Read, Mapped };
bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAccess access, bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAccess access,
uint64_t* accessible_size); uint64_t& accessible_size);
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);
bool HostMemoryIsReadable(uint64_t addr); bool HostMemoryIsReadable(uint64_t addr);
bool HostMemoryRangeIsReadable(uint64_t addr, uint64_t size); bool HostMemoryRangeIsReadable(uint64_t addr, uint64_t size);
+42 -49
View File
@@ -4,6 +4,7 @@
#include "common/threads.h" #include "common/threads.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include <algorithm> #include <algorithm>
@@ -58,17 +59,16 @@ public:
~LabelManager() { KYTY_NOT_IMPLEMENTED; } ~LabelManager() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(LabelManager); KYTY_CLASS_NO_COPY(LabelManager);
Label* Create(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2, Label* Create(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args);
const uint64_t* args); void Delete(Label& label);
void Delete(Label* label); void Set(CommandBuffer& buffer, Label& label);
void Set(CommandBuffer* buffer, Label* label);
void Drain(); void Drain();
private: private:
static void ThreadRun(void* data); static void ThreadRun(void* data);
bool Remove(Label* label); bool Remove(Label& label);
static void Destroy(Label* label); static void Destroy(Label& label);
Common::Mutex m_mutex; Common::Mutex m_mutex;
Common::CondVar m_cond_var; Common::CondVar m_cond_var;
@@ -146,7 +146,7 @@ void LabelManager::ThreadRun(void* data) {
manager->m_callbacks_in_flight += fired_labels.size(); manager->m_callbacks_in_flight += fired_labels.size();
for (auto& label: deleted_labels) { for (auto& label: deleted_labels) {
bool removed = manager->Remove(label); bool removed = manager->Remove(*label);
EXIT_NOT_IMPLEMENTED(!removed); EXIT_NOT_IMPLEMENTED(!removed);
} }
@@ -158,7 +158,7 @@ void LabelManager::ThreadRun(void* data) {
(void)finished_submissions; (void)finished_submissions;
for (auto& label: deleted_labels) { for (auto& label: deleted_labels) {
Destroy(label); Destroy(*label);
} }
for (auto& label: fired_labels) { 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) { const uint64_t* args) {
EXIT_IF(ctx == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
auto* label = new Label; auto* label = new Label;
label->status = LabelStatus::New; label->status = LabelStatus::New;
label->device = ctx->device; label->device = GetRenderContext().GetGraphics().device;
label->callbacks.callback_1 = callback_1; label->callbacks.callback_1 = callback_1;
label->callbacks.callback_2 = callback_2; label->callbacks.callback_2 = callback_2;
@@ -210,21 +208,20 @@ Label* LabelManager::Create(GraphicContext* ctx, LabelCallback callback_1, Label
return label; return label;
} }
bool LabelManager::Remove(Label* label) { bool LabelManager::Remove(Label& label) {
EXIT_IF(label == nullptr); EXIT_IF(label.device == nullptr);
EXIT_IF(label->device == nullptr);
Common::LockGuard lock(m_mutex); 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(it == m_labels.end());
EXIT_NOT_IMPLEMENTED(label->status != LabelStatus::NotActive && EXIT_NOT_IMPLEMENTED(label.status != LabelStatus::NotActive &&
label->status != LabelStatus::Active && label.status != LabelStatus::Active &&
label->status != LabelStatus::ActiveDeleted); label.status != LabelStatus::ActiveDeleted);
if (!label->submissions.empty()) { if (!label.submissions.empty()) {
label->status = LabelStatus::ActiveDeleted; label.status = LabelStatus::ActiveDeleted;
return false; return false;
} }
@@ -234,44 +231,41 @@ bool LabelManager::Remove(Label* label) {
return true; return true;
} }
void LabelManager::Destroy(Label* label) { void LabelManager::Destroy(Label& label) {
EXIT_IF(label == nullptr); EXIT_IF(label.device == nullptr);
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)) { if (Remove(label)) {
Destroy(label); Destroy(label);
} }
} }
void LabelManager::Set(CommandBuffer* buffer, Label* label) { void LabelManager::Set(CommandBuffer& buffer, Label& label) {
EXIT_IF(label == nullptr); EXIT_IF(buffer.IsInvalid());
EXIT_IF(buffer == nullptr); EXIT_IF(label.device == nullptr);
EXIT_IF(buffer->IsInvalid());
EXIT_IF(label->device == nullptr);
Common::LockGuard lock(m_mutex); 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(it == m_labels.end());
EXIT_NOT_IMPLEMENTED(label->status != LabelStatus::New && EXIT_NOT_IMPLEMENTED(label.status != LabelStatus::New &&
label->status != LabelStatus::NotActive && label.status != LabelStatus::NotActive &&
label->status != LabelStatus::Active); label.status != LabelStatus::Active);
label->status = LabelStatus::Active; label.status = LabelStatus::Active;
LabelSubmission submission {}; LabelSubmission submission {};
submission.callbacks = label->callbacks; submission.callbacks = label.callbacks;
submission.completion = std::make_shared<LabelEvent>(); submission.completion = std::make_shared<LabelEvent>();
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); EXIT_NOT_IMPLEMENTED(vk_buffer == nullptr);
@@ -281,24 +275,24 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) {
create_info.flags = {}; create_info.flags = {};
const auto create_result = 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) { if (create_result != vk::Result::eSuccess || submission.completion->event == nullptr) {
EXIT("failed to create label event: %s (%d)\n", VulkanToString(create_result).c_str(), EXIT("failed to create label event: %s (%d)\n", VulkanToString(create_result).c_str(),
static_cast<int>(create_result)); static_cast<int>(create_result));
} }
buffer->RetainResourceUntilFence(submission.completion); buffer.RetainResourceUntilFence(submission.completion);
// Labels can be reused before an earlier end-of-pipe event has been // Labels can be reused before an earlier end-of-pipe event has been
// observed by the polling thread. Capture a separate Vulkan event and // observed by the polling thread. Capture a separate Vulkan event and
// callback snapshot for each set so older writes are not lost. // 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) { if (reset_result != vk::Result::eSuccess) {
EXIT("failed to reset label event: %s (%d)\n", VulkanToString(reset_result).c_str(), EXIT("failed to reset label event: %s (%d)\n", VulkanToString(reset_result).c_str(),
static_cast<int>(reset_result)); static_cast<int>(reset_result));
} }
vk_buffer.setEvent(submission.completion->event, vk::PipelineStageFlagBits::eBottomOfPipe); vk_buffer.setEvent(submission.completion->event, vk::PipelineStageFlagBits::eBottomOfPipe);
label->submissions.push_back(submission); label.submissions.push_back(submission);
m_cond_var.SignalAll(); m_cond_var.SignalAll();
} }
@@ -324,20 +318,19 @@ void LabelInit() {
g_label_manager = new LabelManager; g_label_manager = new LabelManager;
} }
Label* LabelCreate(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2, Label* LabelCreate(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args) {
const uint64_t* args) {
EXIT_IF(g_label_manager == nullptr); 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); EXIT_IF(g_label_manager == nullptr);
g_label_manager->Delete(label); g_label_manager->Delete(label);
} }
void LabelSet(CommandBuffer* buffer, Label* label) { void LabelSet(CommandBuffer& buffer, Label& label) {
EXIT_IF(g_label_manager == nullptr); EXIT_IF(g_label_manager == nullptr);
g_label_manager->Set(buffer, label); g_label_manager->Set(buffer, label);
+3 -4
View File
@@ -15,10 +15,9 @@ void LabelInit();
constexpr int LABEL_ARGS_MAX = 5; constexpr int LABEL_ARGS_MAX = 5;
using LabelCallback = bool (*)(const uint64_t* args); using LabelCallback = bool (*)(const uint64_t* args);
Label* LabelCreate(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2, Label* LabelCreate(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args);
const uint64_t* args); void LabelDelete(Label& label);
void LabelDelete(Label* label); void LabelSet(CommandBuffer& buffer, Label& label);
void LabelSet(CommandBuffer* buffer, Label* label);
void LabelDrain(); void LabelDrain();
[[nodiscard]] bool LabelInCallback() noexcept; [[nodiscard]] bool LabelInCallback() noexcept;
+73 -76
View File
@@ -5,6 +5,7 @@
#include "graphics/guest_gpu/gpu_defs.h" #include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/gpu_format.h" #include "graphics/guest_gpu/gpu_format.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
@@ -240,25 +241,26 @@ vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle) {
return components; return components;
} }
bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info) { bool TextureCheckFormat(vk::ImageCreateInfo& image_info) {
auto& graphics = GetRenderContext().GetGraphics();
vk::ImageFormatProperties props {}; vk::ImageFormatProperties props {};
if (ctx->GetImageFormatProperties(image_info->format, image_info->imageType, image_info->tiling, if (graphics.GetImageFormatProperties(image_info.format, image_info.imageType,
image_info->usage, image_info->flags, image_info.tiling, image_info.usage, image_info.flags,
&props) == vk::Result::eErrorFormatNotSupported) { &props) == vk::Result::eErrorFormatNotSupported) {
auto apply_fallback = [&](vk::Format replacement, const char* message) { auto apply_fallback = [&](vk::Format replacement, const char* message) {
image_info->format = replacement; image_info.format = replacement;
const bool result = TextureCheckFormat(ctx, image_info); const bool result = TextureCheckFormat(image_info);
LOGF("%s [%s]\n", message, (!result ? "FAIL" : "SUCCESS")); LOGF("%s [%s]\n", message, (!result ? "FAIL" : "SUCCESS"));
return result; return result;
}; };
if (image_info->format == vk::Format::eR8G8B8A8Srgb) { if (image_info.format == vk::Format::eR8G8B8A8Srgb) {
// TODO() convert SRGB -> LINEAR in shader // TODO() convert SRGB -> LINEAR in shader
return apply_fallback( return apply_fallback(
vk::Format::eR8G8B8A8Unorm, vk::Format::eR8G8B8A8Unorm,
"replace vk::Format::eR8G8B8A8Srgb => 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 // TODO() convert SRGB -> LINEAR in shader
return apply_fallback( return apply_fallback(
vk::Format::eB8G8R8A8Unorm, vk::Format::eB8G8R8A8Unorm,
@@ -269,34 +271,31 @@ bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info) {
return true; 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 {}; vk::ImageFormatProperties props {};
return ctx->GetImageFormatProperties(image_info.format, image_info.imageType, image_info.tiling, return graphics.GetImageFormatProperties(image_info.format, image_info.imageType,
image_info.usage, image_info.flags, image_info.tiling, image_info.usage, image_info.flags,
&props) != vk::Result::eErrorFormatNotSupported; &props) != vk::Result::eErrorFormatNotSupported;
} }
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components) { bool TextureCheckStorageSwizzle(vk::ImageCreateInfo& image_info, vk::ComponentMapping& components) {
if (image_info->usage & vk::ImageUsageFlagBits::eStorage) { if (image_info.usage & vk::ImageUsageFlagBits::eStorage) {
if (components->r == vk::ComponentSwizzle::eR && if (components.r == vk::ComponentSwizzle::eR && components.g == vk::ComponentSwizzle::eG &&
components->g == vk::ComponentSwizzle::eG && components.b == vk::ComponentSwizzle::eB && components.a == vk::ComponentSwizzle::eA) {
components->b == vk::ComponentSwizzle::eB &&
components->a == vk::ComponentSwizzle::eA) {
return true; return true;
} }
if (components->r == vk::ComponentSwizzle::eB && if (components.r == vk::ComponentSwizzle::eB && components.g == vk::ComponentSwizzle::eG &&
components->g == vk::ComponentSwizzle::eG && components.b == vk::ComponentSwizzle::eR && components.a == vk::ComponentSwizzle::eA &&
components->b == vk::ComponentSwizzle::eR && image_info.format == vk::Format::eR8G8B8A8Srgb) {
components->a == vk::ComponentSwizzle::eA &&
image_info->format == vk::Format::eR8G8B8A8Srgb) {
LOGF("replace vk::Format::eR8G8B8A8Srgb => vk::Format::eB8G8R8A8Srgb\n"); LOGF("replace vk::Format::eR8G8B8A8Srgb => vk::Format::eB8G8R8A8Srgb\n");
components->r = vk::ComponentSwizzle::eR; components.r = vk::ComponentSwizzle::eR;
components->g = vk::ComponentSwizzle::eG; components.g = vk::ComponentSwizzle::eG;
components->b = vk::ComponentSwizzle::eB; components.b = vk::ComponentSwizzle::eB;
components->a = vk::ComponentSwizzle::eA; components.a = vk::ComponentSwizzle::eA;
image_info->format = vk::Format::eB8G8R8A8Srgb; image_info.format = vk::Format::eB8G8R8A8Srgb;
return true; return true;
} }
@@ -413,10 +412,9 @@ bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer
layer_count % 6u == 0; layer_count % 6u == 0;
} }
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj, vk::ComponentMapping TextureCreateImage(VulkanImage& vk_obj,
const TextureImageCreateParams& params) { const TextureImageCreateParams& params) {
EXIT_IF(ctx == nullptr); auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(vk_obj == nullptr);
EXIT_IF(params.owner == nullptr); EXIT_IF(params.owner == nullptr);
const bool array_texture = TextureIsLayeredTexture(params.type); 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; image_info.samples = vk::SampleCountFlagBits::e1;
const bool storage_view = TextureHasFormatUsage(params.view_usage, TextureFormatUsage::Storage); 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) { if (!params.storage_swizzle_fallback) {
EXIT("swizzle is not supported"); 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 requested_usage = params.format_usage;
const auto required_usage = params.required_format_usage; const auto required_usage = params.required_format_usage;
const bool has_optional_usage = static_cast<uint32_t>(requested_usage & ~required_usage) != 0; const bool has_optional_usage = static_cast<uint32_t>(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; auto required_info = image_info;
required_info.usage = TextureGetUsage(required_usage); required_info.usage = TextureGetUsage(required_usage);
required_info.format = view_checked_format; required_info.format = view_checked_format;
if (TextureCheckFormatExact(ctx, required_info)) { if (TextureCheckFormatExact(required_info)) {
static std::atomic_uint log_count {0}; static std::atomic_uint log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { 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 " 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) { if (has_optional_usage) {
image_info.format = view_checked_format; image_info.format = view_checked_format;
image_info.usage = TextureGetUsage(required_usage); 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"); EXIT("format is not supported");
} }
} }
vk_obj->extent.width = image_info.extent.width; vk_obj.extent.width = image_info.extent.width;
vk_obj->extent.height = image_info.extent.height; vk_obj.extent.height = image_info.extent.height;
vk_obj->layers = image_info.arrayLayers; vk_obj.layers = image_info.arrayLayers;
vk_obj->mip_levels = image_info.mipLevels; vk_obj.mip_levels = image_info.mipLevels;
vk_obj->format = image_info.format; vk_obj.format = image_info.format;
vk_obj->image = nullptr; vk_obj.image = nullptr;
vk_obj->layout = image_info.initialLayout; 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); EXIT_NOT_IMPLEMENTED(!created);
return components; return components;
} }
void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj, void TextureCreateImageViews(VulkanImage& vk_obj,
vk::ComponentMapping components, uint64_t type, uint32_t base_array, vk::ComponentMapping components, uint64_t type, uint32_t base_array,
uint32_t base_level, uint32_t level_count, uint32_t depth, uint32_t base_level, uint32_t level_count, uint32_t depth,
bool allow_cube_view, TextureFormatUsage view_usage) { bool allow_cube_view, TextureFormatUsage view_usage) {
EXIT_IF(ctx == nullptr); auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(vk_obj == nullptr); EXIT_IF(level_count == 0 || base_level + level_count > vk_obj.mip_levels);
EXIT_IF(level_count == 0 || base_level + level_count > vk_obj->mip_levels);
const bool layered_texture = TextureIsLayeredTexture(type); const bool layered_texture = TextureIsLayeredTexture(type);
const bool volume_texture = TextureIs3DTexture(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.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = (usage_info.usage ? &usage_info : nullptr); create_info.pNext = (usage_info.usage ? &usage_info : nullptr);
create_info.flags = {}; create_info.flags = {};
create_info.image = vk_obj->image; create_info.image = vk_obj.image;
create_info.viewType = vk::ImageViewType::e2D; create_info.viewType = vk::ImageViewType::e2D;
create_info.format = vk_obj->format; create_info.format = vk_obj.format;
create_info.components = components; create_info.components = components;
create_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; create_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
create_info.subresourceRange.baseArrayLayer = (layered_texture ? base_array : 0); 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) { auto create_view = [&](int index) {
const auto result = const auto result =
ctx->device.createImageView(&create_info, nullptr, &vk_obj->image_view[index]); graphics.device.createImageView(&create_info, nullptr, &vk_obj.image_view[index]);
if (result != vk::Result::eSuccess || vk_obj->image_view[index] == nullptr) { 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", EXIT("failed to create texture image view: result=%d format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(create_info.format), index); static_cast<int>(result), static_cast<int>(create_info.format), index);
} }
@@ -854,7 +851,7 @@ static uint64_t FmaskRegionCopySize(const BufferImageCopy& region) {
sizeof(uint32_t); sizeof(uint32_t);
} }
static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj, static void UploadFmaskIdentity(VulkanImage& vk_obj,
const std::vector<BufferImageCopy>& regions, const std::vector<BufferImageCopy>& regions,
vk::ImageLayout dst_layout, const char* owner) { vk::ImageLayout dst_layout, const char* owner) {
constexpr uint32_t kIdentityFmaskPattern = 0x76543210u; constexpr uint32_t kIdentityFmaskPattern = 0x76543210u;
@@ -878,7 +875,8 @@ static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj,
words[i] = kIdentityFmaskPattern; 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 { struct GpuTileElementLayout {
@@ -887,31 +885,30 @@ struct GpuTileElementLayout {
uint32_t tall = 1; uint32_t tall = 1;
}; };
static bool GetGpuTileElementLayout(uint32_t fmt, GpuTileElementLayout* out) { static bool GetGpuTileElementLayout(uint32_t fmt, GpuTileElementLayout& out) {
EXIT_IF(out == nullptr);
if (const auto bytes = Prospero::NumBytesPerElement(fmt); bytes != 0) { if (const auto bytes = Prospero::NumBytesPerElement(fmt); bytes != 0) {
*out = {bytes, 1, 1}; out = {bytes, 1, 1};
return true; return true;
} }
if (const auto bytes = Prospero::BlockCompressedBytesPerBlock(fmt); bytes != 0) { if (const auto bytes = Prospero::BlockCompressedBytesPerBlock(fmt); bytes != 0) {
*out = {bytes, 4, 4}; out = {bytes, 4, 4};
return true; return true;
} }
return false; return false;
} }
static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity, uint64_t* size) { static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity, uint64_t& size) {
if (size == nullptr || offset > capacity || length > capacity - offset) { if (offset > capacity || length > capacity - offset) {
return false; return false;
} }
*size = length; size = length;
return true; return true;
} }
bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>& regions, bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth, const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth,
uint64_t levels, std::vector<GpuTileInfo>* out_infos) { uint64_t levels, std::vector<GpuTileInfo>& out_infos) {
if (out_infos == nullptr || size == 0 || levels == 0 || levels > 16 || depth == 0 || if (size == 0 || levels == 0 || levels > 16 || depth == 0 ||
regions.size() != GetTextureRegionCount(depth, levels, layout.volume_texture) || regions.size() != GetTextureRegionCount(depth, levels, layout.volume_texture) ||
Prospero::IsFmaskTextureFormat(fmt)) { Prospero::IsFmaskTextureFormat(fmt)) {
return false; return false;
@@ -921,7 +918,7 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
if (layout.tile_family == TileBlockFamily::RenderTarget64KB || if (layout.tile_family == TileBlockFamily::RenderTarget64KB ||
layout.tile_family == TileBlockFamily::Depth64KB) { layout.tile_family == TileBlockFamily::Depth64KB) {
element.bytes = Prospero::RenderTargetBytesPerElement(fmt); element.bytes = Prospero::RenderTargetBytesPerElement(fmt);
} else if (!GetGpuTileElementLayout(fmt, &element)) { } else if (!GetGpuTileElementLayout(fmt, element)) {
return false; return false;
} }
if (element.bytes == 0) { if (element.bytes == 0) {
@@ -933,12 +930,12 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
if (layout.volume_texture) { if (layout.volume_texture) {
TileVolumeLayout volume {}; TileVolumeLayout volume {};
if (!TileGetTextureVolumeLayout(fmt, regions[0].width, regions[0].height, depth, if (!TileGetTextureVolumeLayout(fmt, regions[0].width, regions[0].height, depth,
static_cast<uint32_t>(levels), layout.tile, &volume)) { static_cast<uint32_t>(levels), layout.tile, volume)) {
return false; return false;
} }
element = {volume.bytes_per_element, volume.texel_width, volume.texel_height}; element = {volume.bytes_per_element, volume.texel_width, volume.texel_height};
TileBlockLayout block {}; 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; size_t region_base = 0;
for (uint32_t level = 0; level < levels; ++level) { for (uint32_t level = 0; level < levels; ++level) {
@@ -958,9 +955,9 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
const uint64_t linear_span = const uint64_t linear_span =
static_cast<uint64_t>(copy_depth - 1u) * linear_stride + static_cast<uint64_t>(copy_depth - 1u) * linear_stride +
layout.level_sizes[level].size; 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, !SetGpuTileSize(info.tiled_offset, volume.level_sizes[level], size,
&info.tiled_size)) { info.tiled_size)) {
return false; return false;
} }
info.linear_slice_stride = linear_stride; info.linear_slice_stride = linear_stride;
@@ -990,7 +987,7 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
const bool tail = level >= layout.first_tail_level; const bool tail = level >= layout.first_tail_level;
const auto family = base_family; const auto family = base_family;
TileBlockLayout block {}; TileBlockLayout block {};
if (!TileGetBlockLayout(family, element.bytes, &block)) { if (!TileGetBlockLayout(family, element.bytes, block)) {
return false; return false;
} }
const auto level_depth = GetTextureLevelDepth(depth, level, layout.volume_texture); const auto level_depth = GetTextureLevelDepth(depth, level, layout.volume_texture);
@@ -1001,9 +998,9 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
info.bytes_per_element = block.bytes_per_element; info.bytes_per_element = block.bytes_per_element;
info.linear_offset = region.offset; info.linear_offset = region.offset;
info.tiled_offset = TextureUploadSliceSourceOffset(layout, level, z); 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, !SetGpuTileSize(info.tiled_offset, GetLevelSrcSize(level_size), size,
&info.tiled_size)) { info.tiled_size)) {
return false; return false;
} }
info.width = std::max((region.width + element.wide - 1u) / element.wide, 1u); info.width = std::max((region.width + element.wide - 1u) / element.wide, 1u);
@@ -1036,11 +1033,11 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
if (infos.empty()) { if (infos.empty()) {
return false; return false;
} }
*out_infos = std::move(infos); out_infos = std::move(infos);
return true; 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<BufferImageCopy>& regions, uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint64_t width, const TextureUploadLayout& layout, uint32_t fmt, uint64_t width,
uint64_t height, uint32_t depth, uint64_t levels, const char* owner, 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); owner, layout.tile, size, width, height, depth, layout.pitch, levels);
} }
if (static_cast<Prospero::TileMode>(layout.tile) == Prospero::TileMode::kLinear) { if (static_cast<Prospero::TileMode>(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; return;
} }
if (layout.tile_family == TileBlockFamily::Depth64KB && Prospero::IsFmaskTextureFormat(fmt)) { 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; return;
} }
std::vector<GpuTileInfo> infos; std::vector<GpuTileInfo> 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 EXIT("%s: GPU tiled upload unsupported: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64
"x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n", "x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n",
owner, fmt, layout.tile, size, width, height, depth, layout.pitch, levels); 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 } // namespace Libs::Graphics
@@ -83,8 +83,8 @@ struct TextureImageCreateParams {
vk::ComponentSwizzle TextureGetComponentSwizzle(uint8_t s); vk::ComponentSwizzle TextureGetComponentSwizzle(uint8_t s);
vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle); vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle);
bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info); bool TextureCheckFormat(vk::ImageCreateInfo& image_info);
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components); bool TextureCheckStorageSwizzle(vk::ImageCreateInfo& image_info, vk::ComponentMapping& components);
vk::ImageUsageFlags TextureGetUsage(TextureFormatUsage usage); vk::ImageUsageFlags TextureGetUsage(TextureFormatUsage usage);
vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage); vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage);
vk::Format TextureGetFormat(uint32_t fmt); vk::Format TextureGetFormat(uint32_t fmt);
@@ -99,9 +99,9 @@ bool TextureIs3DTexture(uint64_t type);
bool TextureIsCubeTexture(uint64_t type); bool TextureIsCubeTexture(uint64_t type);
bool TextureIsLayeredTexture(uint64_t type); bool TextureIsLayeredTexture(uint64_t type);
bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer_count); 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); 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, vk::ComponentMapping components, uint64_t type, uint32_t base_array,
uint32_t base_level, uint32_t level_count, uint32_t depth, uint32_t base_level, uint32_t level_count, uint32_t depth,
bool allow_cube_view, TextureFormatUsage view_usage); bool allow_cube_view, TextureFormatUsage view_usage);
@@ -125,8 +125,8 @@ std::vector<ImageBufferCopy>
TextureBuildDownloadRegions(const std::vector<BufferImageCopy>& upload_regions); TextureBuildDownloadRegions(const std::vector<BufferImageCopy>& upload_regions);
bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>& regions, bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth, const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth,
uint64_t levels, std::vector<GpuTileInfo>* infos); uint64_t levels, std::vector<GpuTileInfo>& infos);
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<BufferImageCopy>& regions, uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint64_t width, const TextureUploadLayout& layout, uint32_t fmt, uint64_t width,
uint64_t height, uint32_t depth, uint64_t levels, const char* owner, uint64_t height, uint32_t depth, uint64_t levels, const char* owner,
+108 -139
View File
@@ -7,6 +7,7 @@
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/objects/label.h" #include "graphics/host_gpu/objects/label.h"
#include "graphics/host_gpu/renderer/render.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/resourceMutex.h"
#include "graphics/host_gpu/renderer/textureCache.h" #include "graphics/host_gpu/renderer/textureCache.h"
#include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/transfer.h"
@@ -38,22 +39,20 @@ constexpr uint64_t AlignReadbackCopySize(uint64_t size) noexcept {
} }
struct SharedVulkanBufferOwner { struct SharedVulkanBufferOwner {
explicit SharedVulkanBufferOwner(GraphicContext* context): ctx(context) { explicit SharedVulkanBufferOwner(GraphicContext& graphics): graphics(graphics) {}
EXIT_IF(ctx == nullptr);
}
~SharedVulkanBufferOwner() { ~SharedVulkanBufferOwner() {
if (buffer.buffer != nullptr) { if (buffer.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &buffer); graphics.DeleteBuffer(buffer);
} }
} }
GraphicContext* ctx = nullptr; GraphicContext& graphics;
VulkanBuffer buffer; VulkanBuffer buffer;
}; };
std::shared_ptr<VulkanBuffer> MakeSharedVulkanBuffer(GraphicContext* ctx) { std::shared_ptr<VulkanBuffer> MakeSharedVulkanBuffer() {
auto owner = std::make_shared<SharedVulkanBufferOwner>(ctx); auto owner = std::make_shared<SharedVulkanBufferOwner>(GetRenderContext().GetGraphics());
return {owner, &owner->buffer}; return {owner, &owner->buffer};
} }
@@ -149,21 +148,21 @@ bool PageOverlaps(uint64_t left, uint64_t left_size, uint64_t right, uint64_t ri
} }
} // namespace } // namespace
bool MergeOverlappingBufferCacheRange(BufferCacheRange* merged, bool MergeOverlappingBufferCacheRange(BufferCacheRange& merged,
BufferCacheRange candidate) noexcept { BufferCacheRange candidate) noexcept {
if (merged == nullptr || merged->address == 0 || merged->size == 0 || candidate.address == 0 || if (merged.address == 0 || merged.size == 0 || candidate.address == 0 || candidate.size == 0 ||
candidate.size == 0 || merged->size > UINT64_MAX - merged->address || merged.size > UINT64_MAX - merged.address ||
candidate.size > UINT64_MAX - candidate.address) { candidate.size > UINT64_MAX - candidate.address) {
EXIT("BufferCache: invalid overlap-merge range\n"); 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; 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; 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); const auto end = std::max(merged_end, candidate_end);
*merged = {.address = address, .size = end - address}; merged = {.address = address, .size = end - address};
return true; return true;
} }
@@ -175,7 +174,6 @@ struct BufferCache::CachedBuffer {
uint64_t vaddr = 0; uint64_t vaddr = 0;
uint64_t size = 0; uint64_t size = 0;
uint64_t queue_mask = 0; uint64_t queue_mask = 0;
GraphicContext* ctx = nullptr;
std::shared_ptr<VulkanBuffer> buffer; std::shared_ptr<VulkanBuffer> buffer;
}; };
@@ -220,10 +218,7 @@ struct BufferCache::ReadbackWorker {
} }
} }
void Prepare(GraphicContext* graphic_context) { void Prepare() {
if (graphic_context == nullptr) {
EXIT("BufferCache: cannot prepare readback without a graphics context\n");
}
auto current = state.load(std::memory_order_acquire); auto current = state.load(std::memory_order_acquire);
while (current == State::InitRequested || while (current == State::InitRequested ||
(current == State::Claimed && (current == State::Claimed &&
@@ -236,15 +231,11 @@ struct BufferCache::ReadbackWorker {
EXIT("BufferCache: cannot prepare a stopping readback worker, state=%u\n", EXIT("BufferCache: cannot prepare a stopping readback worker, state=%u\n",
static_cast<uint32_t>(current)); static_cast<uint32_t>(current));
} }
if (ctx != graphic_context || command == nullptr || mapped == nullptr || if (command == nullptr || mapped == nullptr || readback.buffer == nullptr) {
readback.buffer == nullptr) {
EXIT("BufferCache: initialized readback worker has invalid resources, state=%u " EXIT("BufferCache: initialized readback worker has invalid resources, state=%u "
"ctx=%p requested=%p "
"command=%p mapped=%p buffer=%p\n", "command=%p mapped=%p buffer=%p\n",
static_cast<uint32_t>(current), static_cast<const void*>(ctx), static_cast<uint32_t>(current), static_cast<const void*>(command.get()),
static_cast<const void*>(graphic_context), static_cast<const void*>(mapped), static_cast<const void*>(readback.buffer));
static_cast<const void*>(command.get()), static_cast<const void*>(mapped),
static_cast<const void*>(readback.buffer));
} }
return; return;
} }
@@ -253,7 +244,6 @@ struct BufferCache::ReadbackWorker {
EXIT("BufferCache: readback prepare requires uninitialized state, state=%u\n", EXIT("BufferCache: readback prepare requires uninitialized state, state=%u\n",
static_cast<uint32_t>(expected)); static_cast<uint32_t>(expected));
} }
ctx = graphic_context;
state.store(State::InitRequested, std::memory_order_release); state.store(State::InitRequested, std::memory_order_release);
state.notify_all(); state.notify_all();
while ((current = state.load(std::memory_order_acquire)) != State::Idle) { 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 submissions_prepaused_now = GraphicsRunSubmissionLockHeld() || command_thread;
const bool unsafe_gpu_lock = GraphicsRunGpuLockHeld() && !submissions_prepaused_now; const bool unsafe_gpu_lock = GraphicsRunGpuLockHeld() && !submissions_prepaused_now;
if (unsafe_gpu_lock || LabelInCallback() || g_cache_lock_owner != nullptr || if (unsafe_gpu_lock || LabelInCallback() || g_cache_lock_owner != nullptr ||
ctx == nullptr || command == nullptr || mapped == nullptr || command == nullptr || mapped == nullptr || readback.buffer == nullptr) {
readback.buffer == nullptr) {
EXIT("BufferCache: unsafe readback request context, command_thread=%d " EXIT("BufferCache: unsafe readback request context, command_thread=%d "
"submission_lock=%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", "buffer=%p\n",
command_thread, GraphicsRunSubmissionLockHeld(), GraphicsRunGpuLockHeld(), command_thread, GraphicsRunSubmissionLockHeld(), GraphicsRunGpuLockHeld(),
LabelInCallback(), static_cast<const void*>(g_cache_lock_owner), LabelInCallback(), static_cast<const void*>(g_cache_lock_owner),
static_cast<const void*>(ctx), static_cast<const void*>(command.get()), static_cast<const void*>(command.get()), static_cast<const void*>(mapped),
static_cast<const void*>(mapped), static_cast<const void*>(readback.buffer)); static_cast<const void*>(readback.buffer));
} }
State expected = State::Idle; State expected = State::Idle;
while (!state.compare_exchange_weak(expected, State::Claimed, std::memory_order_acq_rel)) { while (!state.compare_exchange_weak(expected, State::Claimed, std::memory_order_acq_rel)) {
@@ -386,48 +375,46 @@ struct BufferCache::ReadbackWorker {
if (current == State::Stopping) { if (current == State::Stopping) {
command.reset(); command.reset();
if (mapped != nullptr) { if (mapped != nullptr) {
VulkanUnmapMemory(ctx, &readback.memory); cache.m_graphics.UnmapMemory(readback.memory);
mapped = nullptr; mapped = nullptr;
} }
if (readback.buffer != nullptr) { if (readback.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &readback); cache.m_graphics.DeleteBuffer(readback);
} }
state.store(State::Stopped, std::memory_order_release); state.store(State::Stopped, std::memory_order_release);
state.notify_all(); state.notify_all();
return; return;
} }
if (current == State::InitRequested) { if (current == State::InitRequested) {
if (ctx == nullptr || command != nullptr || mapped != nullptr || if (command != nullptr || mapped != nullptr || readback.buffer != nullptr) {
readback.buffer != nullptr) { EXIT("BufferCache: invalid resources before readback initialization, "
EXIT("BufferCache: invalid resources before readback initialization, ctx=%p "
"command=%p mapped=%p buffer=%p\n", "command=%p mapped=%p buffer=%p\n",
static_cast<const void*>(ctx), static_cast<const void*>(command.get()), static_cast<const void*>(command.get()), static_cast<const void*>(mapped),
static_cast<const void*>(mapped),
static_cast<const void*>(readback.buffer)); static_cast<const void*>(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<uint32_t>(-1) || if (family == static_cast<uint32_t>(-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, " EXIT("BufferCache: utility and graphics queues must share a valid family, "
"util=%u " "util=%u "
"gfx=%u\n", "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; for (int i = GraphicContext::QUEUE_COMPUTE_START;
i < GraphicContext::QUEUE_COMPUTE_START + GraphicContext::QUEUE_COMPUTE_NUM; i < GraphicContext::QUEUE_COMPUTE_START + GraphicContext::QUEUE_COMPUTE_NUM;
i++) { i++) {
if (ctx->queues[i].family != family) { if (cache.m_graphics.queues[i].family != family) {
EXIT("BufferCache: compute queue %d family mismatch, expected=%u " EXIT("BufferCache: compute queue %d family mismatch, expected=%u "
"actual=%u\n", "actual=%u\n",
i, family, ctx->queues[i].family); i, family, cache.m_graphics.queues[i].family);
} }
} }
readback.usage = vk::BufferUsageFlagBits::eTransferDst; readback.usage = vk::BufferUsageFlagBits::eTransferDst;
readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible | readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached; vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, READBACK_CAPACITY, &readback); cache.m_graphics.CreateBuffer(READBACK_CAPACITY, readback);
VulkanMapMemory(ctx, &readback.memory, &mapped); cache.m_graphics.MapMemory(readback.memory, mapped);
command = std::make_unique<CommandBuffer>(GraphicContext::QUEUE_UTIL); command = std::make_unique<CommandBuffer>(GraphicContext::QUEUE_UTIL);
state.store(State::Idle, std::memory_order_release); state.store(State::Idle, std::memory_order_release);
state.notify_all(); state.notify_all();
@@ -528,7 +515,6 @@ struct BufferCache::ReadbackWorker {
BufferCache& cache; BufferCache& cache;
std::atomic<State> state {State::Uninitialized}; std::atomic<State> state {State::Uninitialized};
GraphicContext* ctx = nullptr;
VulkanBuffer readback {}; VulkanBuffer readback {};
void* mapped = nullptr; void* mapped = nullptr;
std::unique_ptr<CommandBuffer> command; std::unique_ptr<CommandBuffer> command;
@@ -542,8 +528,9 @@ struct BufferCache::ReadbackWorker {
std::thread thread; std::thread thread;
}; };
BufferCache::BufferCache(PageManager& page_manager, ResourceMutex& resource_mutex) BufferCache::BufferCache(GraphicContext& graphics, PageManager& page_manager,
: m_memory_tracker(page_manager), m_page_manager(page_manager), ResourceMutex& resource_mutex)
: m_graphics(graphics), m_memory_tracker(page_manager), m_page_manager(page_manager),
m_resource_mutex(resource_mutex) { m_resource_mutex(resource_mutex) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
m_readback = std::make_unique<ReadbackWorker>(*this); m_readback = std::make_unique<ReadbackWorker>(*this);
@@ -563,7 +550,7 @@ BufferCache::~BufferCache() {
} }
} }
if (!m_buffers.empty()) { if (!m_buffers.empty()) {
Transfer::WaitForGraphicsIdle(m_buffers.begin()->second->ctx); Transfer::WaitForGraphicsIdle();
} }
m_buffers.clear(); 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); const auto ranges = m_gpu_modified_ranges.Intersections(address, bytes);
for (const auto& range: ranges) { for (const auto& range: ranges) {
std::vector<uint8_t> data(range.size); std::vector<uint8_t> data(range.size);
Transfer::DownloadBuffer(cached->ctx, cached->buffer.get(), Transfer::DownloadBuffer(*cached->buffer, range.address - begin, data.data(),
range.address - begin, data.data(), range.size); range.size);
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size()); Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
downloaded += range.size; downloaded += range.size;
} }
@@ -659,19 +646,15 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) {
} }
} }
std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* command, BufferBinding BufferCache::ObtainBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
GraphicContext* ctx, uint64_t vaddr, bool is_written, bool is_read, bool is_formatted) {
uint64_t size, bool is_written, if (command.IsInvalid() || command.IsExecute() || vaddr == 0 || size == 0 ||
bool is_read, bool is_formatted) { size > UINT64_MAX - vaddr || command.GetQueue() < 0 || command.GetQueue() >= 64) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr || EXIT("BufferCache: invalid buffer request, queue=%d addr=0x%016" PRIx64
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
" size=0x%016" PRIx64 "\n", " size=0x%016" PRIx64 "\n",
static_cast<const void*>(command), command == nullptr ? -1 : command->GetQueue(), command.GetQueue(), vaddr, size);
static_cast<const void*>(ctx), vaddr, size);
} }
const auto queue = static_cast<uint32_t>(command->GetQueue()); const auto queue = static_cast<uint32_t>(command.GetQueue());
const auto queue_mask = uint64_t {1} << queue; const auto queue_mask = uint64_t {1} << queue;
ValidateGpuAccess(vaddr, size, is_read, is_written); ValidateGpuAccess(vaddr, size, is_read, is_written);
const auto begin = AlignDown(vaddr); const auto begin = AlignDown(vaddr);
@@ -691,10 +674,10 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
VulkanBuffer* stream_buffer = nullptr; VulkanBuffer* stream_buffer = nullptr;
vk::DeviceSize stream_offset = 0; vk::DeviceSize stream_offset = 0;
vk::DeviceSize stream_range = 0; vk::DeviceSize stream_range = 0;
const auto stream_alignment = std::max<uint64_t>(ctx->StorageMinAlignment(), 16); const auto stream_alignment = std::max<uint64_t>(m_graphics.StorageMinAlignment(), 16);
if (UploadHostData(command, ctx, guest_data.data(), size, stream_alignment, if (UploadHostData(command, guest_data.data(), size, stream_alignment, stream_buffer,
&stream_buffer, &stream_offset, &stream_range)) { stream_offset, stream_range)) {
return {stream_buffer, stream_offset}; return {*stream_buffer, stream_offset};
} }
} }
} }
@@ -728,7 +711,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
} }
} }
if (is_written) { if (is_written) {
m_readback->Prepare(ctx); m_readback->Prepare();
} }
FaultSafeCacheLock lock(this, m_mutex); FaultSafeCacheLock lock(this, m_mutex);
@@ -749,7 +732,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
if (first != m_buffers.begin()) { if (first != m_buffers.begin()) {
auto previous = std::prev(first); auto previous = std::prev(first);
if (MergeOverlappingBufferCacheRange( if (MergeOverlappingBufferCacheRange(
&merged, {previous->second->vaddr, previous->second->size})) { merged, {previous->second->vaddr, previous->second->size})) {
first = previous; first = previous;
} }
} }
@@ -758,7 +741,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
break; break;
} }
if (MergeOverlappingBufferCacheRange( if (MergeOverlappingBufferCacheRange(
&merged, {candidate->second->vaddr, candidate->second->size})) { merged, {candidate->second->vaddr, candidate->second->size})) {
overlaps.push_back(candidate); overlaps.push_back(candidate);
} }
} }
@@ -766,11 +749,10 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
if (!overlaps.empty()) { if (!overlaps.empty()) {
for (const auto& overlap: overlaps) { for (const auto& overlap: overlaps) {
auto& old = *overlap->second; 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 EXIT("BufferCache: invalid overlapping buffer owner, addr=0x%016" PRIx64
" size=0x%016" PRIx64 " owner_ctx=%p requested_ctx=%p buffer=%p\n", " size=0x%016" PRIx64 " buffer=%p\n",
old.vaddr, old.size, static_cast<const void*>(old.ctx), old.vaddr, old.size, static_cast<const void*>(old.buffer.get()));
static_cast<const void*>(ctx), static_cast<const void*>(old.buffer.get()));
} }
if (!CanMergeBufferCacheQueueMask(old.queue_mask, queue)) { if (!CanMergeBufferCacheQueueMask(old.queue_mask, queue)) {
EXIT("BufferCache: cross-queue overlap merge is unsupported, " EXIT("BufferCache: cross-queue overlap merge is unsupported, "
@@ -786,8 +768,8 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
}, },
[&]() noexcept { [&]() noexcept {
for (const auto& [upload_vaddr, upload_size]: uploads) { for (const auto& [upload_vaddr, upload_size]: uploads) {
Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex, Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *old.buffer,
old.buffer.get(), upload_vaddr - old.vaddr, upload_vaddr - old.vaddr,
reinterpret_cast<const void*>(upload_vaddr), reinterpret_cast<const void*>(upload_vaddr),
upload_size); upload_size);
} }
@@ -797,16 +779,15 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
auto cached = std::make_unique<CachedBuffer>(); auto cached = std::make_unique<CachedBuffer>();
cached->vaddr = merged.address; cached->vaddr = merged.address;
cached->size = merged.size; cached->size = merged.size;
cached->ctx = ctx; cached->buffer = MakeSharedVulkanBuffer();
cached->buffer = MakeSharedVulkanBuffer(ctx);
cached->buffer->usage = cached->buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst |
vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer |
vk::BufferUsageFlagBits::eStorageBuffer; vk::BufferUsageFlagBits::eStorageBuffer;
cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
VulkanCreateBuffer(ctx, cached->size, cached->buffer.get()); m_graphics.CreateBuffer(cached->size, *cached->buffer);
if (!overlaps.empty()) { if (!overlaps.empty()) {
auto vk_buffer = command->Handle(); auto vk_buffer = command.Handle();
std::vector<vk::BufferMemoryBarrier> before; std::vector<vk::BufferMemoryBarrier> before;
before.reserve(overlaps.size() + 1); before.reserve(overlaps.size() + 1);
for (const auto& overlap: overlaps) { for (const auto& overlap: overlaps) {
@@ -854,7 +835,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr); vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr);
for (const auto& overlap: overlaps) { for (const auto& overlap: overlaps) {
command->RetainResourceUntilFence(overlap->second->buffer); command.RetainResourceUntilFence(overlap->second->buffer);
m_buffers.erase(overlap); m_buffers.erase(overlap);
} }
} }
@@ -871,8 +852,8 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
}, },
[&]() noexcept { [&]() noexcept {
for (const auto& [upload_vaddr, upload_size]: ranges) { for (const auto& [upload_vaddr, upload_size]: ranges) {
Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex, Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *cached.buffer,
cached.buffer.get(), upload_vaddr - cached.vaddr, upload_vaddr - cached.vaddr,
reinterpret_cast<const void*>(upload_vaddr), upload_size); reinterpret_cast<const void*>(upload_vaddr), upload_size);
} }
}); });
@@ -880,47 +861,46 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
m_gpu_modified_ranges.Add(vaddr, size); m_gpu_modified_ranges.Add(vaddr, size);
} }
cached.queue_mask |= queue_mask; cached.queue_mask |= queue_mask;
command->RetainResourceUntilFence(cached.buffer); command.RetainResourceUntilFence(cached.buffer);
return {cached.buffer.get(), vaddr - cached.vaddr}; return {*cached.buffer, vaddr - cached.vaddr};
} }
bool BufferCache::UploadHostData(CommandBuffer* command, GraphicContext* ctx, const void* src, bool BufferCache::UploadHostData(CommandBuffer& command, const void* src, uint64_t size,
uint64_t size, uint64_t alignment, VulkanBuffer** out_buffer, uint64_t alignment, VulkanBuffer*& out_buffer,
uint64_t* out_offset, uint64_t* out_range) { uint64_t& out_offset, uint64_t& out_range) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr) { if (command.IsInvalid() || command.IsExecute()) {
EXIT("BufferCache: host stream upload requires a recording command buffer\n"); 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, return command.m_host_stream.Copy(src, size, alignment, out_buffer, out_offset, out_range);
out_range);
} }
VulkanBuffer* BufferCache::ObtainNullBuffer(CommandBuffer* command, GraphicContext* ctx) { VulkanBuffer& BufferCache::ObtainNullBuffer(CommandBuffer& command) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr) { if (command.IsInvalid() || command.IsExecute()) {
EXIT("BufferCache: null buffer requires a graphics context\n"); EXIT("BufferCache: null buffer requires a graphics context\n");
} }
FaultSafeCacheLock lock(this, m_mutex); FaultSafeCacheLock lock(this, m_mutex);
if (m_null_buffer == nullptr) { if (m_null_buffer == nullptr) {
// robustBufferAccess makes every fetch safe; TODO: Use a // robustBufferAccess makes every fetch safe; TODO: Use a
// persistent 16-byte fallback when Vulkan null vertex descriptors are unavailable. // persistent 16-byte fallback when Vulkan null vertex descriptors are unavailable.
auto buffer = MakeSharedVulkanBuffer(ctx); auto buffer = MakeSharedVulkanBuffer();
buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer | buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eIndexBuffer; vk::BufferUsageFlagBits::eIndexBuffer;
buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible | buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached; vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, 16, buffer.get()); m_graphics.CreateBuffer(16, *buffer);
void* data = nullptr; void* data = nullptr;
VulkanMapMemory(ctx, &buffer->memory, &data); m_graphics.MapMemory(buffer->memory, data);
std::memset(data, 0, 16); std::memset(data, 0, 16);
VulkanUnmapMemory(ctx, &buffer->memory); m_graphics.UnmapMemory(buffer->memory);
m_null_buffer = std::move(buffer); m_null_buffer = std::move(buffer);
} }
// The buffer remains cache-persistent, while every recorded consumer keeps the allocation // 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. // alive until its own fence even if an unrelated command processor resets the global cache.
command->RetainResourceUntilFence(m_null_buffer); command.RetainResourceUntilFence(m_null_buffer);
return m_null_buffer.get(); return *m_null_buffer;
} }
BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t size) { BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t size) {
@@ -949,8 +929,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
--owner; --owner;
auto& cached = *owner->second; auto& cached = *owner->second;
const auto offset = address - cached.vaddr; const auto offset = address - cached.vaddr;
if (offset > cached.size || bytes > cached.size - offset || cached.ctx == nullptr || if (offset > cached.size || bytes > cached.size - offset || cached.buffer == nullptr ||
cached.buffer == nullptr || cached.buffer->buffer == nullptr) { cached.buffer->buffer == nullptr) {
EXIT("BufferCache: GPU image-source bytes have no containing native buffer\n"); EXIT("BufferCache: GPU image-source bytes have no containing native buffer\n");
} }
return cached; return cached;
@@ -964,14 +944,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
vaddr, size, GraphicsRunIsCommandProcessorThread(), vaddr, size, GraphicsRunIsCommandProcessorThread(),
GraphicsRunSubmissionLockHeld(), LabelInCallback()); GraphicsRunSubmissionLockHeld(), LabelInCallback());
} }
std::vector<GraphicContext*> waited; Transfer::WaitForGraphicsIdle();
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);
}
}
auto backing_writes = ReserveBackingWrites(m_page_manager, dirty_ranges); auto backing_writes = ReserveBackingWrites(m_page_manager, dirty_ranges);
uint64_t downloaded = 0; uint64_t downloaded = 0;
m_memory_tracker.ForEachDownloadRange<true>( m_memory_tracker.ForEachDownloadRange<true>(
@@ -990,8 +963,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
auto& owner = find_owner(range.address, range.size); auto& owner = find_owner(range.address, range.size);
const auto buffer_offset = range.address - owner.vaddr; const auto buffer_offset = range.address - owner.vaddr;
std::vector<uint8_t> data(range.size); std::vector<uint8_t> data(range.size);
Transfer::DownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset, Transfer::DownloadBuffer(*owner.buffer, buffer_offset, data.data(), range.size);
data.data(), range.size);
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size()); Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
downloaded += range.size; downloaded += range.size;
} }
@@ -1013,7 +985,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
if (offset > cached.size || size > cached.size - offset) { if (offset > cached.size || size > cached.size - offset) {
return {nullptr, 0, vaddr, size, true, cpu_modified}; 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"); EXIT("BufferCache: containing image source is inconsistent\n");
} }
if (cpu_modified) { if (cpu_modified) {
@@ -1025,8 +997,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
}, },
[&]() noexcept { [&]() noexcept {
for (const auto& [address, bytes]: uploads) { for (const auto& [address, bytes]: uploads) {
Transfer::UploadBuffer(cached.ctx, Transfer::StagingBufferType::Vertex, Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *cached.buffer,
cached.buffer.get(), address - cached.vaddr, address - cached.vaddr,
reinterpret_cast<const void*>(address), bytes); reinterpret_cast<const void*>(address), bytes);
} }
}); });
@@ -1047,15 +1019,14 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
} }
namespace { 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) { vk::AccessFlags source, vk::AccessFlags destination) {
if (buffer == nullptr || buffer->buffer == nullptr || size == 0 || if (buffer.buffer == nullptr || size == 0 || offset > buffer.buffer_size ||
offset > buffer->buffer_size || size > buffer->buffer_size - offset) { size > buffer.buffer_size - offset) {
EXIT("BufferCache: invalid DMA barrier, buffer=%p handle=%p offset=0x%016" PRIx64 EXIT("BufferCache: invalid DMA barrier, buffer=%p handle=%p offset=0x%016" PRIx64
" size=0x%016" PRIx64 " buffer_size=0x%016" PRIx64 "\n", " size=0x%016" PRIx64 " buffer_size=0x%016" PRIx64 "\n",
static_cast<const void*>(buffer), static_cast<const void*>(&buffer), static_cast<const void*>(buffer.buffer), offset,
buffer == nullptr ? nullptr : static_cast<const void*>(buffer->buffer), offset, size, size, buffer.buffer_size);
buffer == nullptr ? 0 : buffer->buffer_size);
} }
vk::BufferMemoryBarrier barrier {}; vk::BufferMemoryBarrier barrier {};
barrier.sType = vk::StructureType::eBufferMemoryBarrier; barrier.sType = vk::StructureType::eBufferMemoryBarrier;
@@ -1063,23 +1034,19 @@ vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, ui
barrier.dstAccessMask = destination; barrier.dstAccessMask = destination;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = buffer->buffer; barrier.buffer = buffer.buffer;
barrier.offset = offset; barrier.offset = offset;
barrier.size = size; barrier.size = size;
return barrier; return barrier;
} }
vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer* command) { vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer& command) {
if (command == nullptr) { return command.Handle();
EXIT("BufferCache: invalid DMA command buffer, command=%p\n",
static_cast<const void*>(command));
}
return command->Handle();
} }
} // namespace } // namespace
void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, void BufferCache::FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size,
uint64_t size, uint32_t value) { uint32_t value) {
if ((vaddr & 3u) != 0 || (size & 3u) != 0) { if ((vaddr & 3u) != 0 || (size & 3u) != 0) {
EXIT("BufferCache: fill range must be dword aligned, addr=0x%016" PRIx64 EXIT("BufferCache: fill range must be dword aligned, addr=0x%016" PRIx64
" size=0x%016" PRIx64 "\n", " size=0x%016" PRIx64 "\n",
@@ -1114,15 +1081,16 @@ void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
vaddr, size); 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( const auto before = MakeDmaBarrier(
dst, dst_offset, size, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, dst, dst_offset, size, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferWrite); vk::AccessFlagBits::eTransferWrite);
const auto vk_buffer = GetDmaCommandBuffer(command); const auto vk_buffer = GetDmaCommandBuffer(*command);
vk_buffer.pipelineBarrier( vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &before, 0, nullptr); 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 = const auto after =
MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite, MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite); 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); vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr);
} }
void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t dst_vaddr, void BufferCache::CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr,
uint64_t src_vaddr, uint64_t size) { uint64_t size) {
if (dst_vaddr == 0 || src_vaddr == 0 || size == 0 || if (dst_vaddr == 0 || src_vaddr == 0 || size == 0 ||
((dst_vaddr | src_vaddr | size) & 3u) != 0 || size > UINT64_MAX - dst_vaddr || ((dst_vaddr | src_vaddr | size) & 3u) != 0 || size > UINT64_MAX - dst_vaddr ||
size > UINT64_MAX - src_vaddr || size > UINT64_MAX - src_vaddr ||
@@ -1195,10 +1163,11 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
src_vaddr, dst_vaddr, size); 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] = const auto [dst, dst_offset] =
ObtainBuffer(command, ctx, dst_vaddr, size, true, false, dst_image_transition); ObtainBuffer(*command, dst_vaddr, size, true, false, dst_image_transition);
if (src == dst && src_offset < dst_offset + size && dst_offset < src_offset + size) { 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 EXIT("BufferCache: resolved Vulkan copy ranges overlap, src_offset=0x%016" PRIx64
" dst_offset=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", " dst_offset=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
src_offset, dst_offset, size); 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, MakeDmaBarrier(src, src_offset, size, vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferRead), vk::AccessFlagBits::eTransferRead),
}; };
const auto vk_buffer = GetDmaCommandBuffer(command); const auto vk_buffer = GetDmaCommandBuffer(*command);
vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, 0, nullptr, 2, before, 0, nullptr); vk::DependencyFlagBits::eByRegion, 0, nullptr, 2, before, 0, nullptr);
const vk::BufferCopy copy {src_offset, dst_offset, size}; const vk::BufferCopy copy {src_offset, dst_offset, size};
vk_buffer.copyBuffer(src->buffer, dst->buffer, 1, &copy); vk_buffer.copyBuffer(src.buffer, dst.buffer, 1, &copy);
const vk::BufferMemoryBarrier after[] = { const vk::BufferMemoryBarrier after[] = {
MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite, MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite), vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite),
+17 -13
View File
@@ -35,7 +35,12 @@ struct BufferCacheRange {
uint64_t size = 0; uint64_t size = 0;
}; };
[[nodiscard]] bool MergeOverlappingBufferCacheRange(BufferCacheRange* merged, struct BufferBinding {
VulkanBuffer& buffer;
uint64_t offset;
};
[[nodiscard]] bool MergeOverlappingBufferCacheRange(BufferCacheRange& merged,
BufferCacheRange candidate) noexcept; BufferCacheRange candidate) noexcept;
[[nodiscard]] bool CanMergeBufferCacheQueueMask(uint64_t queue_mask, uint32_t queue) noexcept; [[nodiscard]] bool CanMergeBufferCacheQueueMask(uint64_t queue_mask, uint32_t queue) noexcept;
@@ -46,27 +51,25 @@ public:
return vaddr & (CACHING_PAGE_SIZE - 1); return vaddr & (CACHING_PAGE_SIZE - 1);
} }
BufferCache(PageManager& page_manager, ResourceMutex& resource_mutex); BufferCache(GraphicContext& graphics, PageManager& page_manager, ResourceMutex& resource_mutex);
~BufferCache(); ~BufferCache();
KYTY_CLASS_NO_COPY(BufferCache); KYTY_CLASS_NO_COPY(BufferCache);
[[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size, [[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size,
PageFaultPhase phase) noexcept; PageFaultPhase phase) noexcept;
void UnmapMemory(uint64_t vaddr, uint64_t size); void UnmapMemory(uint64_t vaddr, uint64_t size);
[[nodiscard]] std::pair<VulkanBuffer*, uint64_t> [[nodiscard]] BufferBinding ObtainBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
ObtainBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, uint64_t size, bool is_written = false, bool is_read = true,
bool is_written = false, bool is_read = true, bool is_formatted = false); bool is_formatted = false);
// Emulator-owned, CPU-current scratch only. Guest ranges must use ObtainBuffer so page // Emulator-owned, CPU-current scratch only. Guest ranges must use ObtainBuffer so page
// ownership is resolved before any CPU access. // ownership is resolved before any CPU access.
[[nodiscard]] bool UploadHostData(CommandBuffer* command, GraphicContext* ctx, const void* src, [[nodiscard]] bool UploadHostData(CommandBuffer& command, const void* src, uint64_t size,
uint64_t size, uint64_t alignment, VulkanBuffer** out_buffer, uint64_t alignment, VulkanBuffer*& out_buffer,
uint64_t* out_offset, uint64_t* out_range); uint64_t& out_offset, uint64_t& out_range);
[[nodiscard]] VulkanBuffer* ObtainNullBuffer(CommandBuffer* command, GraphicContext* ctx); [[nodiscard]] VulkanBuffer& ObtainNullBuffer(CommandBuffer& command);
[[nodiscard]] BufferImageCopySource ObtainBufferForImage(uint64_t vaddr, uint64_t size); [[nodiscard]] BufferImageCopySource ObtainBufferForImage(uint64_t vaddr, uint64_t size);
void FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, uint64_t size, void FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, uint32_t value);
uint32_t value); void CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);
void CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t dst_vaddr,
uint64_t src_vaddr, uint64_t size);
[[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size); [[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsRegionCpuModified(uint64_t vaddr, uint64_t size); [[nodiscard]] bool IsRegionCpuModified(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsRegionGpuModified(uint64_t vaddr, uint64_t size); [[nodiscard]] bool IsRegionGpuModified(uint64_t vaddr, uint64_t size);
@@ -80,6 +83,7 @@ private:
struct CachedBuffer; struct CachedBuffer;
struct ReadbackWorker; struct ReadbackWorker;
GraphicContext& m_graphics;
Common::Mutex m_mutex; Common::Mutex m_mutex;
std::shared_ptr<VulkanBuffer> m_null_buffer; std::shared_ptr<VulkanBuffer> m_null_buffer;
// TODO: add LRU cache // TODO: add LRU cache
@@ -25,15 +25,13 @@ namespace Libs::Graphics {
static std::atomic<uint32_t> g_render_color_log_count = 0; static std::atomic<uint32_t> g_render_color_log_count = 0;
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, void ResolveRenderColorTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderColorInfo& r,
RenderColorInfo* r, uint32_t render_target_slice_offset, uint32_t render_target_slice_offset, uint32_t render_target_slot,
uint32_t render_target_slot, bool ignore_target_mask, bool ignore_target_mask, bool reuse_existing_render_texture) {
bool reuse_existing_render_texture) {
KYTY_PROFILER_FUNCTION(); 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(buffer)
const auto rt_slot = (render_target_slot == UINT32_MAX ? render_target_first_bound_slot(hw)
: render_target_slot); : render_target_slot);
const auto& rt = hw.GetRenderTarget(rt_slot); const auto& rt = hw.GetRenderTarget(rt_slot);
auto mask = render_target_mask_slot(hw.GetRenderTargetMask(), 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; mask = 0x0f;
} }
r->target_slot = rt_slot; r.target_slot = rt_slot;
r->export_mapping = {}; r.export_mapping = {};
if (rt.base.addr == 0 || mask == 0) { if (rt.base.addr == 0 || mask == 0) {
if (graphics_debug_dump_enabled()) { if (graphics_debug_dump_enabled()) {
@@ -58,17 +56,17 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
} }
// No color output // No color output
r->type = RenderColorType::NoColorOutput; r.type = RenderColorType::NoColorOutput;
r->base_addr = 0; r.base_addr = 0;
r->vulkan_buffer = nullptr; r.vulkan_buffer = nullptr;
r->vulkan_view = nullptr; r.vulkan_view = nullptr;
r->format = vk::Format::eUndefined; r.format = vk::Format::eUndefined;
r->extent = {}; r.extent = {};
r->base_mip_level = 0; r.base_mip_level = 0;
r->buffer_size = 0; r.buffer_size = 0;
r->samples = 1; r.samples = 1;
r->color_clear_enable = false; r.color_clear_enable = false;
r->color_clear_value = {}; r.color_clear_value = {};
return; return;
} }
const auto samples = render_sample_count(rt.attrib.num_fragments); 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, rt.view.base_array_slice_index, rt.view.last_array_slice_index,
render_target_slice_offset); 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; const uint32_t levels = rt.attrib2.num_mip_levels + 1u;
if (levels == 0 || levels > 16 || rt.view.current_mip_level >= levels) { if (levels == 0 || levels > 16 || rt.view.current_mip_level >= levels) {
EXIT("unsupported render-target mip range: current=%u levels=%u\n", 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. // SRGB clear words are still encoded as normalized component values.
// Fast color clears are metadata driven and must be handled explicitly when // Fast color clears are metadata driven and must be handled explicitly when
// that metadata path is implemented; render-pass load must preserve contents. // that metadata path is implemented; render-pass load must preserve contents.
r->color_clear_enable = false; r.color_clear_enable = false;
r->color_clear_value = {}; r.color_clear_value = {};
uint32_t width = 0; uint32_t width = 0;
uint32_t height = 0; uint32_t height = 0;
@@ -189,9 +187,9 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
} else { } else {
valid_layout = valid_layout =
levels == 1 ? TileGetRenderTargetSize(width, height, pitch, bytes_per_element, 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, : TileGetRenderTargetMipLayout(width, height, pitch, bytes_per_element,
levels, &layout, nullptr, nullptr); levels, layout, nullptr, nullptr);
} }
if (!valid_layout) { if (!valid_layout) {
EXIT("unsupported render-target layout: %ux%u pitch=%u bytes=%u levels=%u\n", width, 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.levels = levels;
target.layers = view.image_layers; target.layers = view.image_layers;
target.samples = samples; target.samples = samples;
auto* texture_cache = g_render_ctx->GetTextureCache(); auto& texture_cache = GetRenderContext().GetTextureCache();
auto* buffer_vulkan = auto& buffer_vulkan = texture_cache.FindRenderTarget(buffer, target);
texture_cache->FindRenderTarget(buffer, g_render_ctx->GetGraphicCtx(), target); r.type = RenderColorType::RenderTexture;
r->type = RenderColorType::RenderTexture; r.base_addr = rt.base.addr;
r->base_addr = rt.base.addr; r.vulkan_buffer = &buffer_vulkan;
r->vulkan_buffer = buffer_vulkan; r.vulkan_view = texture_cache.GetRenderTargetAttachmentView(
r->vulkan_view = texture_cache->GetRenderTargetAttachmentView( buffer_vulkan, target.format, rt.view.current_mip_level, view.base_layer,
g_render_ctx->GetGraphicCtx(), buffer_vulkan, target.format, rt.view.current_mip_level, view.layer_count);
view.base_layer, view.layer_count); r.format = target.format;
r->format = target.format; r.extent = view_extent;
r->extent = view_extent; r.base_mip_level = rt.view.current_mip_level;
r->base_mip_level = rt.view.current_mip_level; r.buffer_size = backing_size;
r->buffer_size = backing_size; r.samples = samples;
r->samples = samples; r.export_mapping = target_format.export_mapping;
r->export_mapping = target_format.export_mapping; r.color_clear_enable = buffer_vulkan.initial_clear_pending;
r->color_clear_enable = buffer_vulkan->initial_clear_pending; r.color_clear_value = {};
r->color_clear_value = {};
} else { } else {
if (samples != 1) { if (samples != 1) {
EXIT("multisampled display render targets are unsupported\n"); 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.size < size);
EXIT_NOT_IMPLEMENTED(video_image.pitch != pitch); EXIT_NOT_IMPLEMENTED(video_image.pitch != pitch);
r->type = RenderColorType::DisplayBuffer; r.type = RenderColorType::DisplayBuffer;
r->base_addr = rt.base.addr; r.base_addr = rt.base.addr;
r->vulkan_buffer = video_image.image; r.vulkan_buffer = video_image.image;
r->vulkan_view = video_image.image->image_view[VulkanImage::VIEW_DEFAULT]; r.vulkan_view = video_image.image->image_view[VulkanImage::VIEW_DEFAULT];
r->format = video_image.image->format; r.format = video_image.image->format;
r->extent = video_image.image->extent; r.extent = video_image.image->extent;
r->base_mip_level = 0; r.base_mip_level = 0;
r->buffer_size = video_image.size; r.buffer_size = video_image.size;
r->samples = 1; r.samples = 1;
r->export_mapping = target_format.export_mapping; r.export_mapping = target_format.export_mapping;
} }
} }
@@ -324,7 +321,7 @@ void MarkRenderTargetGpuWritten(const RenderColorInfo& target) {
if (with_color) { if (with_color) {
if (target.type == RenderColorType::RenderTexture || if (target.type == RenderColorType::RenderTexture ||
target.type == RenderColorType::DisplayBuffer) { target.type == RenderColorType::DisplayBuffer) {
g_render_ctx->GetTextureCache()->MarkGpuWritten(target.vulkan_buffer); GetRenderContext().GetTextureCache().MarkGpuWritten(*target.vulkan_buffer);
} else { } else {
EXIT("unknown writable render-color resource type\n"); EXIT("unknown writable render-color resource type\n");
} }
@@ -9,13 +9,9 @@
namespace Libs::Graphics { namespace Libs::Graphics {
class CommandBuffer; class RenderCommandBuffer;
struct VulkanImage; struct VulkanImage;
namespace HW {
class Context;
} // namespace HW
enum class RenderColorType { enum class RenderColorType {
NoColorOutput, NoColorOutput,
DisplayBuffer, DisplayBuffer,
@@ -39,8 +35,8 @@ struct RenderColorInfo {
vk::ClearColorValue color_clear_value {}; vk::ClearColorValue color_clear_value {};
}; };
void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, void ResolveRenderColorTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderColorInfo& r,
RenderColorInfo* r, uint32_t render_target_slice_offset = 0, uint32_t render_target_slice_offset = 0,
uint32_t render_target_slot = UINT32_MAX, uint32_t render_target_slot = UINT32_MAX,
bool ignore_target_mask = false, bool ignore_target_mask = false,
bool reuse_existing_render_texture = false); bool reuse_existing_render_texture = false);
+74 -60
View File
@@ -23,8 +23,11 @@
#include <atomic> #include <atomic>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <mutex>
namespace Libs::Graphics { namespace Libs::Graphics {
static std::atomic<uint64_t> g_command_buffer_submit_seq = 0; static std::atomic<uint64_t> 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) { static void RequireValidQueueId(int queue_id) {
EXIT_IF(queue_id < 0 || queue_id >= GraphicContext::QUEUES_NUM); EXIT_IF(queue_id < 0 || queue_id >= GraphicContext::QUEUES_NUM);
@@ -65,9 +68,18 @@ private:
std::array<VulkanCommandPool*, GraphicContext::QUEUES_NUM> m_pools {}; std::array<VulkanCommandPool*, GraphicContext::QUEUES_NUM> m_pools {};
}; };
RenderContext* g_render_ctx = nullptr; static RenderContext* g_render_ctx = nullptr;
static thread_local CommandPool g_command_pool; 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() { FenceResourceRetainer::~FenceResourceRetainer() {
if (!m_resources.empty()) { if (!m_resources.empty()) {
EXIT("fence resource retainer destroyed before release\n"); EXIT("fence resource retainer destroyed before release\n");
@@ -90,9 +102,9 @@ void FenceResourceRetainer::ReleaseAfterFence() noexcept {
} }
void GraphicsRenderInit() { void GraphicsRenderInit() {
EXIT_IF(g_render_ctx != nullptr); std::scoped_lock lock(g_render_init_mutex);
EXIT_IF(g_render_initialized || g_render_ctx != nullptr);
g_render_ctx = new RenderContext; g_render_initialized = true;
} }
void GraphicsRenderReleaseThreadCommandPools() { void GraphicsRenderReleaseThreadCommandPools() {
@@ -102,32 +114,43 @@ void GraphicsRenderReleaseThreadCommandPools() {
} }
void GraphicsRenderCreateContext() { 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) { void CommandPool::Create(int queue_id) {
RequireValidQueueId(queue_id); RequireValidQueueId(queue_id);
EXIT_IF(g_render_ctx == nullptr);
auto* ctx = g_render_ctx->GetGraphicCtx(); auto& graphics = GetRenderContext().GetGraphics();
auto*& pool = m_pools[queue_id]; auto*& pool = m_pools[queue_id];
EXIT_IF(pool != nullptr); EXIT_IF(pool != nullptr);
EXIT_IF(ctx == nullptr); EXIT_IF(graphics.device == nullptr);
EXIT_IF(ctx->device == nullptr); EXIT_IF(graphics.queues[queue_id].family == static_cast<uint32_t>(-1));
EXIT_IF(ctx->queues[queue_id].family == static_cast<uint32_t>(-1));
pool = new VulkanCommandPool; pool = new VulkanCommandPool;
vk::CommandPoolCreateInfo pool_info {}; vk::CommandPoolCreateInfo pool_info {};
pool_info.sType = vk::StructureType::eCommandPoolCreateInfo; pool_info.sType = vk::StructureType::eCommandPoolCreateInfo;
pool_info.pNext = nullptr; 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; 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); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool->pool == nullptr);
pool->buffers_count = 8; pool->buffers_count = 8;
@@ -142,7 +165,7 @@ void CommandPool::Create(int queue_id) {
alloc_info.level = vk::CommandBufferLevel::ePrimary; alloc_info.level = vk::CommandBufferLevel::ePrimary;
alloc_info.commandBufferCount = pool->buffers_count; 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) { vk::Result::eSuccess) {
EXIT("Can't allocate command buffers"); EXIT("Can't allocate command buffers");
} }
@@ -155,7 +178,7 @@ void CommandPool::Create(int queue_id) {
fence_info.pNext = nullptr; fence_info.pNext = nullptr;
fence_info.flags = vk::FenceCreateFlagBits::eSignaled; 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) { vk::Result::eSuccess) {
EXIT("Can't create fence"); EXIT("Can't create fence");
} }
@@ -165,7 +188,7 @@ void CommandPool::Create(int queue_id) {
semaphore_info.pNext = nullptr; semaphore_info.pNext = nullptr;
semaphore_info.flags = {}; 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) { vk::Result::eSuccess) {
EXIT("Can't create semaphore"); EXIT("Can't create semaphore");
} }
@@ -177,21 +200,21 @@ void CommandPool::Create(int queue_id) {
} }
void CommandPool::DeleteAll() { void CommandPool::DeleteAll() {
auto* ctx = g_render_ctx->GetGraphicCtx(); auto& graphics = GetRenderContext().GetGraphics();
for (auto& pool: m_pools) { for (auto& pool: m_pools) {
if (pool != nullptr) { if (pool != nullptr) {
EXIT_IF(ctx == nullptr); EXIT_IF(graphics.device == nullptr);
EXIT_IF(ctx->device == nullptr);
for (uint32_t i = 0; i < pool->buffers_count; i++) { for (uint32_t i = 0; i < pool->buffers_count; i++) {
ctx->device.destroySemaphore(pool->semaphores[i], nullptr); graphics.device.destroySemaphore(pool->semaphores[i], nullptr);
ctx->device.destroyFence(pool->fences[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; delete pool;
pool = nullptr; pool = nullptr;
@@ -200,8 +223,6 @@ void CommandPool::DeleteAll() {
} }
bool CommandBuffer::IsInvalid() const { bool CommandBuffer::IsInvalid() const {
EXIT_IF(g_render_ctx == nullptr);
if (m_pool != nullptr) { if (m_pool != nullptr) {
Common::LockGuard lock(m_pool->mutex); Common::LockGuard lock(m_pool->mutex);
@@ -255,10 +276,8 @@ void CommandBuffer::Free() {
EXIT_NOT_IMPLEMENTED(!IsInvalid()); EXIT_NOT_IMPLEMENTED(!IsInvalid());
} }
void CommandBuffer::DeleteAfterFence(VulkanBuffer* buffer) { void CommandBuffer::DeleteAfterFence(VulkanBuffer& buffer) {
EXIT_IF(buffer == nullptr); m_delete_after_fence.push_back(&buffer);
m_delete_after_fence.push_back(buffer);
} }
void CommandBuffer::RetainResourceUntilFence(std::shared_ptr<void> resource) { void CommandBuffer::RetainResourceUntilFence(std::shared_ptr<void> resource) {
@@ -268,15 +287,13 @@ void CommandBuffer::RetainResourceUntilFence(std::shared_ptr<void> resource) {
m_fence_resources.Retain(std::move(resource)); m_fence_resources.Retain(std::move(resource));
} }
void CommandBuffer::RecycleDescriptorAfterFence(VulkanDescriptorSet* set) { void CommandBuffer::RecycleDescriptorAfterFence(VulkanDescriptorSet& set) {
EXIT_IF(set == nullptr); m_descriptor_sets_after_fence.push_back(&set);
m_descriptor_sets_after_fence.push_back(set);
} }
void CommandBuffer::RecycleDescriptorsAfterFence() { void CommandBuffer::RecycleDescriptorsAfterFence() {
for (auto* set: m_descriptor_sets_after_fence) { for (auto* set: m_descriptor_sets_after_fence) {
g_render_ctx->GetDescriptorCache()->Recycle(set); GetRenderContext().GetDescriptorCache().Recycle(*set);
} }
m_descriptor_sets_after_fence.clear(); 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.signalSemaphoreCount = has_signal ? 1u : 0u;
submit_info.pSignalSemaphores = has_signal ? &signal_semaphore : nullptr; submit_info.pSignalSemaphores = has_signal ? &signal_semaphore : nullptr;
auto* ctx = g_render_ctx->GetGraphicCtx(); auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(ctx == nullptr); EXIT_IF(graphics.device == nullptr);
EXIT_IF(ctx->device == nullptr); const auto& queue = graphics.queues[m_queue];
const auto& queue = ctx->queues[m_queue];
auto result = ctx->device.resetFences(1, &fence); auto result = graphics.device.resetFences(1, &fence);
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(), LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(),
static_cast<int>(result)); static_cast<int>(result));
@@ -412,7 +428,7 @@ void CommandBuffer::WaitForFenceOnly() {
if (!m_execute || m_fence_waited) { if (!m_execute || m_fence_waited) {
return; 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); auto result = device.waitForFences(1, &m_pool->fences[m_index], VK_TRUE, UINT64_MAX);
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
LOGF("vkWaitForFences failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64 LOGF("vkWaitForFences failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64
@@ -456,21 +472,20 @@ void CommandBuffer::ReleaseResourcesAfterFence() {
void CommandBuffer::DeleteBuffersAfterFence() { void CommandBuffer::DeleteBuffersAfterFence() {
for (auto* buffer: m_delete_after_fence) { for (auto* buffer: m_delete_after_fence) {
VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer); GetRenderContext().GetGraphics().DeleteBuffer(*buffer);
delete buffer; delete buffer;
} }
m_delete_after_fence.clear(); m_delete_after_fence.clear();
} }
void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors, void CommandBuffer::BeginRenderPass(VulkanFramebuffer& framebuffer, RenderColorInfo* colors,
uint32_t requested_color_count, RenderDepthInfo* depth) const { uint32_t requested_color_count, RenderDepthInfo& depth) const {
auto buffer = Handle(); auto buffer = Handle();
EXIT_IF(framebuffer == nullptr);
EXIT_IF(colors == nullptr); EXIT_IF(colors == nullptr);
EXIT_IF(requested_color_count > RENDER_COLOR_ATTACHMENTS_MAX); 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; uint32_t color_count = 0;
for (uint32_t i = 0; i < requested_color_count; i++) { for (uint32_t i = 0; i < requested_color_count; i++) {
if (colors[i].vulkan_buffer == nullptr) { 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++) { for (uint32_t i = 0; i < color_count; i++) {
clears[i].color = colors[i].color_clear_value; 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 {}; vk::RenderPassBeginInfo render_pass_info {};
render_pass_info.sType = vk::StructureType::eRenderPassBeginInfo; render_pass_info.sType = vk::StructureType::eRenderPassBeginInfo;
render_pass_info.pNext = nullptr; render_pass_info.pNext = nullptr;
render_pass_info.renderPass = framebuffer->render_pass; render_pass_info.renderPass = framebuffer.render_pass;
render_pass_info.framebuffer = framebuffer->framebuffer; render_pass_info.framebuffer = framebuffer.framebuffer;
render_pass_info.renderArea.offset = {0, 0}; render_pass_info.renderArea.offset = {0, 0};
render_pass_info.renderArea.extent = extent; render_pass_info.renderArea.extent = extent;
render_pass_info.clearValueCount = color_count + (with_depth ? 1u : 0u); render_pass_info.clearValueCount = color_count + (with_depth ? 1u : 0u);
render_pass_info.pClearValues = clears; render_pass_info.pClearValues = clears;
for (uint32_t i = 0; i < color_count; i++) { 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 (colors[i].vulkan_buffer->layout != color_initial_layout) {
if (graphics_debug_dump_enabled()) { if (graphics_debug_dump_enabled()) {
LOGF("BeginRenderPass: color%u initial barrier image=%p mem=%" PRIu64 " %s -> %s\n", 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 = const auto depth_layout =
(with_depth && framebuffer != nullptr ? framebuffer->depth_layout with_depth ? framebuffer.depth_layout : vk::ImageLayout::eDepthStencilAttachmentOptimal;
: 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 {}; vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier;
image_memory_barrier.pNext = nullptr; image_memory_barrier.pNext = nullptr;
@@ -556,24 +570,24 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
(depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal (depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal
? vk::AccessFlagBits::eMemoryRead ? vk::AccessFlagBits::eMemoryRead
: vk::AccessFlagBits::eMemoryWrite); : 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.newLayout = depth_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = 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 = 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.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = 1; image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.baseArrayLayer = 0; 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( buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); 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); buffer.beginRenderPass(&render_pass_info, vk::SubpassContents::eInline);
@@ -586,8 +600,8 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
} }
} }
if (with_depth) { if (with_depth) {
depth->vulkan_buffer->initial_depth_clear_pending = false; depth.vulkan_buffer->initial_depth_clear_pending = false;
depth->vulkan_buffer->initial_stencil_clear_pending = false; depth.vulkan_buffer->initial_stencil_clear_pending = false;
} }
} }
+11 -7
View File
@@ -25,7 +25,8 @@ static bool RenderTargetMaskHasMrt(uint32_t mask) {
return (mask & ~0x0fu) != 0; return (mask & ~0x0fu) != 0;
} }
static bool RenderTargetMaskHasBoundMrt(const HW::Context& hw) { static bool RenderTargetMaskHasBoundMrt(const RenderCommandBuffer& buffer) {
const auto& hw = buffer.GetRegisters();
const auto mask = hw.GetRenderTargetMask(); const auto mask = hw.GetRenderTargetMask();
if (!RenderTargetMaskHasMrt(mask)) { if (!RenderTargetMaskHasMrt(mask)) {
@@ -42,7 +43,8 @@ static bool RenderTargetMaskHasBoundMrt(const HW::Context& hw) {
return bound_targets > 1; return bound_targets > 1;
} }
uint32_t render_target_first_bound_slot(const HW::Context& hw) { uint32_t render_target_first_bound_slot(const RenderCommandBuffer& buffer) {
const auto& hw = buffer.GetRegisters();
const auto mask = hw.GetRenderTargetMask(); const auto mask = hw.GetRenderTargetMask();
for (uint32_t i = 0; i < 8; i++) { for (uint32_t i = 0; i < 8; i++) {
if (render_target_mask_slot(mask, i) != 0 && hw.GetRenderTarget(i).base.addr != 0) { if (render_target_mask_slot(mask, i) != 0 && hw.GetRenderTarget(i).base.addr != 0) {
@@ -1241,8 +1243,9 @@ ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeC
return ScissorRectClamp(final, extent.width, extent.height); return ScissorRectClamp(final, extent.width, extent.height);
} }
void hw_check(const HW::Context& hw) { void hw_check(const RenderCommandBuffer& buffer) {
const auto rt_slot = render_target_first_bound_slot(hw); const auto& hw = buffer.GetRegisters();
const auto rt_slot = render_target_first_bound_slot(buffer);
const auto& rt = hw.GetRenderTarget(rt_slot); const auto& rt = hw.GetRenderTarget(rt_slot);
const auto& bc = hw.GetBlendControl(rt_slot); const auto& bc = hw.GetBlendControl(rt_slot);
const auto& bclr = hw.GetBlendColor(); const auto& bclr = hw.GetBlendColor();
@@ -1291,7 +1294,7 @@ void hw_check(const HW::Context& hw) {
AaCheck(aa, ac); AaCheck(aa, ac);
log_phase("done"); log_phase("done");
if (RenderTargetMaskHasBoundMrt(hw)) { if (RenderTargetMaskHasBoundMrt(buffer)) {
LOGF("MRT render target mask: 0x%08" PRIx32 "\n", hw.GetRenderTargetMask()); LOGF("MRT render target mask: 0x%08" PRIx32 "\n", hw.GetRenderTargetMask());
for (uint32_t i = 0; i < 8; i++) { for (uint32_t i = 0; i < 8; i++) {
const auto& mrt = hw.GetRenderTarget(i); const auto& mrt = hw.GetRenderTarget(i);
@@ -1312,8 +1315,9 @@ void hw_check(const HW::Context& hw) {
// EXIT_NOT_IMPLEMENTED(hw.GetStencilClearValue() != 0); // EXIT_NOT_IMPLEMENTED(hw.GetStencilClearValue() != 0);
} }
void hw_print(const HW::Context& hw) { void hw_print(const RenderCommandBuffer& buffer) {
const auto rt_slot = render_target_first_bound_slot(hw); const auto& hw = buffer.GetRegisters();
const auto rt_slot = render_target_first_bound_slot(buffer);
const auto& rt = hw.GetRenderTarget(rt_slot); const auto& rt = hw.GetRenderTarget(rt_slot);
const auto& bc = hw.GetBlendControl(rt_slot); const auto& bc = hw.GetBlendControl(rt_slot);
const auto& bclr = hw.GetBlendColor(); const auto& bclr = hw.GetBlendColor();
+5 -3
View File
@@ -9,6 +9,8 @@
namespace Libs::Graphics { namespace Libs::Graphics {
class RenderCommandBuffer;
namespace HW { namespace HW {
class Context; class Context;
class Shader; class Shader;
@@ -26,7 +28,7 @@ struct ScissorRect {
}; };
uint32_t render_target_mask_slot(uint32_t mask, uint32_t slot); 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(); bool graphics_debug_dump_enabled();
void uc_print(const char* func, const HW::UserConfig& uc); void uc_print(const char* func, const HW::UserConfig& uc);
void uc_check(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); void sh_check(const HW::Shader& uc);
std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt); std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt);
bool RenderIsColorTileModeLinear(uint32_t tile_mode); bool RenderIsColorTileModeLinear(uint32_t tile_mode);
void hw_print(const HW::Context& hw); void hw_print(const RenderCommandBuffer& buffer);
void hw_check(const HW::Context& hw); void hw_check(const RenderCommandBuffer& buffer);
void LogDrawPhase(const char* draw_name, const char* phase); void LogDrawPhase(const char* draw_name, const char* phase);
ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc, ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc,
vk::Extent2D extent); vk::Extent2D extent);
@@ -61,20 +61,18 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) {
depth_fail == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp); depth_fail == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp);
} }
[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(GraphicContext* ctx, [[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(const RenderCommandBuffer& buffer,
const DepthFormatPolicy& policy, const DepthFormatPolicy& policy,
bool has_stencil, bool has_stencil,
uint32_t samples) { uint32_t samples) {
if (ctx == nullptr) { auto& graphics = buffer.GetGraphics();
return vk::Format::eUndefined;
}
const auto required_samples = vulkan_sample_count(samples); const auto required_samples = vulkan_sample_count(samples);
const auto supports = [&](vk::Format format) { const auto supports = [&](vk::Format format) {
vk::ImageFormatProperties properties {}; vk::ImageFormatProperties properties {};
return format != vk::Format::eUndefined && return format != vk::Format::eUndefined &&
ctx->GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, graphics.GetImageFormatProperties(
DepthTargetImageUsage(), vk::ImageCreateFlags {}, format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, DepthTargetImageUsage(),
&properties) == vk::Result::eSuccess && vk::ImageCreateFlags {}, &properties) == vk::Result::eSuccess &&
static_cast<bool>(properties.sampleCounts & required_samples); static_cast<bool>(properties.sampleCounts & required_samples);
}; };
if (!has_stencil) { 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) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, void ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderDepthInfo& r) {
RenderDepthInfo* r) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(r == nullptr);
(void)submit_id; (void)submit_id;
(void)buffer; const auto& hw = buffer.GetRegisters();
const auto& z = hw.GetDepthRenderTarget(); const auto& z = hw.GetDepthRenderTarget();
const auto& rc = hw.GetRenderControl(); const auto& rc = hw.GetRenderControl();
const auto& dc = hw.GetDepthControl(); 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"); DepthFatal("unsupported depth/stencil format pair");
} }
const auto ideal_format = DepthAttachmentFormat(*policy, has_stencil); const auto ideal_format = DepthAttachmentFormat(*policy, has_stencil);
r->format = ResolveHostDepthAttachmentFormat(g_render_ctx->GetGraphicCtx(), *policy, r.format = ResolveHostDepthAttachmentFormat(buffer, *policy, has_stencil, samples);
has_stencil, samples); if (r.format == vk::Format::eUndefined) {
if (r->format == vk::Format::eUndefined) {
DepthFatal("no host depth/stencil format supports required usage for %s", DepthFatal("no host depth/stencil format supports required usage for %s",
VulkanToString(ideal_format).c_str()); VulkanToString(ideal_format).c_str());
} }
@@ -250,7 +245,7 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
TileSizeAlign stencil_size {}; TileSizeAlign stencil_size {};
TileSizeAlign htile_size {}; TileSizeAlign htile_size {};
if (!TileGetDepthSize(width, height, 0, z.z_info.format, z.stencil_info.format, has_htile, 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 || depth_size.align != 65536 || depth_size.size == 0 ||
(has_stencil != (stencil_size.align == 65536 && stencil_size.size != 0)) || (has_stencil != (stencil_size.align == 65536 && stencil_size.size != 0)) ||
(has_htile != (htile_size.align == 32768 && htile_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)) { (has_htile && htile_backing_size > TRACKER_ADDRESS_SIZE - z.htile_data_base_addr)) {
DepthFatal("layered depth backing range is invalid"); DepthFatal("layered depth backing range is invalid");
} }
r->htile = has_htile; r.htile = has_htile;
r->width = width; r.width = width;
r->height = height; r.height = height;
r->samples = samples; r.samples = samples;
r->depth_buffer_size = depth_backing_size; r.depth_buffer_size = depth_backing_size;
r->depth_buffer_vaddr = z.z_read_base_addr; r.depth_buffer_vaddr = z.z_read_base_addr;
r->stencil_buffer_size = has_stencil ? stencil_backing_size : 0; r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0;
r->stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 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_size = has_htile ? htile_backing_size : 0;
r->htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0; r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0;
auto* cache = g_render_ctx->GetTextureCache(); auto& cache = GetRenderContext().GetTextureCache();
if (has_htile) { if (has_htile) {
cache->RegisterMeta(g_render_ctx->GetGraphicCtx(), r->htile_buffer_vaddr, cache.RegisterMeta(r.htile_buffer_vaddr, r.htile_buffer_size, view.image_layers);
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"); DepthFatal("failed to acquire HTile metadata for a depth clear");
} }
const bool meta_clear = const bool meta_clear =
has_htile && cache->IsMetaCleared(z.htile_data_base_addr, z.depth_view.slice_start); has_htile && cache.IsMetaCleared(z.htile_data_base_addr, z.depth_view.slice_start);
r->depth_clear_enable = rc.depth_clear_enable; r.depth_clear_enable = rc.depth_clear_enable;
r->depth_meta_clear_enable = meta_clear; r.depth_meta_clear_enable = meta_clear;
r->depth_load_clear_enable = r->depth_clear_enable || r->depth_meta_clear_enable; r.depth_load_clear_enable = r.depth_clear_enable || r.depth_meta_clear_enable;
r->depth_clear_value = hw.GetDepthClearValue(); r.depth_clear_value = hw.GetDepthClearValue();
r->depth_test_enable = dc.z_enable; r.depth_test_enable = dc.z_enable;
r->depth_write_enable = dc.z_write_enable && !z.depth_view.depth_write_disable; r.depth_write_enable = dc.z_write_enable && !z.depth_view.depth_write_disable;
r->depth_compare_op = static_cast<vk::CompareOp>(dc.zfunc); r.depth_compare_op = static_cast<vk::CompareOp>(dc.zfunc);
r->depth_bounds_test_enable = dc.depth_bounds_enable; r.depth_bounds_test_enable = dc.depth_bounds_enable;
r->depth_min_bounds = hw.GetDepthBoundsMin(); r.depth_min_bounds = hw.GetDepthBoundsMin();
r->depth_max_bounds = hw.GetDepthBoundsMax(); r.depth_max_bounds = hw.GetDepthBoundsMax();
r->stencil_clear_enable = rc.stencil_clear_enable; r.stencil_clear_enable = rc.stencil_clear_enable;
r->stencil_clear_value = hw.GetStencilClearValue(); r.stencil_clear_value = hw.GetStencilClearValue();
r->stencil_test_enable = dc.stencil_enable; r.stencil_test_enable = dc.stencil_enable;
if (dc.stencil_enable) { if (dc.stencil_enable) {
if (dc.stencilfunc > static_cast<uint8_t>(vk::CompareOp::eAlways) || if (dc.stencilfunc > static_cast<uint8_t>(vk::CompareOp::eAlways) ||
(dc.backface_enable && (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)) { sm.stencil_opval_bf != sm.stencil_testval_bf)) {
DepthFatal("unsupported stencil compare or replacement state"); 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_fail), ConvertStencilOp(sc.stencil_zpass),
ConvertStencilOp(sc.stencil_zfail), static_cast<vk::CompareOp>(dc.stencilfunc)}; ConvertStencilOp(sc.stencil_zfail), static_cast<vk::CompareOp>(dc.stencilfunc)};
r->stencil_dynamic_front = {sm.stencil_mask, r.stencil_dynamic_front = {sm.stencil_mask,
rc.stencil_clear_enable ? 0u : sm.stencil_writemask, rc.stencil_clear_enable ? 0u : sm.stencil_writemask,
sm.stencil_testval}; sm.stencil_testval};
if (dc.backface_enable) { if (dc.backface_enable) {
r->stencil_static_back = {ConvertStencilOp(sc.stencil_fail_bf), r.stencil_static_back = {ConvertStencilOp(sc.stencil_fail_bf),
ConvertStencilOp(sc.stencil_zpass_bf), ConvertStencilOp(sc.stencil_zpass_bf),
ConvertStencilOp(sc.stencil_zfail_bf), ConvertStencilOp(sc.stencil_zfail_bf),
static_cast<vk::CompareOp>(dc.stencilfunc_bf)}; static_cast<vk::CompareOp>(dc.stencilfunc_bf)};
r->stencil_dynamic_back = {sm.stencil_mask_bf, r.stencil_dynamic_back = {sm.stencil_mask_bf,
rc.stencil_clear_enable ? 0u : sm.stencil_writemask_bf, rc.stencil_clear_enable ? 0u : sm.stencil_writemask_bf,
sm.stencil_testval_bf}; sm.stencil_testval_bf};
} else { } else {
r->stencil_static_back = r->stencil_static_front; r.stencil_static_back = r.stencil_static_front;
r->stencil_dynamic_back = r->stencil_dynamic_front; r.stencil_dynamic_back = r.stencil_dynamic_front;
} }
} }
r->vaddr_num = has_stencil ? 2 : 1; r.vaddr_num = has_stencil ? 2 : 1;
r->vaddr[0] = r->depth_buffer_vaddr; r.vaddr[0] = r.depth_buffer_vaddr;
r->size[0] = r->depth_buffer_size; r.size[0] = r.depth_buffer_size;
if (has_stencil) { if (has_stencil) {
r->vaddr[1] = r->stencil_buffer_vaddr; r.vaddr[1] = r.stencil_buffer_vaddr;
r->size[1] = r->stencil_buffer_size; r.size[1] = r.stencil_buffer_size;
} }
DepthTargetInfo info {}; DepthTargetInfo info {};
info.address = r->depth_buffer_vaddr; info.address = r.depth_buffer_vaddr;
info.size = r->depth_buffer_size; info.size = r.depth_buffer_size;
info.stencil_address = r->stencil_buffer_vaddr; info.stencil_address = r.stencil_buffer_vaddr;
info.stencil_size = r->stencil_buffer_size; info.stencil_size = r.stencil_buffer_size;
info.htile_address = r->htile_buffer_vaddr; info.htile_address = r.htile_buffer_vaddr;
info.htile_size = r->htile_buffer_size; info.htile_size = r.htile_buffer_size;
info.format = r->format; info.format = r.format;
info.guest_format = guest_format; info.guest_format = guest_format;
info.width = width; info.width = width;
info.height = height; 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.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kDepth);
info.layers = view.image_layers; info.layers = view.image_layers;
info.samples = samples; 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.depth_access = depth_active;
info.stencil_load_clear = rc.stencil_clear_enable; info.stencil_load_clear = rc.stencil_clear_enable;
info.stencil_access = info.stencil_access =
r->stencil_clear_enable || r.stencil_clear_enable ||
(r->stencil_test_enable && (r.stencil_test_enable &&
(stencil_face_accesses_attachment(r->stencil_static_front, r->stencil_dynamic_front) || (stencil_face_accesses_attachment(r.stencil_static_front, r.stencil_dynamic_front) ||
stencil_face_accesses_attachment(r->stencil_static_back, r->stencil_dynamic_back))); stencil_face_accesses_attachment(r.stencil_static_back, r.stencil_dynamic_back)));
info.stencil_htile_compressed = info.stencil_htile_compressed =
has_stencil && has_htile && !z.stencil_info.tile_stencil_disable; has_stencil && has_htile && !z.stencil_info.tile_stencil_disable;
r->vulkan_buffer = cache->FindDepthTarget(buffer, g_render_ctx->GetGraphicCtx(), info); r.vulkan_buffer = &cache.FindDepthTarget(buffer, info);
r->vulkan_view = cache->GetDepthTargetAttachmentView( r.vulkan_view =
g_render_ctx->GetGraphicCtx(), r->vulkan_buffer, view.base_layer, view.layer_count); cache.GetDepthTargetAttachmentView(*r.vulkan_buffer, view.base_layer, view.layer_count);
if (r->vulkan_buffer->initial_depth_clear_pending) { if (r.vulkan_buffer->initial_depth_clear_pending) {
r->depth_load_clear_enable = true; r.depth_load_clear_enable = true;
r->depth_clear_value = 0.0f; r.depth_clear_value = 0.0f;
} }
if (r->vulkan_buffer->initial_stencil_clear_pending) { if (r.vulkan_buffer->initial_stencil_clear_pending) {
r->stencil_clear_enable = true; r.stencil_clear_enable = true;
r->stencil_clear_value = 0; 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"); DepthFatal("failed to consume HTile clear state");
} }
} }
@@ -395,8 +389,8 @@ void MarkRenderTargetGpuWritten(const RenderDepthInfo& target) {
const bool with_depth = const bool with_depth =
target.format != vk::Format::eUndefined && target.vulkan_buffer != nullptr; target.format != vk::Format::eUndefined && target.vulkan_buffer != nullptr;
if (with_depth && !depth_attachment_read_only(&target)) { if (with_depth && !depth_attachment_read_only(target)) {
g_render_ctx->GetTextureCache()->MarkGpuWritten(target.vulkan_buffer); GetRenderContext().GetTextureCache().MarkGpuWritten(*target.vulkan_buffer);
} }
} }
@@ -9,13 +9,9 @@
namespace Libs::Graphics { namespace Libs::Graphics {
class CommandBuffer; class RenderCommandBuffer;
struct DepthStencilVulkanImage; struct DepthStencilVulkanImage;
namespace HW {
class Context;
} // namespace HW
inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stencil, bool has_htile, inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stencil, bool has_htile,
bool acceleration_disabled) { bool acceleration_disabled) {
return acceleration_disabled || (has_stencil && has_htile); return acceleration_disabled || (has_stencil && has_htile);
@@ -60,22 +56,20 @@ struct RenderDepthInfo {
int vaddr_num = 0; int vaddr_num = 0;
}; };
inline bool depth_attachment_read_only(const RenderDepthInfo* depth) { inline bool depth_attachment_read_only(const RenderDepthInfo& depth) {
EXIT_IF(depth == nullptr);
const bool stencil_write = const bool stencil_write =
depth->stencil_test_enable && depth.stencil_test_enable &&
(depth->stencil_dynamic_front.writeMask != 0 || depth->stencil_dynamic_back.writeMask != 0); (depth.stencil_dynamic_front.writeMask != 0 || depth.stencil_dynamic_back.writeMask != 0);
return !depth->depth_load_clear_enable && !depth->stencil_clear_enable && return !depth.depth_load_clear_enable && !depth.stencil_clear_enable &&
!depth->depth_write_enable && !stencil_write; !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 return depth_attachment_read_only(depth) ? vk::ImageLayout::eDepthStencilReadOnlyOptimal
: vk::ImageLayout::eDepthStencilAttachmentOptimal; : vk::ImageLayout::eDepthStencilAttachmentOptimal;
} }
void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, void ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderDepthInfo& r);
RenderDepthInfo* r);
void MarkRenderTargetGpuWritten(const RenderDepthInfo& target); void MarkRenderTargetGpuWritten(const RenderDepthInfo& target);
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -76,13 +76,12 @@ std::vector<uint32_t> LayoutKey(DescriptorCache::Stage stage,
return key; return key;
} }
vk::ImageLayout SampledLayout(const VulkanImage* image) { vk::ImageLayout SampledLayout(const VulkanImage& image) {
EXIT_IF(image == nullptr); switch (image.layout) {
switch (image->layout) {
case vk::ImageLayout::eTransferDstOptimal: case vk::ImageLayout::eTransferDstOptimal:
case vk::ImageLayout::eTransferSrcOptimal: case vk::ImageLayout::eTransferSrcOptimal:
case vk::ImageLayout::eColorAttachmentOptimal: return vk::ImageLayout::eGeneral; 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 } // namespace
vk::DescriptorSetLayout vk::DescriptorSetLayout
DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage, DescriptorCache::GetDescriptorSetLayoutInternal(Stage stage,
const ShaderRecompiler::IR::Program& program) { const ShaderRecompiler::IR::Program& program) {
EXIT_IF(gctx == nullptr);
const auto key = LayoutKey(stage, program); const auto key = LayoutKey(stage, program);
if (const auto found = m_descriptor_set_layouts.find(key); if (const auto found = m_descriptor_set_layouts.find(key);
found != m_descriptor_set_layouts.end()) { found != m_descriptor_set_layouts.end()) {
@@ -127,15 +125,14 @@ DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stag
info.bindingCount = static_cast<uint32_t>(bindings.size()); info.bindingCount = static_cast<uint32_t>(bindings.size());
info.pBindings = bindings.data(); info.pBindings = bindings.data();
vk::DescriptorSetLayout layout = nullptr; 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); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || layout == nullptr);
m_descriptor_set_layouts.emplace(key, layout); m_descriptor_set_layouts.emplace(key, layout);
return layout; return layout;
} }
void DescriptorCache::CreatePool(GraphicContext* gctx) { void DescriptorCache::CreatePool() {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(gctx == nullptr);
constexpr uint32_t MaxSets = 512; constexpr uint32_t MaxSets = 512;
const vk::DescriptorPoolSize sizes[] = { const vk::DescriptorPoolSize sizes[] = {
{vk::DescriptorType::eStorageBuffer, {vk::DescriptorType::eStorageBuffer,
@@ -152,7 +149,7 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) {
info.maxSets = MaxSets; info.maxSets = MaxSets;
const auto pool_id = static_cast<int>(m_pools.size()); const auto pool_id = static_cast<int>(m_pools.size());
auto& pool = m_pools.emplace_back(); 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); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool.pool == nullptr);
pool.next_free_pool = m_first_free_pool; pool.next_free_pool = m_first_free_pool;
m_first_free_pool = pool_id; m_first_free_pool = pool_id;
@@ -161,10 +158,8 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) {
VulkanDescriptorSet* DescriptorCache::Allocate(Stage stage, VulkanDescriptorSet* DescriptorCache::Allocate(Stage stage,
const ShaderRecompiler::IR::Program& program) { const ShaderRecompiler::IR::Program& program) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
const auto layout = GetDescriptorSetLayoutInternal(gctx, stage, program); const auto layout = GetDescriptorSetLayoutInternal(stage, program);
EXIT_IF(layout == nullptr); EXIT_IF(layout == nullptr);
auto& free_sets = m_free_sets_by_layout[layout]; auto& free_sets = m_free_sets_by_layout[layout];
if (!free_sets.empty()) { if (!free_sets.empty()) {
@@ -186,7 +181,8 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage
info.descriptorPool = pool.pool; info.descriptorPool = pool.pool;
info.descriptorSetCount = Batch; info.descriptorSetCount = Batch;
info.pSetLayouts = layouts.data(); 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); free_sets.reserve(free_sets.size() + Batch - 1u);
for (uint32_t i = 0; i + 1u < Batch; i++) { for (uint32_t i = 0; i + 1u < Batch; i++) {
free_sets.push_back(new VulkanDescriptorSet {sets[i], layout, pool_id}); 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; m_first_free_pool = pool.next_free_pool;
break; break;
} }
CreatePool(gctx); CreatePool();
} }
return nullptr; return nullptr;
} }
void DescriptorCache::Recycle(VulkanDescriptorSet* set) { void DescriptorCache::Recycle(VulkanDescriptorSet& set) {
EXIT_IF(set == nullptr || set->set == nullptr || set->layout == nullptr); EXIT_IF(set.set == nullptr || set.layout == nullptr);
Common::LockGuard lock(m_mutex); 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 ShaderRecompiler::IR::Program& program,
const NativeDescriptors& data) { const NativeDescriptors& data) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
@@ -215,8 +211,6 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
data.images.size() != program.info.images.size() || data.images.size() != program.info.images.size() ||
data.samplers.size() != program.info.samplers.size() || data.samplers.size() != program.info.samplers.size() ||
data.addresses.size() != program.info.addresses.size()); data.addresses.size() != program.info.addresses.size());
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
auto* set = Allocate(stage, program); auto* set = Allocate(stage, program);
EXIT_NOT_IMPLEMENTED(set == nullptr); EXIT_NOT_IMPLEMENTED(set == nullptr);
@@ -268,7 +262,7 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
const auto& texture = data.images.at(resource); const auto& texture = data.images.at(resource);
image_infos.push_back(MakeDescriptorImageInfo( image_infos.push_back(MakeDescriptorImageInfo(
texture, texture,
IsSampledImage(binding.kind) ? SampledLayout(texture.image) : layout)); IsSampledImage(binding.kind) ? SampledLayout(*texture.image) : layout));
} }
break; break;
} }
@@ -281,17 +275,15 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
} }
writes.push_back(write); writes.push_back(write);
} }
gctx->device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, m_graphics.device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0,
nullptr); nullptr);
return set; return *set;
} }
vk::DescriptorSetLayout vk::DescriptorSetLayout
DescriptorCache::GetDescriptorSetLayout(Stage stage, const ShaderRecompiler::IR::Program& program) { DescriptorCache::GetDescriptorSetLayout(Stage stage, const ShaderRecompiler::IR::Program& program) {
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
return GetDescriptorSetLayoutInternal(gctx, stage, program); return GetDescriptorSetLayoutInternal(stage, program);
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -63,14 +63,16 @@ public:
BufferView user_data; 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; } ~DescriptorCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(DescriptorCache); KYTY_CLASS_NO_COPY(DescriptorCache);
vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage, vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage,
const ShaderRecompiler::IR::Program& program); const ShaderRecompiler::IR::Program& program);
void Recycle(VulkanDescriptorSet* set); void Recycle(VulkanDescriptorSet& set);
VulkanDescriptorSet* GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program, VulkanDescriptorSet& GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program,
const NativeDescriptors& descriptors); const NativeDescriptors& descriptors);
private: private:
@@ -79,12 +81,12 @@ private:
int next_free_pool = -1; int next_free_pool = -1;
}; };
void CreatePool(GraphicContext* gctx); void CreatePool();
VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program); VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program);
vk::DescriptorSetLayout vk::DescriptorSetLayout
GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage, GetDescriptorSetLayoutInternal(Stage stage, const ShaderRecompiler::IR::Program& program);
const ShaderRecompiler::IR::Program& program);
GraphicContext& m_graphics;
Common::Mutex m_mutex; Common::Mutex m_mutex;
std::vector<Pool> m_pools; std::vector<Pool> m_pools;
int m_first_free_pool = -1; int m_first_free_pool = -1;
@@ -93,7 +95,7 @@ private:
std::map<std::vector<uint32_t>, vk::DescriptorSetLayout> m_descriptor_set_layouts; std::map<std::vector<uint32_t>, 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, vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout,
const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage, const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage,
DescriptorCache::Stage stage); DescriptorCache::Stage stage);
+84 -147
View File
@@ -49,13 +49,10 @@ namespace Libs::Graphics {
using TextureVariant = DescriptorCache::TextureVariant; using TextureVariant = DescriptorCache::TextureVariant;
static void BindNullStorageBuffer(CommandBuffer* cmd_buffer, BufferView* dst) { static void BindNullStorageBuffer(CommandBuffer& cmd_buffer, BufferView& dst) {
EXIT_IF(cmd_buffer == nullptr || dst == nullptr); dst.buffer = &GetRenderContext().GetBufferCache().ObtainNullBuffer(cmd_buffer);
dst.offset = 0;
dst->buffer = dst.range = 16;
g_render_ctx->GetBufferCache()->ObtainNullBuffer(cmd_buffer, g_render_ctx->GetGraphicCtx());
dst->offset = 0;
dst->range = 16;
} }
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
@@ -71,21 +68,19 @@ static const char* VulkanImageTypeName(VulkanImageType type) {
} }
} }
static int SampledArrayViewIndex(const VulkanImage* image, int view_index) { static int SampledArrayViewIndex(const VulkanImage& image, int view_index) {
EXIT_IF(image == nullptr);
switch (view_index) { switch (view_index) {
case VulkanImage::VIEW_DEFAULT: return VulkanImage::VIEW_DEFAULT_ARRAY; case VulkanImage::VIEW_DEFAULT: return VulkanImage::VIEW_DEFAULT_ARRAY;
default: return view_index; 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); 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 " EXIT("missing sampled array image view: image_type=%s base_view=%d array_view=%d "
"layers=%u\n", "layers=%u\n",
VulkanImageTypeName(image->type), base_view, array_view, image->layers); VulkanImageTypeName(image.type), base_view, array_view, image.layers);
} }
return array_view; return array_view;
} }
@@ -108,14 +103,14 @@ static int TextureVariantDefaultView(TextureVariant variant) {
: VulkanImage::VIEW_DEFAULT; : VulkanImage::VIEW_DEFAULT;
} }
static VulkanImage* GetDummySampledTexture(TextureVariant variant) { static VulkanImage& GetDummySampledTexture(TextureVariant variant) {
return g_render_ctx->GetTextureCache()->GetDummySampledTexture(TextureVariantIsUint(variant), return GetRenderContext().GetTextureCache().GetDummySampledTexture(
TextureVariantIs3D(variant)); TextureVariantIsUint(variant), TextureVariantIs3D(variant));
} }
static VulkanImage* GetDummyStorageTexture(TextureVariant variant) { static VulkanImage& GetDummyStorageTexture(TextureVariant variant) {
return g_render_ctx->GetTextureCache()->GetDummyStorageTexture(TextureVariantIsUint(variant), return GetRenderContext().GetTextureCache().GetDummyStorageTexture(
TextureVariantIs3D(variant)); TextureVariantIsUint(variant), TextureVariantIs3D(variant));
} }
static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& source, 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()); 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 ShaderBufferResource& descriptor,
const ShaderRecompiler::IR::BufferResource& resource) { const ShaderRecompiler::IR::BufferResource& resource) {
BufferView result; 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<uint32_t>(texture.Width5()) + 1u;
const auto height = static_cast<uint32_t>(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<uint64_t>(binding.second),
static_cast<uint64_t>(alignment));
}
result.buffer = binding.first;
result.offset = binding.second;
result.range = footprint.size;
return result;
}*/
const auto address = descriptor.Base48(); const auto address = descriptor.Base48();
const auto stride = descriptor.Stride(); const auto stride = descriptor.Stride();
const auto records = descriptor.NumRecords(); 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<uint64_t>(stride) * records : records; const auto size = stride != 0 ? static_cast<uint64_t>(stride) * records : records;
if (address == 0 || size == 0) { if (address == 0 || size == 0) {
BindNullStorageBuffer(command_buffer, &result); BindNullStorageBuffer(command_buffer, result);
return result; return result;
} }
auto* const ctx = g_render_ctx->GetGraphicCtx(); const auto& graphics = GetRenderContext().GetGraphics();
const auto alignment = ctx->StorageMinAlignment(); const auto alignment = graphics.StorageMinAlignment();
if (alignment == 0 || size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange || if (alignment == 0 ||
size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
BufferCache::CACHING_PAGE_SIZE % alignment != 0) { BufferCache::CACHING_PAGE_SIZE % alignment != 0) {
EXIT("storage buffer range or device alignment is unsupported\n"); EXIT("storage buffer range or device alignment is unsupported\n");
} }
(void)submit_id; (void)submit_id;
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer( auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(
command_buffer, ctx, address, size, resource.written, resource.read, resource.formatted); command_buffer, address, size, resource.written, resource.read, resource.formatted);
if (binding.second % alignment != 0) { if (binding.offset % alignment != 0) {
EXIT("storage buffer binding is not device-aligned\n"); EXIT("storage buffer binding is not device-aligned\n");
} }
result.buffer = binding.first; result.buffer = &binding.buffer;
result.offset = binding.second; result.offset = binding.offset;
result.range = static_cast<vk::DeviceSize>(size); result.range = static_cast<vk::DeviceSize>(size);
return result; return result;
} }
static BufferView 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::AddressResource& resource,
const ShaderRecompiler::IR::ResourceSnapshot::Address& address) { const ShaderRecompiler::IR::ResourceSnapshot::Address& address) {
BufferView result; BufferView result;
if (address.binding_base == 0) { if (address.binding_base == 0) {
BindNullStorageBuffer(command_buffer, &result); BindNullStorageBuffer(command_buffer, result);
return result; return result;
} }
if (resource.written) { if (resource.written) {
@@ -224,26 +168,28 @@ NativeAddressBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
} }
const auto limit = resource.kind == ShaderRecompiler::IR::ResourceKind::Flat const auto limit = resource.kind == ShaderRecompiler::IR::ResourceKind::Flat
? ShaderRecompiler::IR::FlatAddressWindowSize ? ShaderRecompiler::IR::FlatAddressWindowSize
: static_cast<uint64_t>(g_render_ctx->GetGraphicCtx() : static_cast<uint64_t>(GetRenderContext()
->GetPhysicalDeviceProperties() .GetGraphics()
.GetPhysicalDeviceProperties()
.limits.maxStorageBufferRange); .limits.maxStorageBufferRange);
uint64_t size = 0; uint64_t size = 0;
const auto access = HostMemoryAccess::Mapped; 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", EXIT("address resource is not host-accessible: base=0x%016" PRIx64 "\n",
address.binding_base); address.binding_base);
} }
auto* const ctx = g_render_ctx->GetGraphicCtx(); const auto& graphics = GetRenderContext().GetGraphics();
const auto alignment = ctx->StorageMinAlignment(); const auto alignment = graphics.StorageMinAlignment();
if (alignment == 0 || size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange || if (alignment == 0 ||
size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
BufferCache::GetBufferOffset(address.binding_base) % alignment != 0) { BufferCache::GetBufferOffset(address.binding_base) % alignment != 0) {
EXIT("address resource range or alignment is unsupported\n"); EXIT("address resource range or alignment is unsupported\n");
} }
(void)submit_id; (void)submit_id;
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(command_buffer, ctx, auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(command_buffer,
address.binding_base, size); address.binding_base, size);
result.buffer = binding.first; result.buffer = &binding.buffer;
result.offset = binding.second; result.offset = binding.offset;
result.range = static_cast<vk::DeviceSize>(size); result.range = static_cast<vk::DeviceSize>(size);
return result; return result;
} }
@@ -529,7 +475,7 @@ void ValidateMetadataReuseTexture(const ShaderRecompiler::IR::ImageResource& res
} }
static DescriptorCache::TextureBinding 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::ImageResource& resource,
const ShaderRecompiler::IR::DescriptorValue& value) { const ShaderRecompiler::IR::DescriptorValue& value) {
ShaderTextureResource descriptor; ShaderTextureResource descriptor;
@@ -541,9 +487,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
ValidateStorageImageResource(resource); ValidateStorageImageResource(resource);
} }
if (descriptor.IsNull()) { if (descriptor.IsNull()) {
return storage ? DescriptorCache::TextureBinding {GetDummyStorageTexture(variant), return storage ? DescriptorCache::TextureBinding {&GetDummyStorageTexture(variant),
TextureVariantDefaultView(variant)} TextureVariantDefaultView(variant)}
: DescriptorCache::TextureBinding {GetDummySampledTexture(variant), : DescriptorCache::TextureBinding {&GetDummySampledTexture(variant),
TextureVariantDefaultView(variant)}; TextureVariantDefaultView(variant)};
} }
const auto address = descriptor.Base40(); const auto address = descriptor.Base40();
@@ -578,12 +524,12 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
const auto swizzle = descriptor.DstSelXYZW(); const auto swizzle = descriptor.DstSelXYZW();
TileSizeAlign size; TileSizeAlign size;
TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile, TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile,
type == Prospero::ImageType::kColor3D, &size); type == Prospero::ImageType::kColor3D, size);
EXIT_NOT_IMPLEMENTED(size.size == 0 || EXIT_NOT_IMPLEMENTED(size.size == 0 ||
(address & (static_cast<uint64_t>(size.align) - 1u)) != 0); (address & (static_cast<uint64_t>(size.align) - 1u)) != 0);
if (storage) { if (storage) {
ValidateStorageTexture(resource, descriptor, size.size); ValidateStorageTexture(resource, descriptor, size.size);
g_render_ctx->GetBufferCache()->ValidateGpuAccess(address, size.size, resource.read, GetRenderContext().GetBufferCache().ValidateGpuAccess(address, size.size, resource.read,
resource.written); resource.written);
} }
@@ -594,11 +540,11 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
descriptor.MsaaDepth(); descriptor.MsaaDepth();
if (image == nullptr) { if (image == nullptr) {
if (check_depth) { if (check_depth) {
image = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(command_buffer, address, image = GetRenderContext().GetTextureCache().FindDepthTargetByRange(
size.size, true); command_buffer, address, size.size, true);
} else { } else {
image = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(command_buffer, image = GetRenderContext().GetTextureCache().FindRenderTargetByRange(
address, size.size); command_buffer, address, size.size);
} }
if (image != nullptr) { if (image != nullptr) {
if (check_depth) { if (check_depth) {
@@ -628,10 +574,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
static_cast<uint32_t>(resource.dimension), descriptor.Type(), static_cast<uint32_t>(resource.dimension), descriptor.Type(),
descriptor.BaseArray5(), image->layers); descriptor.BaseArray5(), image->layers);
} }
image_view = g_render_ctx->GetTextureCache()->GetDepthTargetSampledView( image_view = GetRenderContext().GetTextureCache().GetDepthTargetSampledView(
g_render_ctx->GetGraphicCtx(), static_cast<DepthStencilVulkanImage*>(image), *static_cast<DepthStencilVulkanImage*>(image), view_format, swizzle, 0, 1,
view_format, swizzle, 0, 1, depth_view.type, depth_view.base_layer, depth_view.type, depth_view.base_layer, depth_view.layer_count);
depth_view.layer_count);
} }
} else { } else {
if (!(storage ? IsSupportedStorageImageResource(resource) if (!(storage ? IsSupportedStorageImageResource(resource)
@@ -657,23 +602,21 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
} }
if (storage) { if (storage) {
view = SelectStorageColorView(image->format, view_format, swizzle); view = SelectStorageColorView(image->format, view_format, swizzle);
image_view = g_render_ctx->GetTextureCache()->GetRenderTargetStorageView( image_view = GetRenderContext().GetTextureCache().GetRenderTargetStorageView(
g_render_ctx->GetGraphicCtx(), *static_cast<RenderTextureVulkanImage*>(image), view_format, base_level,
static_cast<RenderTextureVulkanImage*>(image), view_format, base_level,
view_levels, target_view.type, target_view.base_layer, view_levels, target_view.type, target_view.base_layer,
target_view.layer_count); target_view.layer_count);
} else { } else {
image_view = g_render_ctx->GetTextureCache()->GetSampledColorView( image_view = GetRenderContext().GetTextureCache().GetSampledColorView(
g_render_ctx->GetGraphicCtx(), image, view_format, swizzle, base_level, *image, view_format, swizzle, base_level, view_levels, target_view.type,
view_levels, target_view.type, target_view.base_layer, target_view.base_layer, target_view.layer_count);
target_view.layer_count);
} }
} }
if (image != nullptr && image_view == nullptr && image->image_view[view] == nullptr) { if (image != nullptr && image_view == nullptr && image->image_view[view] == nullptr) {
EXIT("required cached texture image view is missing\n"); EXIT("required cached texture image view is missing\n");
} }
if (storage && image != nullptr) { 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; image = video.image;
view = VulkanImage::VIEW_STORAGE; view = VulkanImage::VIEW_STORAGE;
g_render_ctx->GetTextureCache()->MarkGpuWritten(image); GetRenderContext().GetTextureCache().MarkGpuWritten(*image);
} else { } else {
const bool exact = const bool exact =
IsSupportedSampledVideoOutView(resource, descriptor, *video.image) && IsSupportedSampledVideoOutView(resource, descriptor, *video.image) &&
@@ -721,15 +664,14 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
static_cast<uint32_t>(type), size.size, video.size, pitch, video.pitch); static_cast<uint32_t>(type), size.size, video.size, pitch, video.pitch);
} }
image = video.image; image = video.image;
image_view = g_render_ctx->GetTextureCache()->GetSampledColorView( image_view = GetRenderContext().GetTextureCache().GetSampledColorView(
g_render_ctx->GetGraphicCtx(), video.image, view_format, swizzle, 0, 1, *video.image, view_format, swizzle, 0, 1, vk::ImageViewType::e2D, 0, 1);
vk::ImageViewType::e2D, 0, 1);
} }
} }
} }
if (image == nullptr) { if (image == nullptr) {
auto* texture_cache = g_render_ctx->GetTextureCache(); auto& texture_cache = GetRenderContext().GetTextureCache();
const bool metadata_read = texture_cache->QueryRegion(address, size.size).metadata_pages; const bool metadata_read = texture_cache.QueryRegion(address, size.size).metadata_pages;
if (storage && metadata_read) { if (storage && metadata_read) {
EXIT("storage texture overlaps surface metadata\n"); EXIT("storage texture overlaps surface metadata\n");
} }
@@ -754,19 +696,15 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
info.type = descriptor.Type(); info.type = descriptor.Type();
info.base_array = descriptor.BaseArray5(); info.base_array = descriptor.BaseArray5();
if (storage) { if (storage) {
image = texture_cache->FindStorageTexture(command_buffer, g_render_ctx->GetGraphicCtx(), image = &texture_cache.FindStorageTexture(command_buffer, info);
info);
view = VulkanImage::VIEW_DEFAULT; view = VulkanImage::VIEW_DEFAULT;
image_view = texture_cache->GetStorageTextureStorageView( image_view = texture_cache.GetStorageTextureStorageView(
g_render_ctx->GetGraphicCtx(), static_cast<StorageTextureVulkanImage*>(image), *static_cast<StorageTextureVulkanImage*>(image), base_level);
base_level);
} else { } else {
image = texture_cache->FindTexture(command_buffer, g_render_ctx->GetGraphicCtx(), info, image = &texture_cache.FindTexture(command_buffer, info, metadata_read);
metadata_read);
if (image->type == VulkanImageType::StorageTexture) { if (image->type == VulkanImageType::StorageTexture) {
image_view = texture_cache->GetStorageTextureSampledView( image_view = texture_cache.GetStorageTextureSampledView(
g_render_ctx->GetGraphicCtx(), static_cast<StorageTextureVulkanImage*>(image), *static_cast<StorageTextureVulkanImage*>(image), info);
info);
} }
} }
} }
@@ -774,7 +712,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
if (NeedsStaticSampledArrayView(resource.dimension == if (NeedsStaticSampledArrayView(resource.dimension ==
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray, ShaderRecompiler::Decoder::ImageDimension::Dim2DArray,
image_view != nullptr)) { image_view != nullptr)) {
view = SelectSampledTextureArrayView(image, view); view = SelectSampledTextureArrayView(*image, view);
} }
return {image, view, image_view}; return {image, view, image_view};
} }
@@ -792,31 +730,31 @@ static vk::Sampler NativeSampler(const ShaderRecompiler::IR::Program& program, u
if (!depth_compare) { if (!depth_compare) {
descriptor.fields[0] &= ~(0x7u << 12u); 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<const uint32_t> data) { static BufferView NativeUpload(CommandBuffer& command_buffer, std::span<const uint32_t> data) {
EXIT_IF(data.empty()); EXIT_IF(data.empty());
BufferView result; BufferView result;
EXIT_IF(!g_render_ctx->GetBufferCache()->UploadHostData( EXIT_IF(!GetRenderContext().GetBufferCache().UploadHostData(
command_buffer, g_render_ctx->GetGraphicCtx(), data.data(), data.size_bytes(), 256, command_buffer, data.data(), data.size_bytes(), 256, result.buffer, result.offset,
&result.buffer, &result.offset, &result.range)); result.range));
return result; 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, vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout,
const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage, const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage,
DescriptorCache::Stage stage) { DescriptorCache::Stage stage) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(buffer == nullptr || !runtime); EXIT_IF(!runtime);
const auto& program = *runtime.program; const auto& program = *runtime.program;
const auto& snapshot = *runtime.resources; const auto& snapshot = *runtime.resources;
std::string error; std::string error;
if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) { if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) {
EXIT("invalid native shader runtime snapshot: %s\n", error.c_str()); 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); const auto shader_stages = ShaderPipelineStages(vk_stage);
DescriptorCache::NativeDescriptors descriptors; DescriptorCache::NativeDescriptors descriptors;
@@ -864,8 +802,7 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
} }
if (ShaderRecompiler::IR::FindBinding( if (ShaderRecompiler::IR::FindBinding(
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) { program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) {
descriptors.gds.buffer = descriptors.gds.buffer = &GetRenderContext().GetGdsBuffer().GetBuffer();
g_render_ctx->GetGdsBuffer()->GetBuffer(g_render_ctx->GetGraphicCtx());
const auto barrier = MakeGdsDependency(*descriptors.gds.buffer); const auto barrier = MakeGdsDependency(*descriptors.gds.buffer);
vk_buffer.pipelineBarrier( vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eHost | vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eHost | vk::PipelineStageFlagBits::eTransfer |
@@ -880,14 +817,14 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) { resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) {
switch (image->type) { switch (image->type) {
case VulkanImageType::DepthStencil: case VulkanImageType::DepthStencil:
GraphicsRenderDepthStencilBarrier(vk_buffer, image); GraphicsRenderDepthStencilBarrier(vk_buffer, *image);
break; break;
case VulkanImageType::RenderTexture: case VulkanImageType::RenderTexture:
case VulkanImageType::StorageTexture: case VulkanImageType::StorageTexture:
GraphicsRenderTextureBarrier(vk_buffer, image); GraphicsRenderTextureBarrier(vk_buffer, *image);
break; break;
case VulkanImageType::VideoOut: case VulkanImageType::VideoOut:
GraphicsRenderColorImageBarrier(vk_buffer, image, RENDER_COLOR_IMAGE_LAYOUT); GraphicsRenderColorImageBarrier(vk_buffer, *image, RENDER_COLOR_IMAGE_LAYOUT);
break; break;
default: break; default: break;
} }
@@ -901,11 +838,11 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
} }
if (!program.bindings.descriptors.empty()) { if (!program.bindings.descriptors.empty()) {
auto* set = g_render_ctx->GetDescriptorCache()->GetDescriptor(stage, program, descriptors); auto& set =
EXIT_IF(set == nullptr); GetRenderContext().GetDescriptorCache().GetDescriptor(stage, program, descriptors);
vk_buffer.bindDescriptorSets(pipeline_bind_point, layout, program.bindings.descriptor_set, vk_buffer.bindDescriptorSets(pipeline_bind_point, layout, program.bindings.descriptor_set,
1, &set->set, 0, nullptr); 1, &set.set, 0, nullptr);
buffer->RecycleDescriptorAfterFence(set); buffer.RecycleDescriptorAfterFence(set);
} }
if (program.bindings.push_constant_size != 0) { if (program.bindings.push_constant_size != 0) {
EXIT_IF(program.bindings.push_constant_size != user_data.size() * sizeof(uint32_t)); EXIT_IF(program.bindings.push_constant_size != user_data.size() * sizeof(uint32_t));
@@ -4,6 +4,8 @@
#include "graphics/host_gpu/renderer/image.h" #include "graphics/host_gpu/renderer/image.h"
#include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/transfer.h"
#include <algorithm>
namespace Libs::Graphics { namespace Libs::Graphics {
namespace { namespace {
@@ -16,15 +18,17 @@ namespace {
DummyTextureCache::~DummyTextureCache() { DummyTextureCache::~DummyTextureCache() {
Common::LockGuard lock(m_mutex); 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; return;
} }
Transfer::WaitForGraphicsIdle();
Transfer::WaitForGraphicsIdle(m_ctx); const auto destroy = [](auto& slots) {
const auto destroy = [this](auto& slots) {
for (auto& slot: slots) { for (auto& slot: slots) {
if (slot.image != nullptr) { if (slot.image != nullptr) {
ImageOps::Destroy(m_ctx, slot.image); ImageOps::Destroy(*slot.image);
slot.image = nullptr; slot.image = nullptr;
} }
} }
@@ -33,26 +37,15 @@ DummyTextureCache::~DummyTextureCache() {
destroy(m_storage); destroy(m_storage);
} }
VulkanImage* DummyTextureCache::Get(GraphicContext* ctx, Usage usage, bool uint_format, VulkanImage& DummyTextureCache::Get(Usage usage, bool uint_format, bool image_3d) {
bool image_3d) {
Common::LockGuard lock(m_mutex); 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<const void*>(m_ctx), static_cast<const void*>(ctx),
static_cast<uint32_t>(usage));
}
m_ctx = ctx;
auto& slots = usage == Usage::Storage ? m_storage : m_sampled; auto& slots = usage == Usage::Storage ? m_storage : m_sampled;
auto& slot = slots[DummyTextureIndex(uint_format, image_3d)]; auto& slot = slots[DummyTextureIndex(uint_format, image_3d)];
if (slot.image == nullptr) { if (slot.image == nullptr) {
slot.image = slot.image = ImageOps::CreateDummyTexture(uint_format, image_3d,
ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, usage == Usage::Storage); usage == Usage::Storage);
} }
return slot.image; return *slot.image;
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -18,8 +18,7 @@ public:
~DummyTextureCache(); ~DummyTextureCache();
KYTY_CLASS_NO_COPY(DummyTextureCache); KYTY_CLASS_NO_COPY(DummyTextureCache);
[[nodiscard]] VulkanImage* Get(GraphicContext* ctx, Usage usage, bool uint_format, [[nodiscard]] VulkanImage& Get(Usage usage, bool uint_format, bool image_3d);
bool image_3d);
private: private:
struct Slot { struct Slot {
@@ -29,7 +28,6 @@ private:
Common::Mutex m_mutex; Common::Mutex m_mutex;
std::array<Slot, 4> m_sampled {}; std::array<Slot, 4> m_sampled {};
std::array<Slot, 4> m_storage {}; std::array<Slot, 4> m_storage {};
GraphicContext* m_ctx = nullptr;
}; };
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -15,17 +15,15 @@ namespace Libs::Graphics {
VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
uint32_t requested_color_count, uint32_t requested_color_count,
RenderDepthInfo* depth) { RenderDepthInfo& depth) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
EXIT_IF(colors == nullptr); EXIT_IF(colors == nullptr);
EXIT_IF(depth == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(requested_color_count > RENDER_COLOR_ATTACHMENTS_MAX); 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] = {}; bool with_color[RENDER_COLOR_ATTACHMENTS_MAX] = {};
uint32_t color_count = 0; uint32_t color_count = 0;
VulkanImage* first_color = nullptr; VulkanImage* first_color = nullptr;
@@ -58,16 +56,16 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
color_count++; color_count++;
} }
if (with_depth) { 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", 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) { if (attachment_samples == 0) {
attachment_samples = depth->samples; attachment_samples = depth.samples;
} else if (attachment_samples != depth->samples) { } else if (attachment_samples != depth.samples) {
EXIT( EXIT(
"Framebuffer: mixed color/depth sample counts are unsupported, color=%u depth=%u\n", "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) { if (!with_depth && color_count == 0) {
@@ -87,26 +85,26 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
(with_depth && depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal); (with_depth && depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal);
if (with_depth && first_color != nullptr && if (with_depth && first_color != nullptr &&
(first_color_extent.width != depth->vulkan_buffer->extent.width || (first_color_extent.width != depth.vulkan_buffer->extent.width ||
first_color_extent.height != depth->vulkan_buffer->extent.height)) { first_color_extent.height != depth.vulkan_buffer->extent.height)) {
static std::atomic<uint32_t> log_count {0}; static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF("Framebuffer: temporary: dropping mismatched PS5 depth attachment color=%ux%u " LOGF("Framebuffer: temporary: dropping mismatched PS5 depth attachment color=%ux%u "
"depth=%ux%u format=%s\n", "depth=%ux%u format=%s\n",
first_color_extent.width, first_color_extent.height, first_color_extent.width, first_color_extent.height,
depth->vulkan_buffer->extent.width, depth->vulkan_buffer->extent.height, depth.vulkan_buffer->extent.width, depth.vulkan_buffer->extent.height,
VulkanToString(depth->format).c_str()); VulkanToString(depth.format).c_str());
} }
depth->format = vk::Format::eUndefined; depth.format = vk::Format::eUndefined;
depth->vulkan_buffer = nullptr; depth.vulkan_buffer = nullptr;
depth->vulkan_view = nullptr; depth.vulkan_view = nullptr;
depth->depth_test_enable = false; depth.depth_test_enable = false;
depth->depth_write_enable = false; depth.depth_write_enable = false;
depth->depth_bounds_test_enable = false; depth.depth_bounds_test_enable = false;
depth->stencil_test_enable = false; depth.stencil_test_enable = false;
depth->depth_clear_enable = false; depth.depth_clear_enable = false;
depth->depth_load_clear_enable = false; depth.depth_load_clear_enable = false;
depth->stencil_clear_enable = false; depth.stencil_clear_enable = false;
with_depth = false; with_depth = false;
depth_layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; depth_layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
depth_read_only = false; depth_read_only = false;
@@ -125,22 +123,21 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
(i < color_count && with_color[i] && colors[i].color_clear_enable) && (i < color_count && with_color[i] && colors[i].color_clear_enable) &&
f.color_layout[i] == color_layout[i]; f.color_layout[i] == color_layout[i];
} }
if (color_match && if (color_match && f.depth_id == (with_depth ? depth.vulkan_buffer->memory.unique_id : 0) &&
f.depth_id == (with_depth ? depth->vulkan_buffer->memory.unique_id : 0) && f.depth_view == (with_depth ? depth.vulkan_view : nullptr) &&
f.depth_view == (with_depth ? depth->vulkan_view : nullptr) && f.depth_clear_enable == depth.depth_load_clear_enable &&
f.depth_clear_enable == depth->depth_load_clear_enable && f.stencil_clear_enable == depth.stencil_clear_enable &&
f.stencil_clear_enable == depth->stencil_clear_enable &&
f.depth_read_only == depth_read_only) { f.depth_read_only == depth_read_only) {
return f.framebuffer; return f.framebuffer;
} }
} }
EXIT_NOT_IMPLEMENTED(with_depth && first_color != nullptr && EXIT_NOT_IMPLEMENTED(with_depth && first_color != nullptr &&
(first_color_extent.width != depth->vulkan_buffer->extent.width || (first_color_extent.width != depth.vulkan_buffer->extent.width ||
first_color_extent.height != depth->vulkan_buffer->extent.height)); first_color_extent.height != depth.vulkan_buffer->extent.height));
if (first_color == nullptr) { if (first_color == nullptr) {
first_color_extent = depth->vulkan_buffer->extent; first_color_extent = depth.vulkan_buffer->extent;
} }
auto* framebuffer = new VulkanFramebuffer; auto* framebuffer = new VulkanFramebuffer;
@@ -152,10 +149,6 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
} }
framebuffer->depth_layout = depth_layout; framebuffer->depth_layout = depth_layout;
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
vk::AttachmentDescription attachments[RENDER_COLOR_ATTACHMENTS_MAX + 1] = {}; vk::AttachmentDescription attachments[RENDER_COLOR_ATTACHMENTS_MAX + 1] = {};
for (uint32_t i = 0; i < color_count; i++) { for (uint32_t i = 0; i < color_count; i++) {
attachments[i].flags = {}; attachments[i].flags = {};
@@ -172,14 +165,14 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
const uint32_t depth_attachment = color_count; const uint32_t depth_attachment = color_count;
attachments[depth_attachment].flags = {}; 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].samples = vulkan_sample_count(attachment_samples);
attachments[depth_attachment].loadOp = attachments[depth_attachment].loadOp =
(depth->depth_load_clear_enable ? vk::AttachmentLoadOp::eClear (depth.depth_load_clear_enable ? vk::AttachmentLoadOp::eClear
: vk::AttachmentLoadOp::eLoad); : vk::AttachmentLoadOp::eLoad);
attachments[depth_attachment].storeOp = vk::AttachmentStoreOp::eStore; attachments[depth_attachment].storeOp = vk::AttachmentStoreOp::eStore;
attachments[depth_attachment].stencilLoadOp = 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].stencilStoreOp = vk::AttachmentStoreOp::eStore;
attachments[depth_attachment].initialLayout = depth_layout; attachments[depth_attachment].initialLayout = depth_layout;
attachments[depth_attachment].finalLayout = depth_layout; attachments[depth_attachment].finalLayout = depth_layout;
@@ -246,7 +239,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
render_pass_info.pDependencies = dependencies; render_pass_info.pDependencies = dependencies;
auto result = 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); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
vk::Format color_formats[RENDER_COLOR_ATTACHMENTS_MAX] = {}; vk::Format color_formats[RENDER_COLOR_ATTACHMENTS_MAX] = {};
@@ -254,7 +247,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
color_formats[i] = colors[i].format; color_formats[i] = colors[i].format;
} }
framebuffer->render_pass_id = render_pass_compat_id( 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); EXIT_NOT_IMPLEMENTED(framebuffer->render_pass == nullptr);
@@ -266,10 +259,10 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
views[i] = colors[i].vulkan_view; views[i] = colors[i].vulkan_view;
} }
if (with_depth) { if (with_depth) {
if (depth->vulkan_view == nullptr) { if (depth.vulkan_view == nullptr) {
EXIT("Framebuffer: depth attachment view is missing\n"); EXIT("Framebuffer: depth attachment view is missing\n");
} }
views[color_count] = depth->vulkan_view; views[color_count] = depth.vulkan_view;
} }
vk::FramebufferCreateInfo framebuffer_info {}; vk::FramebufferCreateInfo framebuffer_info {};
@@ -283,7 +276,8 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
framebuffer_info.height = first_color_extent.height; framebuffer_info.height = first_color_extent.height;
framebuffer_info.layers = 1; 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(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(framebuffer->framebuffer == nullptr); 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); (i < color_count && with_color[i] && colors[i].color_clear_enable);
fnew.color_layout[i] = color_layout[i]; fnew.color_layout[i] = color_layout[i];
} }
fnew.depth_id = (with_depth ? depth->vulkan_buffer->memory.unique_id : 0); fnew.depth_id = (with_depth ? depth.vulkan_buffer->memory.unique_id : 0);
fnew.depth_view = (with_depth ? depth->vulkan_view : nullptr); fnew.depth_view = (with_depth ? depth.vulkan_view : nullptr);
fnew.depth_clear_enable = depth->depth_load_clear_enable; fnew.depth_clear_enable = depth.depth_load_clear_enable;
fnew.stencil_clear_enable = depth->stencil_clear_enable; fnew.stencil_clear_enable = depth.stencil_clear_enable;
fnew.depth_read_only = depth_read_only; fnew.depth_read_only = depth_read_only;
bool updated = false; bool updated = false;
@@ -321,28 +315,21 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
return framebuffer; return framebuffer;
} }
void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) { void FramebufferCache::FreeFramebufferByColor(VulkanImage& image) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(image == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
for (auto& f: m_framebuffers) { for (auto& f: m_framebuffers) {
bool uses_image = false; bool uses_image = false;
for (auto image_id: f.image_id) { for (auto image_id: f.image_id) {
if (image_id == image->memory.unique_id) { if (image_id == image.memory.unique_id) {
uses_image = true; uses_image = true;
break; break;
} }
} }
if (f.framebuffer != nullptr && uses_image) { if (f.framebuffer != nullptr && uses_image) {
auto* gctx = g_render_ctx->GetGraphicCtx(); m_graphics.device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
EXIT_IF(gctx == nullptr); m_graphics.device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
gctx->device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
gctx->device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
delete f.framebuffer; delete f.framebuffer;
@@ -351,21 +338,14 @@ void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) {
} }
} }
void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage* image) { void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage& image) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(image == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
for (auto& f: m_framebuffers) { for (auto& f: m_framebuffers) {
if (f.framebuffer != nullptr && f.depth_id == image->memory.unique_id) { if (f.framebuffer != nullptr && f.depth_id == image.memory.unique_id) {
auto* gctx = g_render_ctx->GetGraphicCtx(); m_graphics.device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
EXIT_IF(gctx == nullptr); m_graphics.device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
gctx->device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
gctx->device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
delete f.framebuffer; delete f.framebuffer;
@@ -50,14 +50,16 @@ inline uint64_t render_pass_compat_id(uint32_t color_count, const vk::Format* co
class FramebufferCache { class FramebufferCache {
public: 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; } ~FramebufferCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FramebufferCache); KYTY_CLASS_NO_COPY(FramebufferCache);
VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count, VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth); RenderDepthInfo& depth);
void FreeFramebufferByColor(VulkanImage* image); void FreeFramebufferByColor(VulkanImage& image);
void FreeFramebufferByDepth(DepthStencilVulkanImage* image); void FreeFramebufferByDepth(DepthStencilVulkanImage& image);
private: private:
struct Framebuffer { struct Framebuffer {
@@ -73,6 +75,7 @@ private:
bool depth_read_only = false; bool depth_read_only = false;
}; };
GraphicContext& m_graphics;
Common::Mutex m_mutex; Common::Mutex m_mutex;
std::vector<Framebuffer> m_framebuffers; std::vector<Framebuffer> m_framebuffers;
}; };
+13 -16
View File
@@ -6,7 +6,7 @@
namespace Libs::Graphics { namespace Libs::Graphics {
void GdsBuffer::Init(GraphicContext* ctx) { void GdsBuffer::Init() {
if (m_buffer == nullptr) { if (m_buffer == nullptr) {
m_buffer = std::make_unique<VulkanBuffer>(); m_buffer = std::make_unique<VulkanBuffer>();
@@ -14,57 +14,54 @@ void GdsBuffer::Init(GraphicContext* ctx) {
m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible | m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached; 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, void GdsBuffer::Clear(uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value) {
uint32_t clear_value) {
EXIT_IF(ctx == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
Init(ctx); Init();
EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE); EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE);
EXIT_NOT_IMPLEMENTED(dw_offset + dw_num > DW_SIZE); EXIT_NOT_IMPLEMENTED(dw_offset + dw_num > DW_SIZE);
void* data = nullptr; 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++) { for (uint32_t i = 0; i < dw_num; i++) {
static_cast<uint32_t*>(data)[dw_offset + i] = clear_value; static_cast<uint32_t*>(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); EXIT_IF(dst == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
Init(ctx); Init();
EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE); EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE);
EXIT_NOT_IMPLEMENTED(dw_offset + dw_size > DW_SIZE); EXIT_NOT_IMPLEMENTED(dw_offset + dw_size > DW_SIZE);
void* data = nullptr; 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++) { for (uint32_t i = 0; i < dw_size; i++) {
dst[i] = static_cast<uint32_t*>(data)[dw_offset + i]; dst[i] = static_cast<uint32_t*>(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); Common::LockGuard lock(m_mutex);
Init(ctx); Init();
return m_buffer.get(); return *m_buffer;
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
+8 -5
View File
@@ -13,20 +13,23 @@ namespace Libs::Graphics {
class GdsBuffer { class GdsBuffer {
public: 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; } ~GdsBuffer() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(GdsBuffer); KYTY_CLASS_NO_COPY(GdsBuffer);
void Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value); void Clear(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 Read(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size);
VulkanBuffer* GetBuffer(GraphicContext* ctx); VulkanBuffer& GetBuffer();
private: private:
static constexpr uint64_t DW_SIZE = 0x3000; static constexpr uint64_t DW_SIZE = 0x3000;
void Init(GraphicContext* ctx); void Init();
GraphicContext& m_graphics;
Common::Mutex m_mutex; Common::Mutex m_mutex;
std::unique_ptr<VulkanBuffer> m_buffer; std::unique_ptr<VulkanBuffer> m_buffer;
}; };
@@ -9,9 +9,9 @@
namespace Libs::Graphics { namespace Libs::Graphics {
GpuResourceManager::GpuResourceManager() GpuResourceManager::GpuResourceManager(GraphicContext& graphics)
: m_page_manager(FaultThunk, this), m_buffer_cache(m_page_manager, m_resource_mutex), : m_page_manager(FaultThunk, this), m_buffer_cache(graphics, m_page_manager, m_resource_mutex),
m_texture_cache(m_page_manager, m_buffer_cache, m_resource_mutex) { m_texture_cache(graphics, m_page_manager, m_buffer_cache, m_resource_mutex) {
m_buffer_cache.SetTextureCache(m_texture_cache); 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]() { const auto handle_range = [this, vaddr, size]() {
if (!m_page_manager.HandleWriteRange(vaddr, size)) { if (!m_page_manager.HandleWriteRange(vaddr, size)) {
EXIT("failed to prepare host write, addr=0x%016" PRIx64 " size=0x%016" PRIx64 EXIT("failed to prepare host write, addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
"\n",
vaddr, size); vaddr, size);
} }
}; };
@@ -113,22 +112,22 @@ void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size, GpuAccess ac
m_page_manager.OnGpuUnmap(vaddr, size, access); 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) { 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"); EXIT("cannot fill a buffer without a valid render command context\n");
} }
Common::LockGuard lock(g_render_ctx->GetMutex()); Common::LockGuard lock(GetRenderContext().GetMutex());
m_buffer_cache.FillBuffer(command, g_render_ctx->GetGraphicCtx(), vaddr, size, value); 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) { 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"); EXIT("cannot copy a buffer without a valid render command context\n");
} }
Common::LockGuard lock(g_render_ctx->GetMutex()); Common::LockGuard lock(GetRenderContext().GetMutex());
m_buffer_cache.CopyBuffer(command, g_render_ctx->GetGraphicCtx(), dst_vaddr, src_vaddr, size); m_buffer_cache.CopyBuffer(&command, dst_vaddr, src_vaddr, size);
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -16,20 +16,20 @@ class CommandBuffer;
class GpuResourceManager { class GpuResourceManager {
public: public:
GpuResourceManager(); explicit GpuResourceManager(GraphicContext& graphics);
~GpuResourceManager(); ~GpuResourceManager();
KYTY_CLASS_NO_COPY(GpuResourceManager); KYTY_CLASS_NO_COPY(GpuResourceManager);
[[nodiscard]] BufferCache* GetBufferCache() { return &m_buffer_cache; } [[nodiscard]] BufferCache& GetBufferCache() { return m_buffer_cache; }
[[nodiscard]] TextureCache* GetTextureCache() { return &m_texture_cache; } [[nodiscard]] TextureCache& GetTextureCache() { return m_texture_cache; }
[[nodiscard]] bool HandleFault(PageFaultAccess access, uint64_t fault_vaddr) noexcept; [[nodiscard]] bool HandleFault(PageFaultAccess access, uint64_t fault_vaddr) noexcept;
void PrepareHostWrite(uint64_t vaddr, uint64_t size); void PrepareHostWrite(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsMapped(uint64_t vaddr, uint64_t size) const noexcept; [[nodiscard]] bool IsMapped(uint64_t vaddr, uint64_t size) const noexcept;
void MapMemory(uint64_t vaddr, uint64_t size, GpuAccess access); void MapMemory(uint64_t vaddr, uint64_t size, GpuAccess access);
void UnmapMemory(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 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 CopyBuffer(CommandBuffer& command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);
private: private:
static bool FaultThunk(void* context, PageFaultAccess access, uint64_t vaddr, uint64_t size, static bool FaultThunk(void* context, PageFaultAccess access, uint64_t vaddr, uint64_t size,
+88 -86
View File
@@ -50,15 +50,15 @@ TextureImageCreateParams MakeImageParams(const ImageInfo& info, bool storage) {
return params; return params;
} }
bool RenderTargetSupportsStorage(GraphicContext* ctx, vk::Format format, bool RenderTargetSupportsStorage(vk::Format format,
vk::ImageCreateFlags flags) { vk::ImageCreateFlags flags) {
const auto compatible = SrgbStorageViewFormat(format); const auto compatible = SrgbStorageViewFormat(format);
const auto required_flags = const auto required_flags =
vk::ImageCreateFlagBits::eMutableFormat | vk::ImageCreateFlagBits::eExtendedUsage; vk::ImageCreateFlagBits::eMutableFormat | vk::ImageCreateFlagBits::eExtendedUsage;
const bool compatible_views = (flags & required_flags) == required_flags; const bool compatible_views = (flags & required_flags) == required_flags;
return ImageViewOps::FormatSupportsStorage(ctx, format) || return ImageViewOps::FormatSupportsStorage(format) ||
(compatible_views && compatible != vk::Format::eUndefined && (compatible_views && compatible != vk::Format::eUndefined &&
ImageViewOps::FormatSupportsStorage(ctx, compatible)); ImageViewOps::FormatSupportsStorage(compatible));
} }
vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) { vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) {
@@ -72,20 +72,21 @@ vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) {
: vk::ImageCreateFlags {0}; : vk::ImageCreateFlags {0};
} }
vk::ImageUsageFlags RenderTargetUsage(GraphicContext* ctx, vk::Format format, vk::ImageUsageFlags RenderTargetUsage(vk::Format format,
vk::ImageCreateFlags flags, uint32_t samples) { vk::ImageCreateFlags flags, uint32_t samples) {
auto& graphics = GetRenderContext().GetGraphics();
auto usage = static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eColorAttachment) | auto usage = static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eColorAttachment) |
static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eTransferSrc) | static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eTransferSrc) |
static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eTransferDst); static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eTransferDst);
if (samples == 1) { if (samples == 1) {
usage |= vk::ImageUsageFlagBits::eSampled; usage |= vk::ImageUsageFlagBits::eSampled;
if (RenderTargetSupportsStorage(ctx, format, flags)) { if (RenderTargetSupportsStorage(format, flags)) {
usage |= vk::ImageUsageFlagBits::eStorage; usage |= vk::ImageUsageFlagBits::eStorage;
} }
} }
vk::ImageFormatProperties properties {}; vk::ImageFormatProperties properties {};
if (ctx->GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, usage, if (graphics.GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal,
flags, &properties) != vk::Result::eSuccess || usage, flags, &properties) != vk::Result::eSuccess ||
!static_cast<bool>(properties.sampleCounts & vulkan_sample_count(samples))) { !static_cast<bool>(properties.sampleCounts & vulkan_sample_count(samples))) {
EXIT("TextureCache: render-target format does not support required usage, format=%d " EXIT("TextureCache: render-target format does not support required usage, format=%d "
"usage=0x%x samples=%u supported=0x%x\n", "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); return RenderTargetTransferFormatImpl(bytes_per_element);
} }
GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage, GpuTextureVulkanImage* CreateTexture(const ImageInfo& info, bool storage,
vk::ComponentMapping* components) { vk::ComponentMapping& components) {
if (components == nullptr) {
EXIT("TextureCache: invalid texture component output\n");
}
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage) auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
: new TextureVulkanImage; : new TextureVulkanImage;
*components = TextureCreateImage(ctx, image, MakeImageParams(info, storage)); components = TextureCreateImage(*image, MakeImageParams(info, storage));
return image; return image;
} }
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, void CreateTextureViews(GpuTextureVulkanImage& image,
bool storage, vk::ComponentMapping components) { const ImageInfo& info, bool storage, vk::ComponentMapping components) {
if (storage) { 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); TextureFormatUsage::Sampled | TextureFormatUsage::Storage);
} else { } else {
TextureCreateImageViews(ctx, image, components, info.type, info.base_array, info.base_level, TextureCreateImageViews(image, components, info.type, info.base_array,
info.view_levels, info.depth, true, TextureFormatUsage::Sampled); 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, const RenderTargetInfo& info, uint32_t base_layer,
uint32_t layer_count, bool refresh) { uint32_t layer_count, bool refresh) {
if (info.layers == 0 || info.size % info.layers != 0 || layer_count == 0 || 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 >= info.layers || layer_count > info.layers - base_layer ||
base_layer >= image->layers || layer_count > image->layers - base_layer) { base_layer >= image.layers || layer_count > image.layers - base_layer) {
EXIT("TextureCache: invalid render-target layer upload, base=%u count=%u " EXIT("TextureCache: invalid render-target layer upload, base=%u count=%u "
"info_layers=%u image_layers=%u size=0x%016" PRIx64 "\n", "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", EXIT("TextureCache: multisampled render-target upload is unsupported, samples=%u/%u\n",
info.samples, image->samples); info.samples, image.samples);
} }
if (refresh) { if (refresh) {
Transfer::WaitForGraphicsIdle(ctx); Transfer::WaitForGraphicsIdle();
} }
const auto slice_size = info.size / info.layers; const auto slice_size = info.size / info.layers;
const auto upload_size = slice_size * layer_count; const auto upload_size = slice_size * layer_count;
@@ -208,7 +207,7 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
region.dst_layer += base_layer; region.dst_layer += base_layer;
} }
const auto source_address = info.address + slice_size * base_layer; const auto source_address = info.address + slice_size * base_layer;
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(source_address), TextureUploadGuestImage(image, reinterpret_cast<const void*>(source_address),
upload_size, regions, layout, format, info.width, info.height, upload_size, regions, layout, format, info.width, info.height,
layer_count, info.levels, "TextureCache render target", layer_count, info.levels, "TextureCache render target",
vk::ImageLayout::eGeneral); vk::ImageLayout::eGeneral);
@@ -222,21 +221,23 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
"TextureCache render target"); "TextureCache render target");
auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1, auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1,
true, false, TextureUploadDestination::MipLevels); true, false, TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size, TextureUploadGuestImage(image, reinterpret_cast<const void*>(info.address),
regions, layout, format, info.width, info.height, 1, 1, slice_size, regions, layout, format, info.width, info.height, 1, 1,
"TextureCache render target", vk::ImageLayout::eGeneral); "TextureCache render target", vk::ImageLayout::eGeneral);
} else { } else {
Transfer::UploadImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size, Transfer::UploadImage(image, reinterpret_cast<const void*>(info.address),
info.pitch, vk::ImageLayout::eGeneral); slice_size, info.pitch, vk::ImageLayout::eGeneral);
} }
} }
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image, void UploadRenderTarget(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, bool refresh) { 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; auto* image = new RenderTextureVulkanImage;
image->extent.width = info.width; image->extent.width = info.width;
image->extent.height = info.height; image->extent.height = info.height;
@@ -255,20 +256,21 @@ RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTa
create.format = info.format; create.format = info.format;
create.tiling = vk::ImageTiling::eOptimal; create.tiling = vk::ImageTiling::eOptimal;
create.initialLayout = vk::ImageLayout::eUndefined; 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.sharingMode = vk::SharingMode::eExclusive;
create.samples = vulkan_sample_count(info.samples); create.samples = vulkan_sample_count(info.samples);
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; 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 EXIT("TextureCache: failed to create render target, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n", " extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format)); info.address, info.width, info.height, static_cast<int>(info.format));
} }
ImageViewOps::CreateRenderTargetViews(ctx, image); ImageViewOps::CreateRenderTargetViews(*image);
return image; return image;
} }
DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info) { DepthStencilVulkanImage* CreateDepthTarget(const DepthTargetInfo& info) {
auto& graphics = GetRenderContext().GetGraphics();
vk::ImageCreateInfo create {}; vk::ImageCreateInfo create {};
create.sType = vk::StructureType::eImageCreateInfo; create.sType = vk::StructureType::eImageCreateInfo;
create.imageType = vk::ImageType::e2D; create.imageType = vk::ImageType::e2D;
@@ -282,9 +284,9 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
create.sharingMode = vk::SharingMode::eExclusive; create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vulkan_sample_count(info.samples); create.samples = vulkan_sample_count(info.samples);
vk::ImageFormatProperties properties {}; vk::ImageFormatProperties properties {};
if (ctx->GetImageFormatProperties(info.format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, if (graphics.GetImageFormatProperties(
create.usage, vk::ImageCreateFlags {}, info.format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, create.usage,
&properties) != vk::Result::eSuccess || vk::ImageCreateFlags {}, &properties) != vk::Result::eSuccess ||
!static_cast<bool>(properties.sampleCounts & create.samples)) { !static_cast<bool>(properties.sampleCounts & create.samples)) {
EXIT("TextureCache: depth format does not support required usage, format=%d usage=0x%x " EXIT("TextureCache: depth format does not support required usage, format=%d usage=0x%x "
"samples=%u supported=0x%x\n", "samples=%u supported=0x%x\n",
@@ -302,16 +304,16 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
image->layout = vk::ImageLayout::eUndefined; image->layout = vk::ImageLayout::eUndefined;
image->compressed = false; image->compressed = false;
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; 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 EXIT("TextureCache: failed to create depth target, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n", " extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format)); info.address, info.width, info.height, static_cast<int>(info.format));
} }
ImageViewOps::CreateDepthViews(ctx, image); ImageViewOps::CreateDepthViews(*image);
return image; return image;
} }
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) { void ValidateVideoOut(const VideoOutInfo& info) {
const auto compression = const auto compression =
ClassifyVideoOutCompression(info.compression != VideoOutCompression::Uncompressed, ClassifyVideoOutCompression(info.compression != VideoOutCompression::Uncompressed,
info.metadata_address, info.dcc_control, 0); 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 >= TRACKER_ADDRESS_SIZE ||
(info.metadata_address >= info.address && (info.metadata_address >= info.address &&
info.metadata_address < info.address + info.size)); info.metadata_address < info.address + info.size));
if (ctx == nullptr || info.address == 0 || info.size == 0 || if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE ||
info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address || info.size > TRACKER_ADDRESS_SIZE - info.address || (info.address & 0xffffu) != 0 ||
(info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 || info.width == 0 || info.height == 0 || info.width > 16384 || info.height > 16384 ||
info.width > 16384 || info.height > 16384 || info.pitch < info.width || info.pitch < info.width ||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
compression == VideoOutCompression::Unsupported || compression != info.compression || compression == VideoOutCompression::Unsupported || compression != info.compression ||
metadata_invalid || !IsSupportedVideoOutFormat(info)) { metadata_invalid || !IsSupportedVideoOutFormat(info)) {
EXIT("TextureCache: unsupported video-out surface, ctx=%p addr=0x%016" PRIx64 EXIT("TextureCache: unsupported video-out surface, addr=0x%016" PRIx64 " size=0x%016" PRIx64
" size=0x%016" PRIx64 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32
" extent=%ux%u pitch=%u tile=%u guest_format=%u bpe=%u vk_format=%d\n", " extent=%ux%u pitch=%u tile=%u guest_format=%u bpe=%u vk_format=%d\n",
static_cast<const void*>(ctx), info.address, info.size, info.metadata_address, info.address, info.size, info.metadata_address, info.dcc_control, info.width,
info.dcc_control, info.width, info.height, info.pitch, info.tile_mode, info.height, info.pitch, info.tile_mode, info.guest_format, info.bytes_per_element,
info.guest_format, info.bytes_per_element, static_cast<int>(info.format)); static_cast<int>(info.format));
} }
TileSizeAlign exact {}; TileSizeAlign exact {};
TileGetTextureTotalSize(info.guest_format, info.width, info.height, 1, info.pitch, 1, 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 || if (exact.align != 65536 || exact.size != info.size ||
TileGetTexturePitch(info.guest_format, info.width, 1, info.tile_mode) != info.pitch) { TileGetTexturePitch(info.guest_format, info.width, 1, info.tile_mode) != info.pitch) {
EXIT("TextureCache: video-out tile layout mismatch, addr=0x%016" PRIx64 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", " pitch=%u\n",
info.address, info.size, exact.size, exact.align, info.pitch); 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; auto* image = new VideoOutVulkanImage;
image->extent.width = info.width; image->extent.width = info.width;
image->extent.height = info.height; image->extent.height = info.height;
@@ -363,20 +366,20 @@ VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& inf
create.tiling = vk::ImageTiling::eOptimal; create.tiling = vk::ImageTiling::eOptimal;
create.initialLayout = vk::ImageLayout::eUndefined; create.initialLayout = vk::ImageLayout::eUndefined;
create.flags = RenderTargetCreateFlags(info.format); 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.sharingMode = vk::SharingMode::eExclusive;
create.samples = vk::SampleCountFlagBits::e1; create.samples = vk::SampleCountFlagBits::e1;
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; 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 EXIT("TextureCache: failed to create video-out image, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n", " extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format)); info.address, info.width, info.height, static_cast<int>(info.format));
} }
ImageViewOps::CreateVideoOutViews(ctx, image); ImageViewOps::CreateVideoOutViews(*image);
return image; return image;
} }
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info, void UploadVideoOut(VideoOutVulkanImage& image, const VideoOutInfo& info,
bool refresh) { bool refresh) {
if (info.compression != VideoOutCompression::Uncompressed) { if (info.compression != VideoOutCompression::Uncompressed) {
EXIT("TextureCache: compressed video-out guest upload is unsupported, " 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); info.address, info.metadata_address, info.dcc_control);
} }
if (refresh) { if (refresh) {
Transfer::WaitForGraphicsIdle(ctx); Transfer::WaitForGraphicsIdle();
} }
image->layout = vk::ImageLayout::eUndefined; image.layout = vk::ImageLayout::eUndefined;
if (!info.bgra16) { if (!info.bgra16) {
auto layout = auto layout =
TextureCalcUploadLayout(info.guest_format, info.width, info.height, 1, 1, info.pitch, TextureCalcUploadLayout(info.guest_format, info.width, info.height, 1, 1, info.pitch,
info.tile_mode, info.size, false, false, "VideoOut"); info.tile_mode, info.size, false, false, "VideoOut");
auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1, auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1,
false, false, TextureUploadDestination::MipLevels); false, false, TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(info.address), info.size, TextureUploadGuestImage(image, reinterpret_cast<const void*>(info.address),
regions, layout, info.guest_format, info.width, info.height, 1, 1, info.size, regions, layout, info.guest_format, info.width,
"VideoOut", vk::ImageLayout::eGeneral); info.height, 1, 1, "VideoOut", vk::ImageLayout::eGeneral);
return; return;
} }
Transfer::ScratchBuffer scratch(info.size); Transfer::ScratchBuffer scratch(info.size);
TileBlockLayout block {}; TileBlockLayout block {};
EXIT_NOT_IMPLEMENTED( 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, const GpuTileInfo tile_info {block.family,
block.bytes_per_element, block.bytes_per_element,
0, 0,
@@ -413,10 +416,10 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
info.height, info.height,
1, 1,
info.pitch}; info.pitch};
GpuDetile(ctx, reinterpret_cast<const void*>(info.address), scratch.Data(), info.size, GpuDetile(reinterpret_cast<const void*>(info.address), scratch.Data(), info.size,
info.size, std::span<const GpuTileInfo>(&tile_info, 1)); info.size, std::span<const GpuTileInfo>(&tile_info, 1));
SwapVideoOutBgra16(scratch.Data(), info.size); 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); 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) { bool storage) {
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage) auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
: new TextureVulkanImage; : new TextureVulkanImage;
@@ -436,48 +439,47 @@ GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture"; auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture";
auto params = MakeDummyTextureParams(uint_format, image_3d, usage, owner); 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; static constexpr uint32_t zero = 0;
Transfer::UploadImage(ctx, image, &zero, sizeof(zero), 1, layout); Transfer::UploadImage(*image, &zero, sizeof(zero), 1, layout);
TextureCreateImageViews(ctx, image, components, params.type, 0, params.base_level, TextureCreateImageViews(*image, components, params.type, 0, params.base_level,
params.levels, params.depth, params.allow_cube_view, params.view_usage); params.levels, params.depth, params.allow_cube_view, params.view_usage);
return image; return image;
} }
void Destroy(GraphicContext* ctx, VulkanImage* image) { void Destroy(VulkanImage& image) {
auto& graphics = GetRenderContext().GetGraphics();
KYTY_PROFILER_BLOCK("TextureCache::DeleteImage"); 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::RenderTexture:
case VulkanImageType::VideoOut: case VulkanImageType::VideoOut:
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image); GetRenderContext().GetFramebufferCache().FreeFramebufferByColor(image);
break; break;
case VulkanImageType::DepthStencil: case VulkanImageType::DepthStencil:
g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth( GetRenderContext().GetFramebufferCache().FreeFramebufferByDepth(
static_cast<DepthStencilVulkanImage*>(image)); static_cast<DepthStencilVulkanImage&>(image));
break; break;
case VulkanImageType::Texture: case VulkanImageType::Texture:
case VulkanImageType::StorageTexture: break; case VulkanImageType::StorageTexture: break;
case VulkanImageType::Unknown: EXIT("cannot destroy an untyped Vulkan image\n"); case VulkanImageType::Unknown: EXIT("cannot destroy an untyped Vulkan image\n");
} }
ImageViewOps::DestroyViews(ctx, image); ImageViewOps::DestroyViews(image);
VulkanDeleteImage(ctx, image); graphics.DeleteImage(image);
switch (image->type) { switch (image.type) {
case VulkanImageType::Texture: delete static_cast<TextureVulkanImage*>(image); break; case VulkanImageType::Texture: delete &static_cast<TextureVulkanImage&>(image); break;
case VulkanImageType::StorageTexture: case VulkanImageType::StorageTexture:
delete static_cast<StorageTextureVulkanImage*>(image); delete &static_cast<StorageTextureVulkanImage&>(image);
break; break;
case VulkanImageType::RenderTexture: case VulkanImageType::RenderTexture:
delete static_cast<RenderTextureVulkanImage*>(image); delete &static_cast<RenderTextureVulkanImage&>(image);
break; break;
case VulkanImageType::DepthStencil: case VulkanImageType::DepthStencil:
delete static_cast<DepthStencilVulkanImage*>(image); delete &static_cast<DepthStencilVulkanImage&>(image);
break; break;
case VulkanImageType::VideoOut: delete static_cast<VideoOutVulkanImage*>(image); break; case VulkanImageType::VideoOut: delete &static_cast<VideoOutVulkanImage&>(image); break;
case VulkanImageType::Unknown: EXIT("cannot delete an untyped Vulkan image\n"); case VulkanImageType::Unknown: EXIT("cannot delete an untyped Vulkan image\n");
} }
} }
+14 -13
View File
@@ -100,33 +100,34 @@ private:
namespace ImageOps { namespace ImageOps {
[[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, [[nodiscard]] GpuTextureVulkanImage* CreateTexture(const ImageInfo& info,
bool storage, vk::ComponentMapping* components); bool storage, vk::ComponentMapping& components);
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, void CreateTextureViews(GpuTextureVulkanImage& image,
bool storage, vk::ComponentMapping components); const ImageInfo& info, bool storage, vk::ComponentMapping components);
[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, [[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(
const RenderTargetInfo& info); const RenderTargetInfo& info);
[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element); [[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, const RenderTargetInfo& info, uint32_t base_layer,
uint32_t layer_count, bool refresh); uint32_t layer_count, bool refresh);
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image, void UploadRenderTarget(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, bool refresh); const RenderTargetInfo& info, bool refresh);
[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, [[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(
const DepthTargetInfo& info); const DepthTargetInfo& info);
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info); void ValidateVideoOut(const VideoOutInfo& info);
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info); [[nodiscard]] VideoOutVulkanImage* CreateVideoOut(
const VideoOutInfo& info);
void SwapVideoOutBgra16(void* data, uint64_t size); 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); bool refresh);
[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, [[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(bool uint_format,
bool image_3d, bool storage); bool image_3d, bool storage);
void Destroy(GraphicContext* ctx, VulkanImage* image); void Destroy(VulkanImage& image);
} // namespace ImageOps } // namespace ImageOps
+59 -80
View File
@@ -316,13 +316,10 @@ inline constexpr std::array<VideoOutFormatPolicy, 6> VIDEO_OUT_FORMAT_POLICIES {
}}; }};
[[nodiscard]] inline bool DecodeVideoOutPixelFormat(uint64_t pixel_format, [[nodiscard]] inline bool DecodeVideoOutPixelFormat(uint64_t pixel_format,
VideoOutPixelFormatInfo* info) { VideoOutPixelFormatInfo& info) {
if (info == nullptr) {
return false;
}
for (const auto& policy: VIDEO_OUT_FORMAT_POLICIES) { for (const auto& policy: VIDEO_OUT_FORMAT_POLICIES) {
if (policy.pixel_format == pixel_format) { if (policy.pixel_format == pixel_format) {
*info = policy.info; info = policy.info;
return true; return true;
} }
} }
@@ -388,9 +385,8 @@ enum class BufferImageWrite : uint8_t {
[[nodiscard]] inline constexpr bool [[nodiscard]] inline constexpr bool
HasGuestCurrentImageOwnership(bool image_gpu_modified, bool buffer_modified, bool cpu_dirty, HasGuestCurrentImageOwnership(bool image_gpu_modified, bool buffer_modified, bool cpu_dirty,
bool tracker_gpu_modified, bool same_context) noexcept { bool tracker_gpu_modified) noexcept {
return !image_gpu_modified && !buffer_modified && !cpu_dirty && !tracker_gpu_modified && return !image_gpu_modified && !buffer_modified && !cpu_dirty && !tracker_gpu_modified;
same_context;
} }
enum class StorageBufferRebind : uint8_t { Reuse, RefreshFromBacking, Unsupported }; 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( [[nodiscard]] inline constexpr bool CanRetireGuestCurrentDepthForMetadataReuse(
bool depth_gpu_modified, bool depth_buffer_modified, bool depth_tracker_gpu_modified, 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 metadata_gpu_modified, bool metadata_tracker_gpu_modified,
bool same_context) noexcept { uint32_t metadata_clear_mask) noexcept {
return !metadata_gpu_modified && !metadata_tracker_gpu_modified && metadata_clear_mask == 0 && return !metadata_gpu_modified && !metadata_tracker_gpu_modified && metadata_clear_mask == 0 &&
HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false, 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, [[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, [[nodiscard]] inline MetaImageOverlap ClassifyMetaImageOverlap(bool sampled, bool writable_image,
bool gpu_modified, bool gpu_modified,
bool buffer_modified, bool cpu_dirty, bool buffer_modified,
bool same_context) { bool cpu_dirty) {
if (sampled && !gpu_modified) { if (sampled && !gpu_modified) {
return MetaImageOverlap::RetainSampled; 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::RetireImage;
} }
return MetaImageOverlap::Unsupported; 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, [[nodiscard]] inline bool DecodePackedColorClear(vk::Format format, uint32_t packed,
vk::ClearColorValue* clear) { vk::ClearColorValue& clear) {
if (clear == nullptr) {
return false;
}
vk::ClearColorValue next {}; vk::ClearColorValue next {};
const auto unorm8 = [](uint32_t value) { return static_cast<float>(value & 0xffu) / 255.0f; }; const auto unorm8 = [](uint32_t value) { return static_cast<float>(value & 0xffu) / 255.0f; };
switch (format) { switch (format) {
@@ -555,32 +548,28 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
break; break;
default: return false; default: return false;
} }
*clear = next; clear = next;
return true; return true;
} }
[[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t* clear) { [[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t& clear) {
if (clear == nullptr) {
return false;
}
const auto value = static_cast<uint8_t>(packed); const auto value = static_cast<uint8_t>(packed);
if (packed != static_cast<uint32_t>(value) * 0x01010101u) { if (packed != static_cast<uint32_t>(value) * 0x01010101u) {
return false; return false;
} }
*clear = value; clear = value;
return true; return true;
} }
[[nodiscard]] inline bool DecodePackedDepthClear(vk::Format format, uint32_t packed, float* clear) { [[nodiscard]] inline bool DecodePackedDepthClear(vk::Format format, uint32_t packed, float& clear) {
if (clear == nullptr || if (format != vk::Format::eD32Sfloat && format != vk::Format::eD32SfloatS8Uint) {
(format != vk::Format::eD32Sfloat && format != vk::Format::eD32SfloatS8Uint)) {
return false; return false;
} }
const auto value = std::bit_cast<float>(packed); const auto value = std::bit_cast<float>(packed);
if (!std::isfinite(value) || value < 0.0f || value > 1.0f) { if (!std::isfinite(value) || value < 0.0f || value > 1.0f) {
return false; return false;
} }
*clear = value; clear = value;
return true; return true;
} }
@@ -643,13 +632,11 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
[[nodiscard]] inline SampledOverlap ClassifySampledOverlap(const ImageInfo& requested, [[nodiscard]] inline SampledOverlap ClassifySampledOverlap(const ImageInfo& requested,
const ImageInfo& cached, const ImageInfo& cached,
bool cached_gpu_modified, bool cached_gpu_modified) {
bool same_context) {
if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) { if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) {
return SampledOverlap::None; return SampledOverlap::None;
} }
return !cached_gpu_modified && same_context ? SampledOverlap::ReadOnlyAlias return !cached_gpu_modified ? SampledOverlap::ReadOnlyAlias : SampledOverlap::Unsupported;
: SampledOverlap::Unsupported;
} }
[[nodiscard]] inline bool IsRgba8SrgbReinterpretation(vk::Format cached, [[nodiscard]] inline bool IsRgba8SrgbReinterpretation(vk::Format cached,
@@ -702,7 +689,7 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
[[nodiscard]] inline StorageSampledOverlap ClassifyStorageSampledOverlap( [[nodiscard]] inline StorageSampledOverlap ClassifyStorageSampledOverlap(
const ImageInfo& requested, const ImageInfo& cached, vk::Format requested_view_format, const ImageInfo& requested, const ImageInfo& cached, vk::Format requested_view_format,
vk::Format cached_image_format, bool cached_gpu_modified, bool cached_cpu_dirty, 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) { bool tracker_gpu_modified = true) {
if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) { if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) {
return StorageSampledOverlap::None; 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) || (requested.format == cached.format && requested_view_format == cached_image_format) ||
IsRgba8SrgbReinterpretation(cached_image_format, requested_view_format) || IsRgba8SrgbReinterpretation(cached_image_format, requested_view_format) ||
IsR32UintFloatReinterpretation(cached_image_format, requested_view_format); IsR32UintFloatReinterpretation(cached_image_format, requested_view_format);
if (same_backing && compatible_format && cached_gpu_modified && !cached_cpu_dirty && if (same_backing && compatible_format && cached_gpu_modified && !cached_cpu_dirty) {
same_context) {
return StorageSampledOverlap::ExactImage; return StorageSampledOverlap::ExactImage;
} }
if (exact_mip_subresource && cached_gpu_modified && tracker_gpu_modified && 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::RetireStorage;
} }
return StorageSampledOverlap::Unsupported; return StorageSampledOverlap::Unsupported;
@@ -866,8 +852,7 @@ ClassifyStorageBufferRebind(bool buffer_overlap, bool cached_gpu_modified,
[[nodiscard]] inline DepthOverlap [[nodiscard]] inline DepthOverlap
ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified, ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
bool storage_buffer_modified, bool storage_cpu_dirty, bool storage_buffer_modified, bool storage_cpu_dirty,
bool tracker_gpu_modified, bool same_context, bool tracker_gpu_modified, const DepthTargetInfo& depth) {
const DepthTargetInfo& depth) {
const bool overlaps_depth = const bool overlaps_depth =
ImageRangeOverlaps(storage.address, storage.size, depth.address, depth.size); ImageRangeOverlaps(storage.address, storage.size, depth.address, depth.size);
const bool overlaps_stencil = const bool overlaps_stencil =
@@ -876,21 +861,20 @@ ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
if (!overlaps_depth && !overlaps_stencil) { if (!overlaps_depth && !overlaps_stencil) {
return DepthOverlap::None; return DepthOverlap::None;
} }
const bool guest_current = const bool guest_current = HasGuestCurrentImageOwnership(
HasGuestCurrentImageOwnership(storage_gpu_modified, storage_buffer_modified, storage_gpu_modified, storage_buffer_modified, storage_cpu_dirty, tracker_gpu_modified);
storage_cpu_dirty, tracker_gpu_modified, same_context);
const bool aspects_discarded = const bool aspects_discarded =
(!overlaps_depth || !depth.depth_access) && (!overlaps_stencil || !depth.stencil_access); (!overlaps_depth || !depth.depth_access) && (!overlaps_stencil || !depth.stencil_access);
return guest_current || (!storage_buffer_modified && !storage_cpu_dirty && same_context && return guest_current || (!storage_buffer_modified && !storage_cpu_dirty && aspects_discarded)
aspects_discarded)
? DepthOverlap::RetireStorage ? DepthOverlap::RetireStorage
: DepthOverlap::Unsupported; : DepthOverlap::Unsupported;
} }
[[nodiscard]] inline bool CanRetireGuestCurrentDepthForSampled( [[nodiscard]] inline bool
const ImageInfo& sampled, const DepthTargetInfo& depth, bool depth_gpu_modified, CanRetireGuestCurrentDepthForSampled(const ImageInfo& sampled, const DepthTargetInfo& depth,
bool depth_buffer_modified, bool depth_tracker_gpu_modified, bool stencil_tracker_gpu_modified, bool depth_gpu_modified, bool depth_buffer_modified,
bool same_context) noexcept { bool depth_tracker_gpu_modified,
bool stencil_tracker_gpu_modified) noexcept {
const bool overlaps_depth = const bool overlaps_depth =
ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size); ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size);
const bool overlaps_stencil = const bool overlaps_stencil =
@@ -898,15 +882,15 @@ ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
depth.stencil_address, depth.stencil_size); depth.stencil_address, depth.stencil_size);
return (overlaps_depth || overlaps_stencil) && return (overlaps_depth || overlaps_stencil) &&
HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false, HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false,
depth_tracker_gpu_modified || stencil_tracker_gpu_modified, depth_tracker_gpu_modified ||
same_context); stencil_tracker_gpu_modified);
} }
[[nodiscard]] inline bool [[nodiscard]] inline bool
CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTargetInfo& depth, CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTargetInfo& depth,
bool sampled_gpu_modified, bool sampled_buffer_modified, bool sampled_gpu_modified, bool sampled_buffer_modified,
bool sampled_cpu_dirty, bool tracker_gpu_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 = const bool overlaps_depth =
ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size); ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size);
const bool overlaps_stencil = const bool overlaps_stencil =
@@ -914,11 +898,11 @@ CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTarget
depth.stencil_address, depth.stencil_size); depth.stencil_address, depth.stencil_size);
return (overlaps_depth || overlaps_stencil) && guest_source_current && return (overlaps_depth || overlaps_stencil) && guest_source_current &&
HasGuestCurrentImageOwnership(sampled_gpu_modified, sampled_buffer_modified, HasGuestCurrentImageOwnership(sampled_gpu_modified, sampled_buffer_modified,
sampled_cpu_dirty, tracker_gpu_modified, same_context); sampled_cpu_dirty, tracker_gpu_modified);
} }
[[nodiscard]] inline RenderTargetOverlap [[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) { const RenderTargetInfo& target) {
if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) { if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None; return RenderTargetOverlap::None;
@@ -926,7 +910,7 @@ ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified,
if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) { if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None; return RenderTargetOverlap::None;
} }
return !sampled_gpu_modified && same_context ? RenderTargetOverlap::RetireSampled return !sampled_gpu_modified ? RenderTargetOverlap::RetireSampled
: RenderTargetOverlap::Unsupported; : RenderTargetOverlap::Unsupported;
} }
@@ -934,7 +918,7 @@ ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified,
ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_format, ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_format,
bool storage_gpu_modified, bool storage_buffer_modified, bool storage_gpu_modified, bool storage_buffer_modified,
bool storage_cpu_dirty, bool tracker_gpu_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)) { if (!ImagePageRangesOverlap(storage.address, storage.size, target.address, target.size)) {
return RenderTargetOverlap::None; return RenderTargetOverlap::None;
} }
@@ -950,11 +934,11 @@ ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_
storage.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && storage.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
storage.base_array == 0 && target.levels == 1 && target.layers == 1 && target.samples == 1; storage.base_array == 0 && target.levels == 1 && target.layers == 1 && target.samples == 1;
if (exact_native_image && storage_gpu_modified && tracker_gpu_modified && 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 RenderTargetOverlap::PreserveStorage;
} }
return HasGuestCurrentImageOwnership(storage_gpu_modified, storage_buffer_modified, 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::RetireStorage
: RenderTargetOverlap::Unsupported; : RenderTargetOverlap::Unsupported;
} }
@@ -988,29 +972,28 @@ ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_
[[nodiscard]] inline RenderTargetOverlap [[nodiscard]] inline RenderTargetOverlap
ClassifySampledRenderTargetOverlap(const ImageInfo& sampled, const RenderTargetInfo& target, 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)) { if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None; return RenderTargetOverlap::None;
} }
if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) { if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None; return RenderTargetOverlap::None;
} }
return same_context && !target_buffer_modified ? RenderTargetOverlap::RetireTarget return !target_buffer_modified ? RenderTargetOverlap::RetireTarget
: RenderTargetOverlap::Unsupported; : RenderTargetOverlap::Unsupported;
} }
[[nodiscard]] inline StorageImageOverlap [[nodiscard]] inline StorageImageOverlap
ClassifyStorageImageOverlap(uint64_t requested_address, uint64_t requested_size, ClassifyStorageImageOverlap(uint64_t requested_address, uint64_t requested_size,
uint64_t cached_address, uint64_t cached_size, bool sampled, uint64_t cached_address, uint64_t cached_size, bool sampled,
bool same_context, bool gpu_modified, bool buffer_modified, bool gpu_modified, bool buffer_modified, bool tracker_gpu_modified) {
bool tracker_gpu_modified) {
if (!ImagePageRangesOverlap(requested_address, requested_size, cached_address, cached_size)) { if (!ImagePageRangesOverlap(requested_address, requested_size, cached_address, cached_size)) {
return StorageImageOverlap::None; return StorageImageOverlap::None;
} }
if (!ImageRangeOverlaps(requested_address, requested_size, cached_address, cached_size)) { if (!ImageRangeOverlaps(requested_address, requested_size, cached_address, cached_size)) {
return StorageImageOverlap::PageNeighbor; 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::RetireSampled
: StorageImageOverlap::Unsupported; : StorageImageOverlap::Unsupported;
} }
@@ -1068,8 +1051,7 @@ IsCompatibleDepthTargetBacking(const DepthTargetInfo& cached,
[[nodiscard]] inline RenderTargetOverlap [[nodiscard]] inline RenderTargetOverlap
ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modified, ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modified,
bool cached_buffer_modified, bool tracker_gpu_modified, bool cached_buffer_modified, bool tracker_gpu_modified,
bool same_context, bool guest_source_current, bool guest_source_current, const RenderTargetInfo& requested) {
const RenderTargetInfo& requested) {
if (!ImagePageRangesOverlap(cached.address, cached.size, requested.address, requested.size)) { if (!ImagePageRangesOverlap(cached.address, cached.size, requested.address, requested.size)) {
return RenderTargetOverlap::None; return RenderTargetOverlap::None;
} }
@@ -1079,8 +1061,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
const bool expand = requested.layers > cached.layers && const bool expand = requested.layers > cached.layers &&
IsCompatibleRenderTargetBacking(requested, cached) && IsCompatibleRenderTargetBacking(requested, cached) &&
cached.format == requested.format; cached.format == requested.format;
if (expand && cached_gpu_modified && tracker_gpu_modified && !cached_buffer_modified && if (expand && cached_gpu_modified && tracker_gpu_modified && !cached_buffer_modified) {
same_context) {
return RenderTargetOverlap::ExpandTarget; return RenderTargetOverlap::ExpandTarget;
} }
// A clean, page-isolated overlap is allocation-pool reuse, including a contained subrange. // 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; cached.size != requested.size || pool_storage_shape_changed;
return page_isolated && new_allocation && guest_source_current && return page_isolated && new_allocation && guest_source_current &&
HasGuestCurrentImageOwnership(cached_gpu_modified, cached_buffer_modified, false, HasGuestCurrentImageOwnership(cached_gpu_modified, cached_buffer_modified, false,
tracker_gpu_modified, same_context) tracker_gpu_modified)
? RenderTargetOverlap::RetireTarget ? RenderTargetOverlap::RetireTarget
: RenderTargetOverlap::Unsupported; : RenderTargetOverlap::Unsupported;
} }
@@ -1108,7 +1089,6 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
[[nodiscard]] inline DepthOverlap ClassifyDepthTargetOverlap(const DepthTargetInfo& cached, [[nodiscard]] inline DepthOverlap ClassifyDepthTargetOverlap(const DepthTargetInfo& cached,
bool cached_gpu_modified, bool cached_gpu_modified,
bool cached_buffer_modified, bool cached_buffer_modified,
bool same_context,
const DepthTargetInfo& requested) { const DepthTargetInfo& requested) {
const auto overlaps = [](uint64_t left, uint64_t left_size, uint64_t right, uint64_t right_size, const auto overlaps = [](uint64_t left, uint64_t left_size, uint64_t right, uint64_t right_size,
bool pages) { bool pages) {
@@ -1132,12 +1112,12 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
} }
const bool expand = const bool expand =
requested.layers > cached.layers && IsCompatibleDepthTargetBacking(requested, cached); 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; return DepthOverlap::ExpandTarget;
} }
const bool exact_discard = const bool exact_discard =
requested.depth_load_clear && cached_gpu_modified && !cached_buffer_modified && 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.samples == requested.samples && cached.stencil_address == 0 &&
cached.stencil_size == 0 && cached.htile_address == 0 && cached.htile_size == 0 && cached.stencil_size == 0 && cached.htile_address == 0 && cached.htile_size == 0 &&
requested.stencil_address == 0 && requested.stencil_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.bytes_per_element == requested.bytes_per_element &&
cached.tile_mode == requested.tile_mode && cached.layers == 1 && cached.tile_mode == requested.tile_mode && cached.layers == 1 &&
requested.layers == 1 && cached.samples == 1 && requested.samples == 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::RecreateTarget
: DepthOverlap::Unsupported; : DepthOverlap::Unsupported;
} }
@@ -1166,7 +1146,6 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
[[nodiscard]] inline bool CanRecreateDepthForRenderTarget(const DepthTargetInfo& depth, [[nodiscard]] inline bool CanRecreateDepthForRenderTarget(const DepthTargetInfo& depth,
bool gpu_modified, bool buffer_modified, bool gpu_modified, bool buffer_modified,
bool tracker_gpu_modified, bool tracker_gpu_modified,
bool same_context,
bool guest_source_current, bool guest_source_current,
const RenderTargetInfo& target) noexcept { const RenderTargetInfo& target) noexcept {
const bool exact_depth = depth.address == target.address && depth.size == target.size; 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 ownership_consistent = gpu_modified == tracker_gpu_modified && !buffer_modified;
const bool source_available = const bool source_available =
((exact_depth || exact_stencil) && gpu_modified) || guest_source_current; ((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 && (exact_depth || exact_stencil || page_isolated_rebind) && depth.layers == 1 &&
target.levels == 1 && target.layers == 1 && depth.samples == 1 && target.samples == 1; target.levels == 1 && target.layers == 1 && depth.samples == 1 && target.samples == 1;
} }
[[nodiscard]] inline bool [[nodiscard]] inline bool CanRecreateRenderTargetForDepth(const RenderTargetInfo& target,
CanRecreateRenderTargetForDepth(const RenderTargetInfo& target, bool gpu_modified, bool gpu_modified, bool buffer_modified,
bool buffer_modified, bool tracker_gpu_modified, bool same_context, bool tracker_gpu_modified,
bool guest_source_current, const DepthTargetInfo& depth) noexcept { bool guest_source_current,
const DepthTargetInfo& depth) noexcept {
const bool exact_depth = target.address == depth.address && target.size == depth.size; const bool exact_depth = target.address == depth.address && target.size == depth.size;
const bool exact_stencil = const bool exact_stencil =
target.address == depth.stencil_address && target.size == depth.stencil_size; 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)); depth.stencil_size % TRACKER_PAGE_SIZE == 0));
const bool source_available = const bool source_available =
(gpu_modified && (exact_depth || exact_stencil)) || guest_source_current; (gpu_modified && (exact_depth || exact_stencil)) || guest_source_current;
return gpu_modified == tracker_gpu_modified && !buffer_modified && same_context && return gpu_modified == tracker_gpu_modified && !buffer_modified && source_available &&
source_available && (exact_depth || exact_stencil || page_isolated_rebind) && (exact_depth || exact_stencil || page_isolated_rebind) && target.levels == 1 &&
target.levels == 1 && target.layers == 1 && depth.layers == 1 && target.samples == 1 && target.layers == 1 && depth.layers == 1 && target.samples == 1 && depth.samples == 1;
depth.samples == 1;
} }
[[nodiscard]] inline bool RequiresMultisampleDepthRefresh(const DepthTargetInfo& info, [[nodiscard]] inline bool RequiresMultisampleDepthRefresh(const DepthTargetInfo& info,
+123 -154
View File
@@ -2,6 +2,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "graphics/host_gpu/objects/textureCommon.h" #include "graphics/host_gpu/objects/textureCommon.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/textureCache.h" #include "graphics/host_gpu/renderer/textureCache.h"
#include <mutex> #include <mutex>
@@ -10,19 +11,19 @@ namespace Libs::Graphics {
namespace { 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::ImageViewType view_type, vk::ImageAspectFlags aspect_mask,
vk::ComponentMapping components, uint32_t base_array_layer, uint32_t base_mip_level, vk::ComponentMapping components, uint32_t base_array_layer, uint32_t base_mip_level,
uint32_t layer_count, uint32_t level_count, uint32_t layer_count, uint32_t level_count,
vk::Format view_format = vk::Format::eUndefined, vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {}) { vk::ImageUsageFlags view_usage = {}) {
if (ctx == nullptr || image == nullptr || view_index < 0 || auto& graphics = GetRenderContext().GetGraphics();
view_index >= VulkanImage::VIEW_MAX || image->image == nullptr || if (view_index < 0 || view_index >= VulkanImage::VIEW_MAX ||
image->image_view[view_index] != nullptr) { image.image_view[view_index] != nullptr) {
EXIT("invalid image-view creation target: image=%p index=%d current_view=%d\n", EXIT("invalid image-view creation target: image=%p index=%d current_view=%d\n",
static_cast<const void*>(image), view_index, static_cast<const void*>(&image), view_index,
image != nullptr && view_index >= 0 && view_index < VulkanImage::VIEW_MAX && view_index >= 0 && view_index < VulkanImage::VIEW_MAX &&
image->image_view[view_index] != nullptr); image.image_view[view_index] != nullptr);
} }
vk::ImageViewUsageCreateInfo usage_info {}; vk::ImageViewUsageCreateInfo usage_info {};
@@ -32,9 +33,9 @@ void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index,
vk::ImageViewCreateInfo create_info {}; vk::ImageViewCreateInfo create_info {};
create_info.sType = vk::StructureType::eImageViewCreateInfo; create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = view_usage ? &usage_info : nullptr; 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.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.components = components;
create_info.subresourceRange.aspectMask = aspect_mask; create_info.subresourceRange.aspectMask = aspect_mask;
create_info.subresourceRange.baseArrayLayer = base_array_layer; 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; create_info.subresourceRange.levelCount = level_count;
const auto result = const auto result =
ctx->device.createImageView(&create_info, nullptr, &image->image_view[view_index]); graphics.device.createImageView(&create_info, nullptr, &image.image_view[view_index]);
if (result != vk::Result::eSuccess || image->image_view[view_index] == nullptr) { 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", EXIT("failed to create image view: result=%d image_format=%d view_format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(image->format), static_cast<int>(result), static_cast<int>(image.format),
static_cast<int>(create_info.format), view_index); static_cast<int>(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 r, vk::ComponentSwizzle g, vk::ComponentSwizzle b,
vk::ComponentSwizzle a, vk::ImageViewType type = vk::ImageViewType::e2D, vk::ComponentSwizzle a, vk::ImageViewType type = vk::ImageViewType::e2D,
vk::Format view_format = vk::Format::eUndefined, vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {}, uint32_t level_count = 0) { vk::ImageUsageFlags view_usage = {}, uint32_t level_count = 0) {
const auto layer_count = type == vk::ImageViewType::e2DArray ? image->layers : 1u; 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, 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, layer_count, level_count == 0 ? image.mip_levels : level_count, view_format,
view_usage); view_usage);
} }
@@ -78,30 +79,31 @@ vk::ImageAspectFlags DepthAspectMask(vk::Format format) {
} }
} }
bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format) { bool FormatSupportsStorage(vk::Format format) {
const auto properties = ctx->GetFormatProperties(format); auto& graphics = GetRenderContext().GetGraphics();
const auto properties = graphics.GetFormatProperties(format);
return static_cast<bool>(properties.optimalTilingFeatures & return static_cast<bool>(properties.optimalTilingFeatures &
vk::FormatFeatureFlagBits::eStorageImage); vk::FormatFeatureFlagBits::eStorageImage);
} }
void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image) { void CreateRenderTargetViews(RenderTextureVulkanImage& image) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity, CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity); vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity);
if (image->layers > 1) { if (image.layers > 1) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY, CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT_ARRAY,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2DArray); vk::ImageViewType::e2DArray);
} }
if (image->samples == 1 && FormatSupportsStorage(ctx, image->format)) { if (image.samples == 1 && FormatSupportsStorage(image.format)) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE, CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2D, vk::Format::eUndefined, vk::ImageViewType::e2D, vk::Format::eUndefined,
vk::ImageUsageFlags {}, 1); vk::ImageUsageFlags {}, 1);
if (image->layers > 1) { if (image.layers > 1) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE_ARRAY, CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE_ARRAY,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2DArray, vk::Format::eUndefined, vk::ImageViewType::e2DArray, vk::Format::eUndefined,
@@ -110,22 +112,21 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag
} }
} }
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) { void CreateDepthViews(DepthStencilVulkanImage& image) {
CreateView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D, CreateView(image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D,
DepthAspectMask(image->format), DepthAspectMask(image.format),
{vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, {vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity}, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity},
0, 0, 1, 1); 0, 0, 1, 1);
} }
void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) { void CreateVideoOutViews(VideoOutVulkanImage& image) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity, CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity); vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity);
if ((image->format == vk::Format::eR8G8B8A8Srgb || if ((image.format == vk::Format::eR8G8B8A8Srgb || image.format == vk::Format::eB8G8R8A8Srgb) &&
image->format == vk::Format::eB8G8R8A8Srgb) && FormatSupportsStorage(vk::Format::eR8G8B8A8Uint)) {
FormatSupportsStorage(ctx, vk::Format::eR8G8B8A8Uint)) { CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE,
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2D, vk::Format::eR8G8B8A8Uint, vk::ImageViewType::e2D, vk::Format::eR8G8B8A8Uint,
@@ -133,20 +134,18 @@ void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) {
} }
} }
void DestroyViews(GraphicContext* ctx, VulkanImage* image) { void DestroyViews(VulkanImage& image) {
EXIT_IF(ctx == nullptr); auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(image == nullptr); for (auto& cached: image.view_cache.views) {
for (auto& cached: image->view_cache.views) {
if (cached.view != nullptr) { if (cached.view != nullptr) {
ctx->device.destroyImageView(cached.view, nullptr); graphics.device.destroyImageView(cached.view, nullptr);
cached.view = nullptr; cached.view = nullptr;
} }
} }
image->view_cache.views.clear(); image.view_cache.views.clear();
for (auto& view: image->image_view) { for (auto& view: image.image_view) {
if (view != nullptr) { if (view != nullptr) {
ctx->device.destroyImageView(view, nullptr); graphics.device.destroyImageView(view, nullptr);
view = nullptr; view = nullptr;
} }
} }
@@ -154,54 +153,45 @@ void DestroyViews(GraphicContext* ctx, VulkanImage* image) {
} // namespace ImageViewOps } // namespace ImageViewOps
vk::ImageView TextureCache::GetRenderTargetAttachmentView(GraphicContext* ctx, vk::ImageView TextureCache::GetRenderTargetAttachmentView(RenderTextureVulkanImage& image,
RenderTextureVulkanImage* image,
vk::Format format, uint32_t level, vk::Format format, uint32_t level,
uint32_t base_layer, uint32_t base_layer,
uint32_t layer_count) { uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr || if (image.format == vk::Format::eUndefined || level >= image.mip_levels || level >= 16 ||
format == vk::Format::eUndefined || level >= image->mip_levels || level >= 16 || layer_count == 0 || base_layer >= image.layers || layer_count > image.layers - base_layer) {
layer_count == 0 || base_layer >= image->layers ||
layer_count > image->layers - base_layer) {
EXIT("TextureCache: invalid render-target attachment view, image=%p format=%d" 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", " level=%u image_levels=%u base_layer=%u layer_count=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(format), level, static_cast<const void*>(&image), static_cast<int>(format), level, image.mip_levels,
image != nullptr ? image->mip_levels : 0, base_layer, layer_count, base_layer, layer_count, image.layers);
image != nullptr ? image->layers : 0);
} }
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" EXIT("TextureCache: incompatible render-target attachment view, image_format=%d"
" view_format=%d level=%u\n", " view_format=%d level=%u\n",
static_cast<int>(image->format), static_cast<int>(format), level); static_cast<int>(image.format), static_cast<int>(format), level);
} }
return GetImageView(ctx, image, return GetImageView(
{format, image, {format, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
vk::ImageAspectFlagBits::eColor, level, 1, base_layer, layer_count, vk::ImageAspectFlagBits::eColor, level, 1, base_layer, layer_count,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eColorAttachment}); DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eColorAttachment});
} }
vk::ImageView TextureCache::GetDepthTargetAttachmentView(GraphicContext* ctx, vk::ImageView TextureCache::GetDepthTargetAttachmentView(DepthStencilVulkanImage& image,
DepthStencilVulkanImage* image,
uint32_t base_layer, uint32_t base_layer,
uint32_t layer_count) { uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr || layer_count == 0 || if (layer_count == 0 || base_layer >= image.layers || layer_count > image.layers - base_layer) {
base_layer >= image->layers || layer_count > image->layers - base_layer) {
EXIT("TextureCache: invalid depth-target attachment view, image=%p base_layer=%u " EXIT("TextureCache: invalid depth-target attachment view, image=%p base_layer=%u "
"layer_count=%u image_layers=%u\n", "layer_count=%u image_layers=%u\n",
static_cast<const void*>(image), base_layer, layer_count, static_cast<const void*>(&image), base_layer, layer_count, image.layers);
image != nullptr ? image->layers : 0);
} }
return GetImageView( return GetImageView(image,
ctx, image, {image.format,
{image->format, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
ImageViewOps::DepthAspectMask(image->format), 0, 1, base_layer, layer_count, ImageViewOps::DepthAspectMask(image.format), 0, 1, base_layer, layer_count,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eDepthStencilAttachment}); DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eDepthStencilAttachment});
} }
vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image, vk::ImageView TextureCache::GetImageView(VulkanImage& image, const ImageViewInfo& info) {
const ImageViewInfo& info) {
const bool supported_type = info.type == vk::ImageViewType::e2D || const bool supported_type = info.type == vk::ImageViewType::e2D ||
info.type == vk::ImageViewType::e2DArray || info.type == vk::ImageViewType::e2DArray ||
info.type == vk::ImageViewType::e3D; 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::e2D && info.layer_count == 1) ||
info.type == vk::ImageViewType::e2DArray || info.type == vk::ImageViewType::e2DArray ||
(info.type == vk::ImageViewType::e3D && info.base_layer == 0 && info.layer_count == 1); (info.type == vk::ImageViewType::e3D && info.base_layer == 0 && info.layer_count == 1);
if (ctx == nullptr || image == nullptr || image->image == nullptr || if (info.format == vk::Format::eUndefined || !info.aspect || info.level_count == 0 ||
info.format == vk::Format::eUndefined || !info.aspect || info.level_count == 0 || info.base_level >= (image.mip_levels) ||
info.base_level >= (image != nullptr ? image->mip_levels : 0) || info.level_count > image.mip_levels - info.base_level || info.layer_count == 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 ||
info.base_layer >= image->layers || info.layer_count > image->layers - info.base_layer ||
!supported_type || !valid_shape || !supported_usage) { !supported_type || !valid_shape || !supported_usage) {
EXIT("TextureCache: invalid dynamic image view, image=%p format=%d aspect=0x%x" 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" " swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d usage=0x%x"
" image_levels=%u image_layers=%u\n", " image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(info.format), static_cast<const void*>(&image), static_cast<int>(info.format),
static_cast<vk::ImageAspectFlags::MaskType>(info.aspect), info.swizzle, static_cast<vk::ImageAspectFlags::MaskType>(info.aspect), info.swizzle,
info.base_level, info.level_count, info.base_layer, info.layer_count, info.base_level, info.level_count, info.base_layer, info.layer_count,
static_cast<int>(info.type), static_cast<vk::ImageUsageFlags::MaskType>(info.usage), static_cast<int>(info.type), static_cast<vk::ImageUsageFlags::MaskType>(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); std::lock_guard lock(cache.mutex);
for (const auto& cached: cache.views) { for (const auto& cached: cache.views) {
if (cached.info == info) { if (cached.info == info) {
@@ -243,7 +232,7 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
vk::ImageViewCreateInfo create {}; vk::ImageViewCreateInfo create {};
create.sType = vk::StructureType::eImageViewCreateInfo; create.sType = vk::StructureType::eImageViewCreateInfo;
create.pNext = &usage; create.pNext = &usage;
create.image = image->image; create.image = image.image;
create.viewType = info.type; create.viewType = info.type;
create.format = info.format; create.format = info.format;
create.components = info.usage == vk::ImageUsageFlagBits::eSampled 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.baseArrayLayer = info.base_layer;
create.subresourceRange.layerCount = info.layer_count; create.subresourceRange.layerCount = info.layer_count;
vk::ImageView view = nullptr; 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) { if (result != vk::Result::eSuccess || view == nullptr) {
EXIT("TextureCache: failed to create dynamic image view, result=%d format=%d" 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", " 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; return view;
} }
vk::ImageView TextureCache::GetDepthTargetSampledView(GraphicContext* ctx, vk::ImageView TextureCache::GetDepthTargetSampledView(DepthStencilVulkanImage& image,
DepthStencilVulkanImage* image,
vk::Format view_format, uint32_t swizzle, vk::Format view_format, uint32_t swizzle,
uint32_t base_level, uint32_t level_count, uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer, vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count) { uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr || if (view_format == vk::Format::eUndefined ||
view_format == vk::Format::eUndefined || !IsSupportedSampledDepthView(image.format, view_format, swizzle)) {
!IsSupportedSampledDepthView(image->format, view_format, swizzle)) {
EXIT("TextureCache: invalid sampled depth-target view, image=%p image_format=%d" 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" " view_format=%d swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d"
" image_levels=%u image_layers=%u\n", " image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<const void*>(&image), static_cast<int>(image.format),
image != nullptr ? static_cast<int>(image->format)
: static_cast<int>(vk::Format::eUndefined),
static_cast<int>(view_format), swizzle, base_level, level_count, base_layer, static_cast<int>(view_format), swizzle, base_level, level_count, base_layer,
layer_count, static_cast<int>(type), image != nullptr ? image->mip_levels : 0, layer_count, static_cast<int>(type), image.mip_levels, image.layers);
image != nullptr ? image->layers : 0);
} }
return GetImageView(ctx, image, return GetImageView(image, {image.format, type, vk::ImageAspectFlagBits::eDepth, base_level,
{image->format, type, vk::ImageAspectFlagBits::eDepth, base_level,
level_count, base_layer, layer_count, swizzle}); level_count, base_layer, layer_count, swizzle});
} }
vk::ImageView TextureCache::GetSampledColorView(GraphicContext* ctx, VulkanImage* image, vk::ImageView TextureCache::GetSampledColorView(VulkanImage& image, vk::Format view_format,
vk::Format view_format, uint32_t swizzle, uint32_t swizzle, uint32_t base_level,
uint32_t base_level, uint32_t level_count, uint32_t level_count, vk::ImageViewType type,
vk::ImageViewType type, uint32_t base_layer, uint32_t base_layer, uint32_t layer_count) {
uint32_t layer_count) { if (view_format == vk::Format::eUndefined || base_level >= 16 ||
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
view_format == vk::Format::eUndefined || base_level >= 16 ||
(type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray) || (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" 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", " view_format=%d mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), swizzle, static_cast<int>(view_format), base_level, static_cast<const void*>(&image), swizzle, static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type), level_count, base_layer, layer_count, static_cast<int>(type), image.mip_levels,
image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0); image.layers);
} }
const auto precreated_view = type == vk::ImageViewType::e2DArray const auto precreated_view = type == vk::ImageViewType::e2DArray
? VulkanImage::VIEW_DEFAULT_ARRAY ? VulkanImage::VIEW_DEFAULT_ARRAY
: VulkanImage::VIEW_DEFAULT; : VulkanImage::VIEW_DEFAULT;
const bool full_view = const bool full_view = base_level == 0 && level_count == image.mip_levels && base_layer == 0 &&
base_level == 0 && level_count == image->mip_levels && base_layer == 0 && layer_count == (type == vk::ImageViewType::e2DArray ? image.layers : 1u);
layer_count == (type == vk::ImageViewType::e2DArray ? image->layers : 1u); if (view_format == image.format && swizzle == DstSel(4, 5, 6, 7) && full_view &&
if (view_format == image->format && swizzle == DstSel(4, 5, 6, 7) && full_view && image.image_view[precreated_view] != nullptr) {
image->image_view[precreated_view] != nullptr) { return image.image_view[precreated_view];
return image->image_view[precreated_view];
} }
return GetImageView(ctx, image, return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
{view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
level_count, base_layer, layer_count, swizzle}); level_count, base_layer, layer_count, swizzle});
} }
vk::ImageView TextureCache::GetRenderTargetStorageView(GraphicContext* ctx, vk::ImageView TextureCache::GetRenderTargetStorageView(RenderTextureVulkanImage& image,
RenderTextureVulkanImage* image,
vk::Format view_format, uint32_t base_level, vk::Format view_format, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type, uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count) { uint32_t base_layer, uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr || if (view_format == vk::Format::eUndefined ||
view_format == vk::Format::eUndefined ||
(type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray)) { (type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray)) {
EXIT("TextureCache: invalid render-target storage view, image=%p view_format=%d" 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", " mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(view_format), base_level, static_cast<const void*>(&image), static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type), level_count, base_layer, layer_count, static_cast<int>(type), image.mip_levels,
image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0); image.layers);
} }
const bool exact = view_format == image->format; const bool exact = view_format == image.format;
const bool compatible = view_format == BgraSrgbStorageViewFormat(image->format); const bool compatible = view_format == BgraSrgbStorageViewFormat(image.format);
if (!exact && !compatible) { if (!exact && !compatible) {
EXIT("TextureCache: incompatible render-target storage view, image_format=%d" EXIT("TextureCache: incompatible render-target storage view, image_format=%d"
" view_format=%d base=%u count=%u\n", " view_format=%d base=%u count=%u\n",
static_cast<int>(image->format), static_cast<int>(view_format), base_level, static_cast<int>(image.format), static_cast<int>(view_format), base_level,
level_count); level_count);
} }
if (exact) { if (exact) {
@@ -349,44 +326,40 @@ vk::ImageView TextureCache::GetRenderTargetStorageView(GraphicContext*
: VulkanImage::VIEW_STORAGE; : VulkanImage::VIEW_STORAGE;
const bool full_view = const bool full_view =
base_level == 0 && level_count == 1 && base_layer == 0 && base_level == 0 && level_count == 1 && base_layer == 0 &&
layer_count == (type == vk::ImageViewType::e2DArray ? image->layers : 1u); layer_count == (type == vk::ImageViewType::e2DArray ? image.layers : 1u);
if (full_view && image->image_view[index] != nullptr) { if (full_view && image.image_view[index] != nullptr) {
return image->image_view[index]; 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," EXIT("TextureCache: compatible render-target storage format lacks storage support,"
" image_format=%d view_format=%d base=%u count=%u\n", " image_format=%d view_format=%d base=%u count=%u\n",
static_cast<int>(image->format), static_cast<int>(view_format), base_level, static_cast<int>(image.format), static_cast<int>(view_format), base_level,
level_count); level_count);
} }
return GetImageView(ctx, image, return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
{view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
level_count, base_layer, layer_count, DstSel(4, 5, 6, 7), level_count, base_layer, layer_count, DstSel(4, 5, 6, 7),
vk::ImageUsageFlagBits::eStorage}); vk::ImageUsageFlagBits::eStorage});
} }
vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext* ctx, vk::ImageView TextureCache::GetStorageTextureSampledView(StorageTextureVulkanImage& image,
StorageTextureVulkanImage* image,
const ImageInfo& info) { const ImageInfo& info) {
const auto shape = const auto shape = SelectStorageSampledViewShape(info.type, info.depth, image.layers);
SelectStorageSampledViewShape(info.type, info.depth, image != nullptr ? image->layers : 0); if (image.image == nullptr || shape == StorageSampledViewShape::Unsupported ||
if (ctx == nullptr || image == nullptr || image->image == nullptr || info.base_array != 0 || info.levels != image.mip_levels || info.base_level >= info.levels ||
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) { 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" 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", " base=%u levels=%u view_levels=%u image_levels=%u base_array=%u\n",
static_cast<const void*>(image), info.type, info.depth, info.base_level, info.levels, static_cast<const void*>(&image), info.type, info.depth, info.base_level, info.levels,
info.view_levels, image != nullptr ? image->mip_levels : 0, info.base_array); info.view_levels, image.mip_levels, info.base_array);
} }
const auto view_format = TextureGetFormat(info.format); const auto view_format = TextureGetFormat(info.format);
if (view_format != image->format && !IsRgba8SrgbReinterpretation(image->format, view_format) && if (view_format != image.format && !IsRgba8SrgbReinterpretation(image.format, view_format) &&
!IsR32UintFloatReinterpretation(image->format, view_format)) { !IsR32UintFloatReinterpretation(image.format, view_format)) {
EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d" EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d"
" view_format=%d swizzle=0x%03x\n", " view_format=%d swizzle=0x%03x\n",
static_cast<int>(image->format), static_cast<int>(view_format), info.swizzle); static_cast<int>(image.format), static_cast<int>(view_format), info.swizzle);
} }
vk::ImageViewType type = static_cast<vk::ImageViewType>(VK_IMAGE_VIEW_TYPE_MAX_ENUM); vk::ImageViewType type = static_cast<vk::ImageViewType>(VK_IMAGE_VIEW_TYPE_MAX_ENUM);
@@ -398,26 +371,22 @@ vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext*
EXIT("TextureCache: unsupported sampled storage-image view shape\n"); EXIT("TextureCache: unsupported sampled storage-image view shape\n");
} }
const auto layer_count = shape == StorageSampledViewShape::Image2DArray ? info.depth : 1u; const auto layer_count = shape == StorageSampledViewShape::Image2DArray ? info.depth : 1u;
return GetImageView(ctx, image, return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, info.base_level,
{view_format, type, vk::ImageAspectFlagBits::eColor, info.base_level,
info.view_levels, 0, layer_count, info.swizzle}); info.view_levels, 0, layer_count, info.swizzle});
} }
vk::ImageView TextureCache::GetStorageTextureStorageView(GraphicContext* ctx, vk::ImageView TextureCache::GetStorageTextureStorageView(StorageTextureVulkanImage& image,
StorageTextureVulkanImage* image,
uint32_t base_level) { uint32_t base_level) {
if (ctx == nullptr || image == nullptr || image->image == nullptr || if (image.image == nullptr || base_level >= (image.mip_levels)) {
base_level >= (image != nullptr ? image->mip_levels : 0)) {
EXIT("TextureCache: invalid storage-texture mip view, image=%p level=%u levels=%u\n", EXIT("TextureCache: invalid storage-texture mip view, image=%p level=%u levels=%u\n",
static_cast<const void*>(image), base_level, image != nullptr ? image->mip_levels : 0); static_cast<const void*>(&image), base_level, image.mip_levels);
} }
if (base_level == 0) { if (base_level == 0) {
return image->image_view[VulkanImage::VIEW_DEFAULT]; return image.image_view[VulkanImage::VIEW_DEFAULT];
} }
return GetImageView(ctx, image, return GetImageView(image, {image.format, vk::ImageViewType::e2D,
{image->format, vk::ImageViewType::e2D, vk::ImageAspectFlagBits::eColor, vk::ImageAspectFlagBits::eColor, base_level, 1, 0, 1,
base_level, 1, 0, 1, DstSel(4, 5, 6, 7), DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eStorage});
vk::ImageUsageFlagBits::eStorage});
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
+5 -5
View File
@@ -216,12 +216,12 @@ ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource
namespace ImageViewOps { namespace ImageViewOps {
[[nodiscard]] vk::ImageAspectFlags DepthAspectMask(vk::Format format); [[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 CreateRenderTargetViews(RenderTextureVulkanImage& image);
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image); void CreateDepthViews(DepthStencilVulkanImage& image);
void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image); void CreateVideoOutViews(VideoOutVulkanImage& image);
void DestroyViews(GraphicContext* ctx, VulkanImage* image); void DestroyViews(VulkanImage& image);
} // namespace ImageViewOps } // namespace ImageViewOps
@@ -8,6 +8,7 @@
#include "graphics/host_gpu/renderer/debug.h" #include "graphics/host_gpu/renderer/debug.h"
#include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/depthRenderTarget.h"
#include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include <atomic> #include <atomic>
@@ -39,78 +40,77 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other)
return std::memcmp(this, &other, sizeof(*this)) == 0; return std::memcmp(this, &other, sizeof(*this)) == 0;
} }
PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline( PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count, VulkanFramebuffer& framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx, RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info, RenderCommandBuffer& command,
HW::Shader* sh_ctx, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool ps_active,
bool ps_active, std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv) { std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv) {
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Gfx)", profiler::colors::DeepOrangeA200); KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Gfx)", profiler::colors::DeepOrangeA200);
EXIT_IF(framebuffer == nullptr);
EXIT_IF(depth == nullptr);
EXIT_IF(colors == nullptr); EXIT_IF(colors == nullptr);
EXIT_IF(color_count > RENDER_COLOR_ATTACHMENTS_MAX); EXIT_IF(color_count > RENDER_COLOR_ATTACHMENTS_MAX);
EXIT_IF(vs_spirv.empty()); EXIT_IF(vs_spirv.empty());
EXIT_IF(ps_active && ps_spirv.empty()); EXIT_IF(ps_active && ps_spirv.empty());
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
auto& ctx = command.GetRegisters();
auto& sh_ctx = command.GetShaders();
const auto& vertex_info = sh_ctx->GetVs(); const auto& vertex_info = sh_ctx.GetVs();
const auto& ps_regs = sh_ctx->GetPs(); const auto& ps_regs = sh_ctx.GetPs();
const HW::BlendColor& bclr = ctx->GetBlendColor(); const HW::BlendColor& bclr = ctx.GetBlendColor();
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {}; uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
for (uint32_t i = 0; i < color_count; i++) { for (uint32_t i = 0; i < color_count; i++) {
color_mask[i] = (colors[i].vulkan_buffer != nullptr color_mask[i] = (colors[i].vulkan_buffer != nullptr
? colors[i].export_mapping.ApplyMask(render_target_mask_slot( ? colors[i].export_mapping.ApplyMask(render_target_mask_slot(
ctx->GetRenderTargetMask(), colors[i].target_slot)) ctx.GetRenderTargetMask(), colors[i].target_slot))
: 0); : 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 {}; ShaderId ps_id {};
if (ps_active) { if (ps_active) {
ps_id = ShaderGetIdPS(&ps_regs, ps_input_info, true); ps_id = ShaderGetIdPS(ps_regs, *ps_input_info, true);
} }
PipelineStaticParameters static_params {}; PipelineStaticParameters static_params {};
GraphicsPipeline p {}; 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.ps_shader_id = ps_id;
p.vs_shader_id = vs_id; p.vs_shader_id = vs_id;
static_params.color_count = color_count; 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<uint32_t> log_count {0}; static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF("Pipeline: temporary: accepting EXEC_ON_NOOP with depth test enabled\n"); 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()); EXIT_NOT_IMPLEMENTED(!clip_control.IsZClipModeRepresentable());
static_params.negative_one_to_one = !clip_control.dx_clip_space; static_params.negative_one_to_one = !clip_control.dx_clip_space;
static_params.depth_clip_enable = clip_control.IsZClipEnabled(); static_params.depth_clip_enable = clip_control.IsZClipEnabled();
static_params.topology = topology; static_params.topology = topology;
static_params.samples = framebuffer->samples; static_params.samples = framebuffer.samples;
static_params.sample_shading_enable = static_params.sample_shading_enable =
ps_active && framebuffer->samples > 1 && ps_input_info->ps_sample_shading; ps_active && framebuffer.samples > 1 && ps_input_info->ps_sample_shading;
if (static_params.sample_shading_enable && if (static_params.sample_shading_enable && !m_graphics.sample_rate_shading_enabled) {
!g_render_ctx->GetGraphicCtx()->sample_rate_shading_enabled) {
EXIT("Pipeline: sample-rate shading is required but unsupported by the host\n"); EXIT("Pipeline: sample-rate shading is required but unsupported by the host\n");
} }
static_params.with_depth = static_params.with_depth =
(depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr); (depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr);
static_params.depth_test_enable = depth->depth_test_enable; 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_write_enable = (depth.depth_write_enable && !depth.depth_clear_enable);
static_params.depth_compare_op = depth->depth_compare_op; static_params.depth_compare_op = depth.depth_compare_op;
static_params.depth_bounds_test_enable = depth->depth_bounds_test_enable; static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable;
static_params.depth_min_bounds = depth->depth_min_bounds; static_params.depth_min_bounds = depth.depth_min_bounds;
static_params.depth_max_bounds = depth->depth_max_bounds; static_params.depth_max_bounds = depth.depth_max_bounds;
static_params.stencil_test_enable = depth->stencil_test_enable; static_params.stencil_test_enable = depth.stencil_test_enable;
static_params.stencil_front = depth->stencil_static_front; static_params.stencil_front = depth.stencil_static_front;
static_params.stencil_back = depth->stencil_static_back; static_params.stencil_back = depth.stencil_static_back;
for (uint32_t i = 0; i < RENDER_COLOR_ATTACHMENTS_MAX; i++) { for (uint32_t i = 0; i < RENDER_COLOR_ATTACHMENTS_MAX; i++) {
static_params.color_mask[i] = color_mask[i]; static_params.color_mask[i] = color_mask[i];
} }
@@ -119,8 +119,8 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
static_params.face = mc.face; static_params.face = mc.face;
for (uint32_t i = 0; i < color_count; i++) { for (uint32_t i = 0; i < color_count; i++) {
const auto& rt = ctx->GetRenderTarget(colors[i].target_slot); const auto& rt = ctx.GetRenderTarget(colors[i].target_slot);
const auto& bc = ctx->GetBlendControl(colors[i].target_slot); const auto& bc = ctx.GetBlendControl(colors[i].target_slot);
static_params.color_srcblend[i] = bc.color_srcblend; static_params.color_srcblend[i] = bc.color_srcblend;
static_params.color_comb_fcn[i] = bc.color_comb_fcn; static_params.color_comb_fcn[i] = bc.color_comb_fcn;
static_params.color_destblend[i] = bc.color_destblend; static_params.color_destblend[i] = bc.color_destblend;
@@ -145,13 +145,13 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
key.static_params = static_params; key.static_params = static_params;
if (auto iter = m_graphics_pipelines.find(key); iter != m_graphics_pipelines.end()) { 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()) { if (graphics_debug_dump_enabled()) {
ShaderDbgDumpInputInfo(vs_input_info); ShaderDbgDumpInputInfo(vs_input_info);
if (ps_active) { if (ps_active) {
ShaderDbgDumpInputInfo(ps_input_info); ShaderDbgDumpInputInfo(*ps_input_info);
} }
LOGF("PipelineTrace: shader binaries VS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64 LOGF("PipelineTrace: shader binaries VS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64
" PS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64 "\n", " PS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64 "\n",
@@ -162,9 +162,9 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
auto cached = std::make_unique<GraphicsPipeline>(p); auto cached = std::make_unique<GraphicsPipeline>(p);
LogPipelineTrace("CreatePipelineInternal begin", vs_id.hash0, vs_id.crc32, ps_id.hash0, LogPipelineTrace("CreatePipelineInternal begin", vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.crc32); ps_id.crc32);
CreatePipelineInternal(cached.get(), framebuffer->render_pass, vs_input_info, vs_spirv, CreatePipelineInternal(*cached, framebuffer.render_pass, vs_input_info, vs_spirv, ps_input_info,
ps_input_info, ps_spirv, static_params, vs_id.hash0, vs_id.crc32, ps_spirv, static_params, vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.hash0, ps_id.crc32, ps_active); ps_id.crc32, ps_active);
LogPipelineTrace("CreatePipelineInternal done", vs_id.hash0, vs_id.crc32, ps_id.hash0, LogPipelineTrace("CreatePipelineInternal done", vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.crc32); ps_id.crc32);
@@ -174,16 +174,15 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
auto [iter, inserted] = m_graphics_pipelines.emplace(std::move(key), std::move(cached)); auto [iter, inserted] = m_graphics_pipelines.emplace(std::move(key), std::move(cached));
EXIT_IF(!inserted); EXIT_IF(!inserted);
return iter->second.get(); return *iter->second;
} }
PipelineCache::ComputePipeline* PipelineCache::ComputePipeline&
PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info, PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info,
const HW::ComputeShaderInfo* cs_regs, const HW::ComputeShaderInfo& cs_regs,
std::span<const uint32_t> cs_spirv) { std::span<const uint32_t> cs_spirv) {
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100); KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100);
EXIT_IF(cs_regs == nullptr);
EXIT_IF(cs_spirv.empty()); EXIT_IF(cs_spirv.empty());
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
@@ -197,7 +196,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
key.cs_shader_id = p.cs_shader_id; key.cs_shader_id = p.cs_shader_id;
if (auto iter = m_compute_pipelines.find(key); iter != m_compute_pipelines.end()) { 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()) { if (graphics_debug_dump_enabled()) {
@@ -205,7 +204,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
} }
auto cached = std::make_unique<ComputePipeline>(p); auto cached = std::make_unique<ComputePipeline>(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 == nullptr);
EXIT_NOT_IMPLEMENTED(cached->pipeline_layout == 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)); auto [iter, inserted] = m_compute_pipelines.emplace(std::move(key), std::move(cached));
EXIT_IF(!inserted); EXIT_IF(!inserted);
return iter->second.get(); return *iter->second;
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
+27 -22
View File
@@ -17,9 +17,11 @@
namespace Libs::Graphics { namespace Libs::Graphics {
struct GraphicContext;
struct RenderColorInfo; struct RenderColorInfo;
struct RenderDepthInfo; struct RenderDepthInfo;
struct VulkanFramebuffer; struct VulkanFramebuffer;
class RenderCommandBuffer;
namespace HW { namespace HW {
class Context; class Context;
@@ -86,7 +88,9 @@ static_assert(sizeof(PipelineStaticParameters) ==
class PipelineCache { class PipelineCache {
public: 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; } ~PipelineCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(PipelineCache); KYTY_CLASS_NO_COPY(PipelineCache);
@@ -105,13 +109,13 @@ public:
ShaderId cs_shader_id; ShaderId cs_shader_id;
}; };
GraphicsPipeline* CreateGraphicsPipeline( GraphicsPipeline& CreateGraphicsPipeline(
VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count, VulkanFramebuffer& framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx, RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info, RenderCommandBuffer& command,
HW::Shader* sh_ctx, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool ps_active,
bool ps_active, std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv); std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv);
ComputePipeline* CreateComputePipeline(ShaderComputeInputInfo* input_info, ComputePipeline& CreateComputePipeline(ShaderComputeInputInfo& input_info,
const HW::ComputeShaderInfo* cs_regs, const HW::ComputeShaderInfo& cs_regs,
std::span<const uint32_t> cs_spirv); std::span<const uint32_t> cs_spirv);
private: private:
@@ -136,12 +140,12 @@ private:
}; };
struct PipelineKeyHash { struct PipelineKeyHash {
static void Mix(std::size_t* hash, std::size_t value) { static void Mix(std::size_t& hash, std::size_t value) {
*hash ^= value + static_cast<std::size_t>(0x9e3779b97f4a7c15ull) + (*hash << 6u) + hash ^= value + static_cast<std::size_t>(0x9e3779b97f4a7c15ull) + (hash << 6u) +
(*hash >> 2u); (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.hash0);
Mix(hash, id.crc32); Mix(hash, id.crc32);
Mix(hash, id.ids.size()); 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<const uint8_t*>(&params); const auto* bytes = reinterpret_cast<const uint8_t*>(&params);
for (std::size_t i = 0; i < sizeof(params); i++) { for (std::size_t i = 0; i < sizeof(params); i++) {
Mix(hash, bytes[i]); Mix(hash, bytes[i]);
@@ -161,10 +165,10 @@ private:
struct GraphicsPipelineKeyHash { struct GraphicsPipelineKeyHash {
std::size_t operator()(const GraphicsPipelineKey& key) const { std::size_t operator()(const GraphicsPipelineKey& key) const {
std::size_t hash = 0; std::size_t hash = 0;
PipelineKeyHash::Mix(&hash, key.render_pass_id); PipelineKeyHash::Mix(hash, key.render_pass_id);
PipelineKeyHash::MixShaderId(&hash, key.vs_shader_id); PipelineKeyHash::MixShaderId(hash, key.vs_shader_id);
PipelineKeyHash::MixShaderId(&hash, key.ps_shader_id); PipelineKeyHash::MixShaderId(hash, key.ps_shader_id);
PipelineKeyHash::MixStaticParams(&hash, key.static_params); PipelineKeyHash::MixStaticParams(hash, key.static_params);
return hash; return hash;
} }
}; };
@@ -172,11 +176,12 @@ private:
struct ComputePipelineKeyHash { struct ComputePipelineKeyHash {
std::size_t operator()(const ComputePipelineKey& key) const { std::size_t operator()(const ComputePipelineKey& key) const {
std::size_t hash = 0; std::size_t hash = 0;
PipelineKeyHash::MixShaderId(&hash, key.cs_shader_id); PipelineKeyHash::MixShaderId(hash, key.cs_shader_id);
return hash; return hash;
} }
}; };
GraphicContext& m_graphics;
std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>, std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>,
GraphicsPipelineKeyHash> GraphicsPipelineKeyHash>
m_graphics_pipelines; 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, void LogPipelineTrace(const char* phase, uint32_t vs_hash0, uint32_t vs_crc32, uint32_t ps_hash0,
uint32_t ps_crc32); uint32_t ps_crc32);
void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::RenderPass render_pass, void CreatePipelineInternal(PipelineCache::GraphicsPipeline& pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo* vs_input_info, const ShaderVertexInputInfo& vs_input_info,
std::span<const uint32_t> vs_shader, std::span<const uint32_t> vs_shader,
const ShaderPixelInputInfo* ps_input_info, const ShaderPixelInputInfo* ps_input_info,
std::span<const uint32_t> ps_shader, std::span<const uint32_t> ps_shader,
const PipelineStaticParameters& static_params, uint32_t vs_hash0, const PipelineStaticParameters& static_params, uint32_t vs_hash0,
uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32, uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32,
bool ps_active); bool ps_active);
void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline, void CreatePipelineInternal(PipelineCache::ComputePipeline& pipeline,
const ShaderComputeInputInfo* input_info, const ShaderComputeInputInfo& input_info,
std::span<const uint32_t> cs_shader); std::span<const uint32_t> cs_shader);
} // namespace Libs::Graphics } // namespace Libs::Graphics
+36 -18
View File
@@ -33,6 +33,7 @@ struct VulkanFramebuffer;
struct RenderDepthInfo; struct RenderDepthInfo;
struct RenderColorInfo; struct RenderColorInfo;
class BufferCache; class BufferCache;
class RenderContext;
struct HtileClearTarget { struct HtileClearTarget {
uint64_t address = 0; uint64_t address = 0;
@@ -68,7 +69,7 @@ private:
class CommandBuffer { class CommandBuffer {
public: public:
explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); } explicit CommandBuffer(int queue);
~CommandBuffer() { Free(); } ~CommandBuffer() { Free(); }
KYTY_CLASS_NO_COPY(CommandBuffer); KYTY_CLASS_NO_COPY(CommandBuffer);
@@ -85,17 +86,18 @@ public:
vk::Semaphore signal_semaphore); vk::Semaphore signal_semaphore);
void SetDebugInfo(uint32_t op, uint64_t submit_id, uint32_t arg0 = 0, uint32_t arg1 = 0, 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); uint32_t arg2 = 0, uint32_t arg3 = 0, uint64_t arg4 = 0);
void BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors, void BeginRenderPass(VulkanFramebuffer& framebuffer, RenderColorInfo* colors,
uint32_t color_count, RenderDepthInfo* depth) const; uint32_t color_count, RenderDepthInfo& depth) const;
void EndRenderPass() const; void EndRenderPass() const;
void WaitForFenceOnly(); void WaitForFenceOnly();
void WaitForFence(); void WaitForFence();
void WaitForFenceAndReset(); void WaitForFenceAndReset();
void DeleteAfterFence(VulkanBuffer* buffer); void DeleteAfterFence(VulkanBuffer& buffer);
void RetainResourceUntilFence(std::shared_ptr<void> resource); void RetainResourceUntilFence(std::shared_ptr<void> resource);
void RecycleDescriptorAfterFence(VulkanDescriptorSet* set); void RecycleDescriptorAfterFence(VulkanDescriptorSet& set);
[[nodiscard]] vk::CommandBuffer Handle() const; [[nodiscard]] vk::CommandBuffer Handle() const;
[[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; }
[[nodiscard]] int GetQueue() const { return m_queue; } [[nodiscard]] int GetQueue() const { return m_queue; }
[[nodiscard]] bool IsExecute() const { return m_execute; } [[nodiscard]] bool IsExecute() const { return m_execute; }
[[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; } [[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; }
@@ -111,6 +113,7 @@ private:
void DeleteBuffersAfterFence(); void DeleteBuffersAfterFence();
void RecycleDescriptorsAfterFence(); void RecycleDescriptorsAfterFence();
GraphicContext& m_graphics;
VulkanCommandPool* m_pool = nullptr; VulkanCommandPool* m_pool = nullptr;
uint32_t m_index = static_cast<uint32_t>(-1); uint32_t m_index = static_cast<uint32_t>(-1);
int m_queue = -1; int m_queue = -1;
@@ -131,34 +134,49 @@ private:
HostStreamBuffer m_host_stream; HostStreamBuffer m_host_stream;
}; };
void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, class RenderCommandBuffer final: public CommandBuffer {
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_type_and_size, 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 index_count, const void* index_addr, uint32_t flags, uint32_t type,
uint32_t instance_count = 1, uint32_t render_target_slice_offset = 0, uint32_t instance_count = 1, uint32_t render_target_slice_offset = 0,
int32_t vertex_offset_add = 0, uint32_t first_instance = 0); int32_t vertex_offset_add = 0, uint32_t first_instance = 0);
void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, void RenderDrawIndexAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_count,
uint32_t flags, uint32_t render_target_slice_offset = 0, uint32_t flags, uint32_t render_target_slice_offset = 0,
uint32_t instance_count = 1, uint32_t first_vertex = 0, uint32_t instance_count = 1, uint32_t first_vertex = 0,
uint32_t first_instance = 0); uint32_t first_instance = 0);
void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, void RenderDispatchDirect(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t thread_group_x,
HW::Shader* sh_ctx, uint32_t thread_group_x, uint32_t thread_group_y, uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode);
uint32_t thread_group_z, uint32_t mode);
void GraphicsRenderInit(); void GraphicsRenderInit();
void GraphicsRenderCreateContext(); void GraphicsRenderCreateContext();
void GraphicsRenderSetContext(RenderContext& context);
void GraphicsRenderReleaseThreadCommandPools(); void GraphicsRenderReleaseThreadCommandPools();
[[nodiscard]] bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x, [[nodiscard]] bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode, uint32_t group_y, uint32_t group_z, uint32_t mode,
ShaderBufferResource* descriptor, ShaderBufferResource& descriptor,
uint32_t* packed_clear, uint64_t* size); uint32_t& packed_clear, uint64_t& size);
[[nodiscard]] bool ResolveHtileClearTarget(const HW::DepthRenderTarget& target, [[nodiscard]] bool ResolveHtileClearTarget(const HW::DepthRenderTarget& target,
uint64_t descriptor_size, HtileClearTarget* resolved); uint64_t descriptor_size, HtileClearTarget& resolved);
void GraphicsRenderMemoryBarrier(CommandBuffer* buffer); void GraphicsRenderMemoryBarrier(CommandBuffer& buffer);
void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size); void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size);
void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size); void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size);
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -51,11 +51,8 @@ static uint64_t BufferDescriptorSize(const ShaderBufferResource& descriptor) {
} }
bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor_size, bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor_size,
HtileClearTarget* resolved) { HtileClearTarget& resolved) {
if (resolved == nullptr) { resolved = {};
return false;
}
*resolved = {};
const bool has_stencil = const bool has_stencil =
z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid); z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid);
const auto* depth_policy = FindDepthFormatPolicy(z.z_info.format); 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) { if (!descriptor_backed_state) {
return false; return false;
} }
*resolved = {.address = z.htile_data_base_addr, .size = descriptor_size}; resolved = {.address = z.htile_data_base_addr, .size = descriptor_size};
return true; return true;
} }
const uint32_t width = size_xy_valid ? static_cast<uint32_t>(z.size.x_max) + 1u : z.width; const uint32_t width = size_xy_valid ? static_cast<uint32_t>(z.size.x_max) + 1u : z.width;
@@ -124,10 +121,10 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor
return false; return false;
} }
TileSizeAlign htile_size {}; 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; 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; return true;
} }
@@ -154,9 +151,10 @@ static void ValidateFullHtileClearDispatch(const ShaderComputeInputInfo& input,
} }
} }
static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, const HW::Context& ctx, static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input,
uint32_t group_x, uint32_t group_y, uint32_t group_z, const RenderCommandBuffer& buffer, uint32_t group_x,
uint32_t mode) { uint32_t group_y, uint32_t group_z, uint32_t mode) {
const auto& ctx = buffer.GetRegisters();
const auto& program = *input.stage.program; const auto& program = *input.stage.program;
const auto& resources = *input.stage.resources; const auto& resources = *input.stage.resources;
if (resources.buffers.size() != program.info.buffers.size()) { 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 auto& z = ctx.GetDepthRenderTarget();
const uint64_t meta_addr = z.htile_data_base_addr; 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 current_references = 0;
uint32_t registered_writes = 0; uint32_t registered_writes = 0;
uint64_t described_meta_size = 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. // identifiable even when it is no longer the currently bound depth target.
TextureCache::MetaRangeInfo resolved_meta {}; TextureCache::MetaRangeInfo resolved_meta {};
if (resource.written && if (resource.written &&
cache->ResolveMetaRange(descriptor.Base48(), descriptor_size, &resolved_meta)) { cache.ResolveMetaRange(descriptor.Base48(), descriptor_size, resolved_meta)) {
registered_writes++; registered_writes++;
registered_target = {.address = descriptor.Base48(), .size = descriptor_size}; registered_target = {.address = descriptor.Base48(), .size = descriptor_size};
registered_meta = resolved_meta; registered_meta = resolved_meta;
@@ -197,7 +195,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
} }
HtileClearTarget target {}; HtileClearTarget target {};
if (current_references != 0) { 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 " 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 "meta=0x%016" PRIx64 "+0x%016" PRIx64 " depth=0x%016" PRIx64 "/0x%016" PRIx64
" stencil=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.slice_div64_minus1, z.z_info.format, z.stencil_info.format,
z.z_info.num_samples); z.z_info.num_samples);
} }
cache->RegisterMeta(g_render_ctx->GetGraphicCtx(), target.address, target.size); cache.RegisterMeta(target.address, target.size);
if (!cache->ResolveMetaRange(target.address, target.size, &registered_meta)) { if (!cache.ResolveMetaRange(target.address, target.size, registered_meta)) {
EXIT("failed to resolve registered HTile compute-clear range\n"); EXIT("failed to resolve registered HTile compute-clear range\n");
} }
} else { } else {
target = registered_target; 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; uint32_t metadata_writes = 0;
ShaderBufferResource metadata_descriptor {}; ShaderBufferResource metadata_descriptor {};
@@ -245,10 +243,10 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
} }
if (resource.written || !resource.read || resource.atomic || descriptor.Base48() == 0 || if (resource.written || !resource.read || resource.atomic || descriptor.Base48() == 0 ||
descriptor_size == 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"); EXIT("unsupported HTile clear side-buffer access\n");
} }
g_render_ctx->GetBufferCache()->ValidateGpuAccess(descriptor.Base48(), descriptor_size, GetRenderContext().GetBufferCache().ValidateGpuAccess(descriptor.Base48(), descriptor_size,
true, false); true, false);
} }
if (metadata_writes != 1) { if (metadata_writes != 1) {
@@ -256,8 +254,8 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
metadata_writes); metadata_writes);
} }
ValidateFullHtileClearDispatch(input, metadata_descriptor, group_x, group_y, group_z, mode); ValidateFullHtileClearDispatch(input, metadata_descriptor, group_x, group_y, group_z, mode);
const bool recorded = registered_meta.full ? cache->ClearMeta(registered_meta.metadata_address) const bool recorded = registered_meta.full ? cache.ClearMeta(registered_meta.metadata_address)
: cache->TouchMeta(registered_meta.metadata_address, : cache.TouchMeta(registered_meta.metadata_address,
registered_meta.slice, true); registered_meta.slice, true);
if (!recorded) { if (!recorded) {
EXIT("failed to record HTile compute clear\n"); 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, bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode, uint32_t group_y, uint32_t group_z, uint32_t mode,
ShaderBufferResource* resolved_descriptor, uint32_t* resolved_clear, ShaderBufferResource& resolved_descriptor, uint32_t& resolved_clear,
uint64_t* resolved_size) { uint64_t& resolved_size) {
if (resolved_descriptor == nullptr || resolved_clear == nullptr || resolved_size == nullptr) {
return false;
}
const auto& program = *input.stage.program; const auto& program = *input.stage.program;
const auto& resources = *input.stage.resources; const auto& resources = *input.stage.resources;
if (program.info.buffers.size() != 1 || resources.buffers.size() != 1 || 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) { if (!full_dispatch || size == 0) {
return false; return false;
} }
*resolved_descriptor = descriptor; resolved_descriptor = descriptor;
*resolved_clear = clear; resolved_clear = clear;
*resolved_size = size; resolved_size = size;
return true; 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 group_x, uint32_t group_y, uint32_t group_z,
uint32_t mode) { uint32_t mode) {
ShaderBufferResource descriptor; ShaderBufferResource descriptor;
uint32_t packed_clear = 0; uint32_t packed_clear = 0;
uint64_t size = 0; uint64_t size = 0;
if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, &descriptor, if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, descriptor, packed_clear,
&packed_clear, &size)) { size)) {
return false; return false;
} }
auto* cache = g_render_ctx->GetTextureCache(); auto& cache = GetRenderContext().GetTextureCache();
if (!cache->ClearImageFromBuffer(command, descriptor.Base48(), size, packed_clear)) { if (!cache.ClearImageFromBuffer(command, descriptor.Base48(), size, packed_clear)) {
return false; return false;
} }
static std::atomic<uint32_t> logged_clears {0}; static std::atomic<uint32_t> logged_clears {0};
@@ -342,28 +337,26 @@ static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, Com
return true; return true;
} }
void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, void RenderDispatchDirect(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t thread_group_x,
HW::Shader* sh_ctx, uint32_t thread_group_x, uint32_t thread_group_y, uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode) {
uint32_t thread_group_z, uint32_t mode) { EXIT_IF(buffer.IsInvalid());
EXIT_IF(ctx == nullptr); auto& ctx = buffer.GetRegisters();
EXIT_IF(g_render_ctx == nullptr); auto& sh_ctx = buffer.GetShaders();
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DispatchDirect), submit_id, buffer.SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DispatchDirect), submit_id,
thread_group_x, thread_group_y, thread_group_z, mode, thread_group_x, thread_group_y, thread_group_z, mode,
sh_ctx != nullptr ? sh_ctx->GetCs().cs_regs.data_addr : 0); 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, " LOGF("GraphicsRenderDispatchDirect: temporary: ignoring dispatch with null CS shader, "
"groups=%ux%ux%u mode=%u\n", "groups=%ux%ux%u mode=%u\n",
thread_group_x, thread_group_y, thread_group_z, mode); thread_group_x, thread_group_y, thread_group_z, mode);
return; return;
} }
if (!ShaderAddressValid(sh_ctx->GetCs().cs_regs.data_addr)) { if (!ShaderAddressValid(sh_ctx.GetCs().cs_regs.data_addr)) {
return; return;
} }
@@ -380,17 +373,17 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
LOGF("GraphicsRenderDispatchDirect: unknown dispatch initiator bits " LOGF("GraphicsRenderDispatchDirect: unknown dispatch initiator bits "
"mode=0x%08" PRIx32 " unknown=0x%08" PRIx32 " shader=0x%016" PRIx64 "mode=0x%08" PRIx32 " unknown=0x%08" PRIx32 " shader=0x%016" PRIx64
" groups=%ux%ux%u\n", " 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); thread_group_y, thread_group_z);
} }
} }
const auto& cs_regs = sh_ctx->GetCs(); const auto& cs_regs = sh_ctx.GetCs();
const auto& sh_regs = ctx->GetShaderRegisters(); const auto& sh_regs = ctx.GetShaderRegisters();
ShaderComputeInputInfo input_info {}; ShaderComputeInputInfo input_info {};
std::span<const uint32_t> cs_shader; std::span<const uint32_t> 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", EXIT("ShaderCompileInfoCS failed for dispatch with CS shader 0x%016" PRIx64 "\n",
cs_regs.cs_regs.data_addr); 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); (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& program = *input_info.stage.program;
const auto& resources = *input_info.stage.resources; const auto& resources = *input_info.stage.resources;
if (TryConsumeComputeMetaClear(input_info, *ctx, thread_group_x, thread_group_y, thread_group_z, if (TryConsumeComputeMetaClear(input_info, buffer, thread_group_x, thread_group_y,
mode)) { thread_group_z, mode)) {
return; return;
} }
if (TryConsumeComputeImageClear(input_info, buffer, thread_group_x, thread_group_y, 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 LOGF("GraphicsRenderDispatchDirect: frame=%u shader=0x%016" PRIx64
" groups=%ux%ux%u mode=0x%08" PRIx32 " local=%ux%ux%u " " 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", "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], 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(), input_info.threads_num[2], program.info.buffers.size(), program.info.images.size(),
sampled_images, program.info.images.size() - sampled_images, 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 " LOGF("GraphicsRenderDispatchDirect: skipping zero-sized dispatch groups=%ux%ux%u "
"mode=0x%08" PRIx32 " shader=0x%016" PRIx64 "\n", "mode=0x%08" PRIx32 " shader=0x%016" PRIx64 "\n",
thread_group_x, thread_group_y, thread_group_z, mode, 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; return;
} }
for (;;) { for (;;) {
const auto recording_generation = buffer->GetRecordingGeneration(); const auto recording_generation = buffer.GetRecordingGeneration();
auto vk_buffer = buffer->Handle(); auto vk_buffer = buffer.Handle();
auto* pipeline = g_render_ctx->GetPipelineCache()->CreateComputePipeline( auto& pipeline = GetRenderContext().GetPipelineCache().CreateComputePipeline(
&input_info, &sh_ctx->GetCs(), cs_shader); 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, 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); vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute);
if (buffer->GetRecordingGeneration() != recording_generation) { if (buffer.GetRecordingGeneration() != recording_generation) {
continue; continue;
} }
@@ -2,7 +2,6 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "graphics/presentation/window.h"
#include "kernel/pthread.h" #include "kernel/pthread.h"
#include "libs/errno.h" #include "libs/errno.h"
@@ -10,38 +9,11 @@
namespace Libs::Graphics { namespace Libs::Graphics {
void RenderContext::SetGraphicCtx(GraphicContext* ctx) { RenderContext::RenderContext(GraphicContext& graphics)
EXIT_IF(ctx == nullptr); : m_graphics(graphics), m_pipeline_cache(graphics), m_descriptor_cache(graphics),
m_framebuffer_cache(graphics), m_sampler_cache(graphics), m_gds_buffer(graphics),
Common::LockGuard lock(m_graphic_ctx_mutex); m_gpu_resources(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
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<void*>(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;
} }
void RenderContext::AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id) { void RenderContext::AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id) {
+13 -14
View File
@@ -23,22 +23,21 @@ constexpr int AGC_USER_INTERRUPT_EVENT = 0x1800;
class RenderContext { class RenderContext {
public: public:
RenderContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } explicit RenderContext(GraphicContext& graphics);
~RenderContext() { KYTY_NOT_IMPLEMENTED; } ~RenderContext() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(RenderContext); KYTY_CLASS_NO_COPY(RenderContext);
void SetGraphicCtx(GraphicContext* ctx); [[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; }
GraphicContext* GetGraphicCtx();
Common::Mutex& GetMutex() { return m_mutex; } Common::Mutex& GetMutex() { return m_mutex; }
PipelineCache* GetPipelineCache() { return &m_pipeline_cache; } PipelineCache& GetPipelineCache() { return m_pipeline_cache; }
DescriptorCache* GetDescriptorCache() { return &m_descriptor_cache; } DescriptorCache& GetDescriptorCache() { return m_descriptor_cache; }
FramebufferCache* GetFramebufferCache() { return &m_framebuffer_cache; } FramebufferCache& GetFramebufferCache() { return m_framebuffer_cache; }
SamplerCache* GetSamplerCache() { return &m_sampler_cache; } SamplerCache& GetSamplerCache() { return m_sampler_cache; }
GdsBuffer* GetGdsBuffer() { return &m_gds_buffer; } GdsBuffer& GetGdsBuffer() { return m_gds_buffer; }
GpuResourceManager* GetGpuResources() { return &m_gpu_resources; } GpuResourceManager& GetGpuResources() { return m_gpu_resources; }
BufferCache* GetBufferCache() { return m_gpu_resources.GetBufferCache(); } BufferCache& GetBufferCache() { return m_gpu_resources.GetBufferCache(); }
TextureCache* GetTextureCache() { return m_gpu_resources.GetTextureCache(); } TextureCache& GetTextureCache() { return m_gpu_resources.GetTextureCache(); }
void AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id); void AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id);
void DeleteEopEq(LibKernel::EventQueue::KernelEqueue eq, int id); void DeleteEopEq(LibKernel::EventQueue::KernelEqueue eq, int id);
@@ -51,13 +50,12 @@ private:
uint32_t count = 0; uint32_t count = 0;
}; };
GraphicContext& m_graphics;
Common::Mutex m_mutex; Common::Mutex m_mutex;
Common::Mutex m_graphic_ctx_mutex;
PipelineCache m_pipeline_cache; PipelineCache m_pipeline_cache;
DescriptorCache m_descriptor_cache; DescriptorCache m_descriptor_cache;
FramebufferCache m_framebuffer_cache; FramebufferCache m_framebuffer_cache;
SamplerCache m_sampler_cache; SamplerCache m_sampler_cache;
GraphicContext* m_graphic_ctx = nullptr;
GdsBuffer m_gds_buffer; GdsBuffer m_gds_buffer;
GpuResourceManager m_gpu_resources; GpuResourceManager m_gpu_resources;
@@ -65,7 +63,8 @@ private:
std::vector<EopEqRegistration> m_eop_eqs; std::vector<EopEqRegistration> m_eop_eqs;
}; };
extern RenderContext* g_render_ctx; [[nodiscard]] bool HasRenderContext() noexcept;
[[nodiscard]] RenderContext& GetRenderContext();
} // namespace Libs::Graphics } // namespace Libs::Graphics
+213 -248
View File
@@ -70,7 +70,7 @@ static std::atomic<uint32_t> g_mrt_state_log_count = 0;
static std::atomic<uint32_t> g_shader_stage_log_count = 0; static std::atomic<uint32_t> g_shader_stage_log_count = 0;
static std::atomic<uint32_t> g_framebuffer_skip_log_count = 0; static std::atomic<uint32_t> 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); uint32_t render_target_slice_offset);
static const char* RenderColorTypeName(RenderColorType type) { 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, static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& color,
const RenderDepthInfo& depth, const HW::Context* ctx, const RenderDepthInfo& depth, const RenderCommandBuffer& buffer,
const HW::UserConfig* ucfg, uint32_t index_count, uint32_t flags) { uint32_t index_count, uint32_t flags) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
if (!graphics_debug_dump_enabled()) { if (!graphics_debug_dump_enabled()) {
return; 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", " prim=%u index_count=%u flags=0x%08" PRIx32 "\n",
log_id, draw_name, RenderColorTypeName(color.type), color.base_addr, color.buffer_size, log_id, draw_name, RenderColorTypeName(color.type), color.base_addr, color.buffer_size,
color.vulkan_buffer != nullptr ? "yes" : "no", VulkanToString(depth.format).c_str(), color.vulkan_buffer != nullptr ? "yes" : "no", VulkanToString(depth.format).c_str(),
depth.vulkan_buffer != nullptr ? "yes" : "no", depth.vaddr_num, depth.vulkan_buffer != nullptr ? "yes" : "no", depth.vaddr_num, ctx.GetRenderTargetMask(),
ctx != nullptr ? ctx->GetRenderTargetMask() : 0, ucfg != nullptr ? ucfg->GetPrimType() : 0, ucfg.GetPrimType(), index_count, flags);
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) { const ShaderPixelInputInfo& ps_input_info) {
EXIT_IF(ctx == nullptr); const auto& ctx = buffer.GetRegisters();
const auto& sh_regs = ctx.GetShaderRegisters();
const auto& sh_regs = ctx->GetShaderRegisters(); const auto rt_mask = ctx.GetRenderTargetMask();
const auto rt_mask = ctx->GetRenderTargetMask();
const auto cb_shader_mask = sh_regs.m_cbShaderMask; 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 || bool interesting = rt_mask != 0x0f || (cb_shader_mask & ~0x0fu) != 0 ||
IsDualSourceBlendFactor(bc0.color_srcblend) || IsDualSourceBlendFactor(bc0.color_srcblend) ||
@@ -125,7 +125,7 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx,
IsDualSourceBlendFactor(bc0.alpha_destblend))); IsDualSourceBlendFactor(bc0.alpha_destblend)));
for (uint32_t i = 1; i < 8; i++) { 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 || 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) { ((rt_mask >> (i * 4u)) & 0x0fu) != 0 || ((cb_shader_mask >> (i * 4u)) & 0x0fu) != 0) {
interesting = true; interesting = true;
@@ -148,8 +148,8 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx,
bc0.separate_alpha_blend ? "true" : "false"); bc0.separate_alpha_blend ? "true" : "false");
for (uint32_t i = 0; i < 8; i++) { for (uint32_t i = 0; i < 8; i++) {
const auto& rt = ctx->GetRenderTarget(i); const auto& rt = ctx.GetRenderTarget(i);
const auto& bc = ctx->GetBlendControl(i); const auto& bc = ctx.GetBlendControl(i);
const auto ctm = (rt_mask >> (i * 4u)) & 0x0fu; const auto ctm = (rt_mask >> (i * 4u)) & 0x0fu;
const auto csm = (cb_shader_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, static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& color,
const RenderDepthInfo& depth, const HW::Context* ctx, const RenderDepthInfo& depth, const RenderCommandBuffer& buffer,
const HW::UserConfig* ucfg,
const ShaderPixelInputInfo& ps_input_info, uint32_t index_count, const ShaderPixelInputInfo& ps_input_info, uint32_t index_count,
uint32_t flags) { uint32_t flags) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
if (color.type == RenderColorType::NoColorOutput) { if (color.type == RenderColorType::NoColorOutput) {
return; return;
} }
@@ -184,13 +185,10 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
return; return;
} }
EXIT_IF(ctx == nullptr); const auto& cc = ctx.GetColorControl();
EXIT_IF(ucfg == nullptr); const auto& bc = ctx.GetBlendControl(color.target_slot);
const auto& dc = ctx.GetDepthControl();
const auto& cc = ctx->GetColorControl(); const auto& vp = ctx.GetScreenViewport();
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& vp0 = vp.viewports[0];
const auto& ps_resources = ps_input_info.stage.program->info; const auto& ps_resources = ps_input_info.stage.program->info;
const auto sampled_images = std::count_if( 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 {}; 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( LOGF(
"DrawTargetState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64 "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) " " depth_test=%s depth_write=%s depth_func=%u depth_clear=%s viewport=(%.1f,%.1f %.1fx%.1f) "
"scissor=(%d,%d)-(%d,%d)\n", "scissor=(%d,%d)-(%d,%d)\n",
log_id, GraphicsRunGetFrameNum(), draw_name, RenderColorTypeName(color.type), log_id, GraphicsRunGetFrameNum(), draw_name, RenderColorTypeName(color.type),
color.base_addr, extent.width, extent.height, ucfg->GetPrimType(), index_count, flags, color.base_addr, extent.width, extent.height, ucfg.GetPrimType(), index_count, flags,
ctx->GetRenderTargetMask(), color.color_clear_enable ? "true" : "false", 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[0], color.color_clear_value.float32[1],
color.color_clear_value.float32[2], color.color_clear_value.float32[3], cc.mode, cc.op, 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, 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, vp0.yoffset - vp0.yscale, vp0.xscale * 2.0f, vp0.yscale * 2.0f, sc.left, sc.top, sc.right,
sc.bottom); sc.bottom);
LogMrtState(draw_name, ctx, ps_input_info); LogMrtState(draw_name, buffer, ps_input_info);
} }
static void LogDrawInputState(const RenderColorInfo& color, 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, static void VulkanCmdSetColorWriteEnableEXT(const RenderCommandBuffer& buffer,
vk::CommandBuffer command_buffer,
uint32_t attachment_count, uint32_t attachment_count,
const vk::Bool32* p_color_write_enables) { const vk::Bool32* p_color_write_enables) {
EXIT_IF(ctx == nullptr); EXIT_IF(buffer.GetGraphics().device == nullptr);
EXIT_IF(ctx->device == nullptr);
if (VULKAN_HPP_DEFAULT_DISPATCHER.vkCmdSetColorWriteEnableEXT == nullptr) { if (VULKAN_HPP_DEFAULT_DISPATCHER.vkCmdSetColorWriteEnableEXT == nullptr) {
EXIT("vkCmdSetColorWriteEnableEXT not present\n"); 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); command_buffer.setColorWriteEnableEXT(attachment_count, p_color_write_enables);
} }
static PipelineDynamicParameters BuildGraphicsDynamicParams(const HW::Context& ctx, static PipelineDynamicParameters BuildGraphicsDynamicParams(const RenderCommandBuffer& buffer,
const RenderColorInfo* colors, const RenderColorInfo* colors,
uint32_t color_count, uint32_t color_count,
const RenderDepthInfo& depth) { const RenderDepthInfo& depth) {
EXIT_IF(colors == nullptr); EXIT_IF(colors == nullptr);
const auto& ctx = buffer.GetRegisters();
PipelineDynamicParameters ret {}; PipelineDynamicParameters ret {};
ret.color_write_count = color_count; ret.color_write_count = color_count;
@@ -362,7 +361,7 @@ static PipelineDynamicParameters BuildGraphicsDynamicParams(const HW::Context&
return ret; return ret;
} }
static void SetDynamicParams(vk::CommandBuffer vk_buffer, static void SetDynamicParams(const RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer,
const PipelineDynamicParameters& dynamic_params) { const PipelineDynamicParameters& dynamic_params) {
KYTY_PROFILER_FUNCTION(); 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++) { for (uint32_t i = 0; i < dynamic_params.color_write_count; i++) {
enable[i] = (dynamic_params.color_write_enable[i] ? VK_TRUE : VK_FALSE); enable[i] = (dynamic_params.color_write_enable[i] ? VK_TRUE : VK_FALSE);
} }
VulkanCmdSetColorWriteEnableEXT(g_render_ctx->GetGraphicCtx(), vk_buffer, VulkanCmdSetColorWriteEnableEXT(buffer, vk_buffer, dynamic_params.color_write_count, enable);
dynamic_params.color_write_count, enable);
} }
static bool DrawHasValidVertexShader(const HW::Shader* sh_ctx) { static bool DrawHasValidVertexShader(const HW::Shader& sh_ctx) {
EXIT_IF(sh_ctx == nullptr);
const auto& vs = sh_ctx->GetVs(); const auto& vs = sh_ctx.GetVs();
return vs.gs_regs.chksum != 0 && ShaderAddressValid(vs.es_regs.data_addr); 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; db.shader_execute_on_noop;
} }
static bool ShouldSkipGeShader(const HW::Context* ctx, const HW::UserConfig* ucfg, static bool ShouldSkipGeShader(const RenderCommandBuffer& buffer) {
const HW::Shader* sh_ctx) { const auto& ctx = buffer.GetRegisters();
EXIT_IF(ctx == nullptr); const auto& ucfg = buffer.GetUserConfig();
EXIT_IF(ucfg == nullptr); const auto& sh_ctx = buffer.GetShaders();
EXIT_IF(sh_ctx == nullptr); const auto& sh_regs = ctx.GetShaderRegisters();
const auto& ge_cntl = ucfg.GetGeControl();
const auto& sh_regs = ctx->GetShaderRegisters(); const auto& vertex_info = sh_ctx.GetVs();
const auto& ge_cntl = ucfg->GetGeControl(); const auto stages = ctx.GetShaderStages();
const auto& vertex_info = sh_ctx->GetVs();
const auto stages = ctx->GetShaderStages();
const auto is_known_gs_out_prim_type = [](uint32_t value) { const auto is_known_gs_out_prim_type = [](uint32_t value) {
switch (static_cast<Prospero::GsOutputPrimitiveType>(value)) { switch (static_cast<Prospero::GsOutputPrimitiveType>(value)) {
@@ -511,11 +506,11 @@ struct DrawCallInfo {
uint32_t first_instance = 0; 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) { const DrawRenderState& state, const DrawCallInfo& draw) {
EXIT_IF(ctx == nullptr);
EXIT_IF(sh_ctx == nullptr);
EXIT_IF(draw.name == 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 && const bool with_depth = (state.depth_info.format != vk::Format::eUndefined &&
state.depth_info.vulkan_buffer != nullptr); state.depth_info.vulkan_buffer != nullptr);
@@ -523,8 +518,8 @@ static bool DrawHasActivePixelShader(const HW::Context* ctx, const HW::Shader* s
return true; return true;
} }
const auto& sh_regs = ctx->GetShaderRegisters(); const auto& sh_regs = ctx.GetShaderRegisters();
const auto& ps = sh_ctx->GetPs(); const auto& ps = sh_ctx.GetPs();
return ShaderAddressValid(ps.ps_regs.data_addr) && return ShaderAddressValid(ps.ps_regs.data_addr) &&
PixelShaderHasDepthOrCoverageSideEffects(sh_regs); PixelShaderHasDepthOrCoverageSideEffects(sh_regs);
} }
@@ -538,7 +533,8 @@ enum class CbColorMode : uint8_t {
DccDecompress = 6, DccDecompress = 6,
}; };
static bool ConsumeMetadataColorOperation(const HW::Context& ctx) { static bool ConsumeMetadataColorOperation(const RenderCommandBuffer& buffer) {
const auto& ctx = buffer.GetRegisters();
const auto mode = ctx.GetColorControl().mode; const auto mode = ctx.GetColorControl().mode;
// These AGC CB modes run color-buffer metadata/decompression operations. The shader is a // 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. // dummy vehicle for the CB, and its exported color must not be applied as a normal draw.
@@ -570,176 +566,160 @@ static uint64_t VertexBufferDescriptorSize(const ShaderVertexInputBuffer& buffer
: buffer.num_records); : buffer.num_records);
} }
static void SetDrawDebugPhase(CommandBuffer* buffer, uint64_t submit_id, const DrawCallInfo& draw, static void SetDrawDebugPhase(RenderCommandBuffer& buffer, uint64_t submit_id,
uint32_t phase) { const DrawCallInfo& draw, uint32_t phase) {
EXIT_IF(buffer == nullptr);
EXIT_IF(draw.name == nullptr); EXIT_IF(draw.name == nullptr);
buffer->SetDebugInfo(static_cast<uint32_t>(draw.debug_op), submit_id, phase, draw.index_count, buffer.SetDebugInfo(static_cast<uint32_t>(draw.debug_op), submit_id, phase, draw.index_count,
draw.flags, draw.instance_count, draw.first_instance); draw.flags, draw.instance_count, draw.first_instance);
} }
static bool GetDrawTopology(const HW::UserConfig* ucfg, bool auto_draw, bool use_ngg_rectlist_draw, static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw, bool use_ngg_rectlist_draw,
vk::PrimitiveTopology* topology) { vk::PrimitiveTopology& topology) {
EXIT_IF(ucfg == nullptr);
EXIT_IF(topology == nullptr);
*topology = vk::PrimitiveTopology::ePointList; topology = vk::PrimitiveTopology::ePointList;
switch (static_cast<Prospero::PrimitiveType>(ucfg->GetPrimType())) { switch (static_cast<Prospero::PrimitiveType>(ucfg.GetPrimType())) {
case Prospero::PrimitiveType::kNone: return false; case Prospero::PrimitiveType::kNone: return false;
case Prospero::PrimitiveType::kPointList: case Prospero::PrimitiveType::kPointList:
*topology = vk::PrimitiveTopology::ePointList; topology = vk::PrimitiveTopology::ePointList;
break;
case Prospero::PrimitiveType::kLineList:
*topology = vk::PrimitiveTopology::eLineList;
break; break;
case Prospero::PrimitiveType::kLineList: topology = vk::PrimitiveTopology::eLineList; break;
case Prospero::PrimitiveType::kLineStrip: case Prospero::PrimitiveType::kLineStrip:
*topology = vk::PrimitiveTopology::eLineStrip; topology = vk::PrimitiveTopology::eLineStrip;
break; break;
case Prospero::PrimitiveType::kTriList: case Prospero::PrimitiveType::kTriList:
*topology = vk::PrimitiveTopology::eTriangleList; topology = vk::PrimitiveTopology::eTriangleList;
break; break;
case Prospero::PrimitiveType::kTriFan: case Prospero::PrimitiveType::kTriFan:
*topology = vk::PrimitiveTopology::eTriangleFan; topology = vk::PrimitiveTopology::eTriangleFan;
break; break;
case Prospero::PrimitiveType::kTriStrip: case Prospero::PrimitiveType::kTriStrip:
*topology = vk::PrimitiveTopology::eTriangleStrip; topology = vk::PrimitiveTopology::eTriangleStrip;
break; break;
case Prospero::PrimitiveType::kRectList: case Prospero::PrimitiveType::kRectList:
*topology = (auto_draw && use_ngg_rectlist_draw ? vk::PrimitiveTopology::eTriangleStrip topology = (auto_draw && use_ngg_rectlist_draw ? vk::PrimitiveTopology::eTriangleStrip
: vk::PrimitiveTopology::eTriangleList); : vk::PrimitiveTopology::eTriangleList);
break; break;
case Prospero::PrimitiveType::kRectListLegacy: case Prospero::PrimitiveType::kRectListLegacy:
if (!auto_draw) { 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; break;
case Prospero::PrimitiveType::kQuadListLegacy: case Prospero::PrimitiveType::kQuadListLegacy:
*topology = vk::PrimitiveTopology::eTriangleFan; topology = vk::PrimitiveTopology::eTriangleFan;
break; break;
default: EXIT("unknown primitive type: %u\n", ucfg->GetPrimType()); default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
} }
return true; return true;
} }
static bool PrepareDrawRenderState(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, static bool PrepareDrawRenderState(uint64_t submit_id, RenderCommandBuffer& buffer,
HW::UserConfig* ucfg, HW::Shader* sh_ctx,
const DrawCallInfo& draw, uint32_t render_target_slice_offset, const DrawCallInfo& draw, uint32_t render_target_slice_offset,
bool skip_null_framebuffer, bool log_setup_phases, bool skip_null_framebuffer, bool log_setup_phases,
DrawRenderState* state) { DrawRenderState& state) {
EXIT_IF(buffer == nullptr);
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(sh_ctx == nullptr);
EXIT_IF(draw.name == nullptr); EXIT_IF(draw.name == nullptr);
EXIT_IF(state == nullptr); auto& ctx = buffer.GetRegisters();
if (log_setup_phases) { if (log_setup_phases) {
LogDrawPhase(draw.name, "ResolveRenderDepthTarget"); 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)) { if (ResolveColorTargets(submit_id, buffer, render_target_slice_offset)) {
MarkRenderTargetGpuWritten(state->depth_info); MarkRenderTargetGpuWritten(state.depth_info);
return false; return false;
} }
MarkRenderTargetGpuWritten(state->depth_info); MarkRenderTargetGpuWritten(state.depth_info);
if (log_setup_phases) { if (log_setup_phases) {
LogDrawPhase(draw.name, "ResolveRenderColorTarget"); LogDrawPhase(draw.name, "ResolveRenderColorTarget");
} }
for (uint32_t slot = 0; slot < RENDER_COLOR_ATTACHMENTS_MAX; slot++) { for (uint32_t slot = 0; slot < RENDER_COLOR_ATTACHMENTS_MAX; slot++) {
if (slot == 0 || (render_target_mask_slot(ctx->GetRenderTargetMask(), slot) != 0 && if (slot == 0 || (render_target_mask_slot(ctx.GetRenderTargetMask(), slot) != 0 &&
ctx->GetRenderTarget(slot).base.addr != 0)) { ctx.GetRenderTarget(slot).base.addr != 0)) {
ResolveRenderColorTarget(submit_id, buffer, *ctx, ResolveRenderColorTarget(submit_id, buffer, state.color_info[state.color_count],
&state->color_info[state->color_count],
render_target_slice_offset, slot); render_target_slice_offset, slot);
if (state->color_info[state->color_count].vulkan_buffer != nullptr) { if (state.color_info[state.color_count].vulkan_buffer != nullptr) {
MarkRenderTargetGpuWritten(state->color_info[state->color_count]); MarkRenderTargetGpuWritten(state.color_info[state.color_count]);
state->color_count++; state.color_count++;
} }
} }
} }
const bool with_depth = (state->depth_info.format != vk::Format::eUndefined && const bool with_depth = (state.depth_info.format != vk::Format::eUndefined &&
state->depth_info.vulkan_buffer != nullptr); state.depth_info.vulkan_buffer != nullptr);
if (state->color_count == 0 && !with_depth) { if (state.color_count == 0 && !with_depth) {
LogFramebufferSkip(draw.name, state->color_info[0], state->depth_info, ctx, ucfg, LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer,
draw.index_count, draw.flags); draw.index_count, draw.flags);
return false; return false;
} }
state->ps_active = DrawHasActivePixelShader(ctx, sh_ctx, *state, draw); state.ps_active = DrawHasActivePixelShader(buffer, state, draw);
if (log_setup_phases) { if (log_setup_phases) {
LogDrawPhase(draw.name, "CreateFramebuffer"); LogDrawPhase(draw.name, "CreateFramebuffer");
} }
state->framebuffer = g_render_ctx->GetFramebufferCache()->CreateFramebuffer( state.framebuffer = GetRenderContext().GetFramebufferCache().CreateFramebuffer(
state->color_info, state->color_count, &state->depth_info); state.color_info, state.color_count, state.depth_info);
if (state->framebuffer == nullptr && skip_null_framebuffer) { if (state.framebuffer == nullptr && skip_null_framebuffer) {
LogFramebufferSkip(draw.name, state->color_info[0], state->depth_info, ctx, ucfg, LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer,
draw.index_count, draw.flags); draw.index_count, draw.flags);
return false; return false;
} }
EXIT_NOT_IMPLEMENTED(state->framebuffer == nullptr); EXIT_NOT_IMPLEMENTED(state.framebuffer == nullptr);
EXIT_NOT_IMPLEMENTED(state->framebuffer->render_pass == nullptr); EXIT_NOT_IMPLEMENTED(state.framebuffer->render_pass == nullptr);
state->vk_buffer = buffer->Handle(); state.vk_buffer = buffer.Handle();
return true; return true;
} }
static void RefreshShaders(HW::Context* ctx, HW::Shader* sh_ctx, const DrawCallInfo& draw, static void RefreshShaders(RenderCommandBuffer& buffer, const DrawCallInfo& draw, bool log_phases,
bool log_phases, DrawRenderState* state) { DrawRenderState& state) {
EXIT_IF(ctx == nullptr);
EXIT_IF(sh_ctx == nullptr);
EXIT_IF(draw.name == nullptr); 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& vertex_shader_info = sh_ctx.GetVs();
const auto& pixel_shader_info = sh_ctx->GetPs(); const auto& pixel_shader_info = sh_ctx.GetPs();
const auto& shader_regs = ctx->GetShaderRegisters(); const auto& shader_regs = ctx.GetShaderRegisters();
state->vs_shader = {}; state.vs_shader = {};
state->ps_shader = {}; state.ps_shader = {};
state->ps_input_info = {}; state.ps_input_info = {};
std::array<Prospero::ColorComponentMapping, RENDER_COLOR_ATTACHMENTS_MAX> std::array<Prospero::ColorComponentMapping, RENDER_COLOR_ATTACHMENTS_MAX>
target_export_mapping {}; target_export_mapping {};
for (uint32_t i = 0; i < state->color_count; i++) { for (uint32_t i = 0; i < state.color_count; i++) {
target_export_mapping[state->color_info[i].target_slot] = target_export_mapping[state.color_info[i].target_slot] = state.color_info[i].export_mapping;
state->color_info[i].export_mapping;
} }
EXIT_IF(g_render_ctx == nullptr || g_render_ctx->GetGraphicCtx() == nullptr); const auto lane_mask_mode = SelectGraphicsLaneMaskMode(64u);
const auto lane_mask_mode = SelectGraphicsLaneMaskMode(*g_render_ctx->GetGraphicCtx(), 64u);
if (log_phases) { if (log_phases) {
LogDrawPhase(draw.name, "ShaderCompileInfoVS"); LogDrawPhase(draw.name, "ShaderCompileInfoVS");
} }
if (!ShaderCompileInfoVS(&vertex_shader_info, &shader_regs, lane_mask_mode, if (!ShaderCompileInfoVS(vertex_shader_info, shader_regs, lane_mask_mode, state.vs_input_info,
&state->vs_input_info, &state->vs_shader)) { state.vs_shader)) {
EXIT("ShaderCompileInfoVS failed for draw %s\n", draw.name); EXIT("ShaderCompileInfoVS failed for draw %s\n", draw.name);
} }
if (!state->ps_active) { if (!state.ps_active) {
return; return;
} }
if (log_phases) { if (log_phases) {
LogDrawPhase(draw.name, "ShaderCompileInfoPS"); LogDrawPhase(draw.name, "ShaderCompileInfoPS");
} }
if (!ShaderCompileInfoPS(&pixel_shader_info, &shader_regs, lane_mask_mode, if (!ShaderCompileInfoPS(pixel_shader_info, shader_regs, lane_mask_mode, state.vs_input_info,
&state->vs_input_info, target_export_mapping, &state->ps_input_info, target_export_mapping, state.ps_input_info, state.ps_shader)) {
&state->ps_shader)) {
EXIT("ShaderCompileInfoPS failed for draw %s\n", draw.name); 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 DrawCallInfo& draw, vk::CommandBuffer vk_buffer,
const ShaderVertexInputInfo& vs_input_info) { const ShaderVertexInputInfo& vs_input_info) {
EXIT_IF(buffer == nullptr);
EXIT_IF(draw.name == nullptr); EXIT_IF(draw.name == nullptr);
(void)submit_id; (void)submit_id;
@@ -752,13 +732,11 @@ static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer,
vk::DeviceSize offset = 0; vk::DeviceSize offset = 0;
if (size == 0) { if (size == 0) {
vertices = g_render_ctx->GetBufferCache()->ObtainNullBuffer( vertices = &GetRenderContext().GetBufferCache().ObtainNullBuffer(buffer);
buffer, g_render_ctx->GetGraphicCtx());
} else { } else {
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer( auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(buffer, addr, size);
buffer, g_render_ctx->GetGraphicCtx(), addr, size); vertices = &binding.buffer;
vertices = binding.first; offset = binding.offset;
offset = binding.second;
} }
EXIT_NOT_IMPLEMENTED(vertices == nullptr); 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) { const DrawIndexBufferSource& source) {
if (!source.enabled) { if (!source.enabled) {
return; return;
@@ -777,27 +755,24 @@ static void BindDrawIndexBuffer(CommandBuffer* buffer, vk::CommandBuffer vk_buff
vk::DeviceSize index_offset = 0; vk::DeviceSize index_offset = 0;
if (source.host_data != nullptr) { if (source.host_data != nullptr) {
vk::DeviceSize range = 0; vk::DeviceSize range = 0;
if (!g_render_ctx->GetBufferCache()->UploadHostData(buffer, g_render_ctx->GetGraphicCtx(), if (!GetRenderContext().GetBufferCache().UploadHostData(
source.host_data, source.size, 16, buffer, source.host_data, source.size, 16, index_buffer, index_offset, range)) {
&index_buffer, &index_offset, &range)) {
EXIT("failed to upload host index buffer\n"); EXIT("failed to upload host index buffer\n");
} }
} else { } else {
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer( auto binding =
buffer, g_render_ctx->GetGraphicCtx(), source.address, source.size); GetRenderContext().GetBufferCache().ObtainBuffer(buffer, source.address, source.size);
index_buffer = binding.first; index_buffer = &binding.buffer;
index_offset = binding.second; index_offset = binding.offset;
} }
EXIT_IF(index_buffer == nullptr); EXIT_IF(index_buffer == nullptr);
vk_buffer.bindIndexBuffer(index_buffer->buffer, index_offset, source.type); 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, const DrawRenderState& state, bool always_log,
bool force_legacy_rect_log, uint32_t index_type_and_size, bool force_legacy_rect_log, uint32_t index_type_and_size,
const void* index_addr) { const void* index_addr) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(draw.name == nullptr); EXIT_IF(draw.name == nullptr);
if (!graphics_debug_dump_enabled()) { if (!graphics_debug_dump_enabled()) {
@@ -809,7 +784,7 @@ static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const D
} }
if (state.ps_active) { 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); state.ps_input_info, draw.index_count, draw.flags);
} }
LogDrawInputState(state.color_info[0], state.vs_input_info, index_type_and_size, 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; 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 ShaderVertexInputInfo& vs_input_info, const DrawCallInfo& draw,
const DrawEmitInfo& emit) { const DrawEmitInfo& emit) {
EXIT_IF(ucfg == nullptr);
EXIT_IF(draw.name == nullptr); EXIT_IF(draw.name == nullptr);
switch (static_cast<Prospero::PrimitiveType>(ucfg->GetPrimType())) { switch (static_cast<Prospero::PrimitiveType>(ucfg.GetPrimType())) {
case Prospero::PrimitiveType::kPointList: case Prospero::PrimitiveType::kPointList:
case Prospero::PrimitiveType::kLineList: case Prospero::PrimitiveType::kLineList:
case Prospero::PrimitiveType::kLineStrip: case Prospero::PrimitiveType::kLineStrip:
@@ -865,7 +839,7 @@ static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_
break; break;
case Prospero::PrimitiveType::kRectListLegacy: case Prospero::PrimitiveType::kRectListLegacy:
if (emit.indexed) { if (emit.indexed) {
EXIT("unknown primitive type: %u\n", ucfg->GetPrimType()); EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
} }
// Sarah // Sarah
EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0)); 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; 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, static void ExecutePreparedDraw(uint64_t submit_id, RenderCommandBuffer& buffer,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, const DrawCallInfo& draw, const DrawCallInfo& draw, DrawRenderState& state,
DrawRenderState* state, vk::PrimitiveTopology topology, vk::PrimitiveTopology topology, const DrawEmitInfo& emit,
const DrawEmitInfo& emit, const DrawIndexBufferSource& index_source, const DrawIndexBufferSource& index_source, bool log_pipeline_phase,
bool log_pipeline_phase, bool set_bind_debug, bool set_auto_debug) { 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);
EXIT_IF(draw.name == nullptr); EXIT_IF(draw.name == nullptr);
EXIT_IF(state == nullptr); auto& ucfg = buffer.GetUserConfig();
for (;;) { for (;;) {
const auto recording_generation = buffer->GetRecordingGeneration(); const auto recording_generation = buffer.GetRecordingGeneration();
if (log_pipeline_phase) { if (log_pipeline_phase) {
LogDrawPhase(draw.name, "CreatePipeline"); LogDrawPhase(draw.name, "CreatePipeline");
} }
auto* pipeline = g_render_ctx->GetPipelineCache()->CreateGraphicsPipeline( auto& pipeline = GetRenderContext().GetPipelineCache().CreateGraphicsPipeline(
state->framebuffer, state->color_info, state->color_count, &state->depth_info, *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_input_info, buffer, &state.ps_input_info, topology, state.ps_active,
state->vs_shader, state->ps_shader); state.vs_shader, state.ps_shader);
if (set_bind_debug) { if (set_bind_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x100u); SetDrawDebugPhase(buffer, submit_id, draw, 0x100u);
} }
state->vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline->pipeline); state.vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.pipeline);
const auto dynamic_params = BuildGraphicsDynamicParams( const auto dynamic_params = BuildGraphicsDynamicParams(buffer, state.color_info,
*ctx, state->color_info, state->color_count, state->depth_info); state.color_count, state.depth_info);
SetDynamicParams(state->vk_buffer, dynamic_params); SetDynamicParams(buffer, state.vk_buffer, dynamic_params);
// EXIT_NOT_IMPLEMENTED(vs_input_info.buffers_num > 1); // 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"); LogDrawPhase(draw.name, "BindDescriptorsVS");
if (set_auto_debug) { if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x200u); SetDrawDebugPhase(buffer, submit_id, draw, 0x200u);
} }
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, 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); vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex);
if (state->ps_active) { if (state.ps_active) {
LogDrawPhase(draw.name, "BindDescriptorsPS"); LogDrawPhase(draw.name, "BindDescriptorsPS");
if (set_auto_debug) { if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x300u); SetDrawDebugPhase(buffer, submit_id, draw, 0x300u);
} }
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, 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); vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel);
} }
if (buffer->GetRecordingGeneration() != recording_generation) { if (buffer.GetRecordingGeneration() != recording_generation) {
continue; continue;
} }
// Index data may use this command buffer's host stream. Resolve it only after the other // 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. // fault-capable bindings, and rebuild it whenever a fault reset changes the generation.
BindDrawIndexBuffer(buffer, state->vk_buffer, index_source); BindDrawIndexBuffer(buffer, state.vk_buffer, index_source);
if (buffer->GetRecordingGeneration() != recording_generation) { if (buffer.GetRecordingGeneration() != recording_generation) {
continue; continue;
} }
@@ -951,29 +921,29 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
if (set_auto_debug) { if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x400u); SetDrawDebugPhase(buffer, submit_id, draw, 0x400u);
} }
buffer->BeginRenderPass(state->framebuffer, state->color_info, state->color_count, buffer.BeginRenderPass(*state.framebuffer, state.color_info, state.color_count,
&state->depth_info); state.depth_info);
if (set_auto_debug) { if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x500u); 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) { if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x600u); SetDrawDebugPhase(buffer, submit_id, draw, 0x600u);
} }
buffer->EndRenderPass(); buffer.EndRenderPass();
vk::PipelineStageFlags shader_write_stages = {}; 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; shader_write_stages |= vk::PipelineStageFlagBits::eVertexShader;
} }
if (state->ps_active) { if (state.ps_active) {
if (HasShaderBufferWrites(state->ps_input_info.stage)) { if (HasShaderBufferWrites(state.ps_input_info.stage)) {
shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader; shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader;
} }
} }
if (shader_write_stages) { if (shader_write_stages) {
ShaderWriteBarrier(state->vk_buffer, shader_write_stages); ShaderWriteBarrier(state.vk_buffer, shader_write_stages);
} }
LogDrawPhase(draw.name, "EndRenderPass"); LogDrawPhase(draw.name, "EndRenderPass");
if (set_auto_debug) { 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, void RenderDrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_type_and_size,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_type_and_size,
uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type, uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
uint32_t instance_count, uint32_t render_target_slice_offset, uint32_t instance_count, uint32_t render_target_slice_offset,
int32_t vertex_offset_add, uint32_t first_instance) { int32_t vertex_offset_add, uint32_t first_instance) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr); EXIT_IF(buffer.IsInvalid());
EXIT_IF(ucfg == nullptr); auto& ucfg = buffer.GetUserConfig();
EXIT_IF(g_render_ctx == nullptr); auto& sh_ctx = buffer.GetShaders();
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndex), submit_id, buffer.SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndex), submit_id,
index_count, flags, type, instance_count, index_count, flags, type, instance_count,
reinterpret_cast<uint64_t>(index_addr)); reinterpret_cast<uint64_t>(index_addr));
Common::LockGuard lock(g_render_ctx->GetMutex()); Common::LockGuard lock(GetRenderContext().GetMutex());
if (index_count == 0) { if (index_count == 0) {
return; return;
} }
if (ConsumeMetadataColorOperation(*ctx)) { if (ConsumeMetadataColorOperation(buffer)) {
return; return;
} }
@@ -1014,14 +981,14 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
return; return;
} }
if (ShouldSkipGeShader(ctx, ucfg, sh_ctx)) { if (ShouldSkipGeShader(buffer)) {
return; return;
} }
if (graphics_debug_dump_enabled()) { if (graphics_debug_dump_enabled()) {
sh_print("GraphicsRenderDrawIndex():Shader:", *sh_ctx); sh_print("GraphicsRenderDrawIndex():Shader:", sh_ctx);
uc_print("GraphicsRenderDrawIndex():UserConfig:", *ucfg); uc_print("GraphicsRenderDrawIndex():UserConfig:", ucfg);
hw_print(*ctx); hw_print(buffer);
LOGF("GraphicsRenderDrawIndex():Parameters:\n" LOGF("GraphicsRenderDrawIndex():Parameters:\n"
"\t index_type_and_size = 0x%08" PRIx32 "\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<uint32_t>(vertex_offset_add), instance_count, render_target_slice_offset, static_cast<uint32_t>(vertex_offset_add),
first_instance); 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; vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
if (!GetDrawTopology(ucfg, false, false, &topology)) { if (!GetDrawTopology(ucfg, false, false, topology)) {
return; return;
} }
@@ -1099,47 +1066,46 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
index_source.type = index_type; index_source.type = index_type;
DrawRenderState state {}; DrawRenderState state {};
if (!PrepareDrawRenderState(submit_id, buffer, ctx, ucfg, sh_ctx, draw, if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, false, true,
render_target_slice_offset, false, true, &state)) { state)) {
return; 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 = 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 {}; DrawEmitInfo emit {};
emit.indexed = true; emit.indexed = true;
emit.vertex_offset = vertex_offset; emit.vertex_offset = vertex_offset;
ExecutePreparedDraw(submit_id, buffer, ctx, ucfg, sh_ctx, draw, &state, topology, emit, ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, true, true,
index_source, true, true, false); false);
} }
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx, void RenderDrawIndexAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_count,
uint32_t flags, uint32_t render_target_slice_offset, uint32_t flags, uint32_t render_target_slice_offset,
uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance) { uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ucfg == nullptr); EXIT_IF(buffer.IsInvalid());
EXIT_IF(g_render_ctx == nullptr); auto& ucfg = buffer.GetUserConfig();
EXIT_IF(buffer == nullptr || buffer->IsInvalid()); auto& sh_ctx = buffer.GetShaders();
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndexAuto), submit_id, buffer.SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndexAuto), submit_id,
index_count, flags, first_vertex, instance_count, first_instance); 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) { if (index_count == 0) {
return; return;
} }
if (ConsumeMetadataColorOperation(*ctx)) { if (ConsumeMetadataColorOperation(buffer)) {
return; return;
} }
@@ -1147,14 +1113,14 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
return; return;
} }
if (ShouldSkipGeShader(ctx, ucfg, sh_ctx)) { if (ShouldSkipGeShader(buffer)) {
return; return;
} }
if (graphics_debug_dump_enabled()) { if (graphics_debug_dump_enabled()) {
sh_print("GraphicsRenderDrawIndexAuto():Shader:", *sh_ctx); sh_print("GraphicsRenderDrawIndexAuto():Shader:", sh_ctx);
uc_print("GraphicsRenderDrawIndexAuto():UserConfig:", *ucfg); uc_print("GraphicsRenderDrawIndexAuto():UserConfig:", ucfg);
hw_print(*ctx); hw_print(buffer);
LOGF("GraphicsRenderDrawIndexAuto():Parameters:\n" LOGF("GraphicsRenderDrawIndexAuto():Parameters:\n"
"\t index_count = 0x%08" PRIx32 "\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, index_count, flags, render_target_slice_offset, instance_count, first_vertex,
first_instance); 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); EXIT_NOT_IMPLEMENTED(flags != 0);
if (instance_count == 0) { if (instance_count == 0) {
@@ -1182,41 +1148,41 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
instance_count, first_instance}; instance_count, first_instance};
DrawRenderState state {}; DrawRenderState state {};
if (!PrepareDrawRenderState(submit_id, buffer, ctx, ucfg, sh_ctx, draw, if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, true, false,
render_target_slice_offset, true, false, &state)) { state)) {
return; return;
} }
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList; vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
const bool use_ngg_rectlist_draw = Config::NggRectlistDrawEnabled(); 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; return;
} }
const bool draw_prim7_as_ngg = const bool draw_prim7_as_ngg =
(use_ngg_rectlist_draw && (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 && 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) { state.vs_input_info.param_export_mask == 0 && state.ps_input_info.input_num != 0) {
if (graphics_debug_dump_enabled()) { if (graphics_debug_dump_enabled()) {
LOGF("DrawIndexAuto: skipping rect-list draw with no VS param exports and PS inputs: " 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", "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, 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); sh_ctx.GetVs().es_regs.data_addr, sh_ctx.GetVs().gs_regs.data_addr);
} }
return; return;
} }
LogDrawStateIfNeeded(ctx, ucfg, draw, state, false, LogDrawStateIfNeeded(buffer, draw, state, false,
ucfg->GetPrimType() == ucfg.GetPrimType() ==
Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectListLegacy), Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectListLegacy),
0, nullptr); 0, nullptr);
const uint32_t draw_vertex_count = (draw_prim7_as_ngg ? 4u : index_count); const uint32_t draw_vertex_count = (draw_prim7_as_ngg ? 4u : index_count);
const auto vertex_offset = ResolveVertexOffset(ucfg->GetIndexOffset(), state.vs_input_info) + const auto vertex_offset = ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) +
static_cast<int32_t>(first_vertex); static_cast<int32_t>(first_vertex);
DrawEmitInfo emit {}; DrawEmitInfo emit {};
emit.draw_prim7_as_ngg = draw_prim7_as_ngg; emit.draw_prim7_as_ngg = draw_prim7_as_ngg;
@@ -1224,8 +1190,8 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
emit.first_vertex = static_cast<uint32_t>(vertex_offset); emit.first_vertex = static_cast<uint32_t>(vertex_offset);
DrawIndexBufferSource index_source {}; DrawIndexBufferSource index_source {};
ExecutePreparedDraw(submit_id, buffer, ctx, ucfg, sh_ctx, draw, &state, topology, emit, ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, false, false,
index_source, false, false, true); true);
} }
bool IsSameColorResolveSubresource(const RenderColorInfo& src, const RenderColorInfo& dst) { 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, ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColorInfo& dst,
uint32_t width, uint32_t height) { uint32_t width, uint32_t height) {
ImageImageCopy region {}; ImageImageCopy region {*src.vulkan_buffer};
region.src_image = src.vulkan_buffer;
region.src_level = src.base_mip_level; region.src_level = src.base_mip_level;
region.dst_level = dst.base_mip_level; region.dst_level = dst.base_mip_level;
region.width = width; region.width = width;
@@ -1246,8 +1211,9 @@ ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColo
return region; 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) { uint32_t render_target_slice_offset) {
const auto& hw = buffer.GetRegisters();
if (hw.GetColorControl().mode != 3) { if (hw.GetColorControl().mode != 3) {
return false; return false;
} }
@@ -1260,9 +1226,8 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const
RenderColorInfo src {}; RenderColorInfo src {};
RenderColorInfo dst {}; RenderColorInfo dst {};
ResolveRenderColorTarget(submit_id, buffer, hw, &src, render_target_slice_offset, 0, true, ResolveRenderColorTarget(submit_id, buffer, src, render_target_slice_offset, 0, true, true);
true); ResolveRenderColorTarget(submit_id, buffer, dst, render_target_slice_offset, 1, true);
ResolveRenderColorTarget(submit_id, buffer, hw, &dst, render_target_slice_offset, 1, true);
if (src.vulkan_buffer == nullptr || dst.vulkan_buffer == nullptr || if (src.vulkan_buffer == nullptr || dst.vulkan_buffer == nullptr ||
src.type == RenderColorType::NoColorOutput || dst.type == RenderColorType::NoColorOutput) { src.type == RenderColorType::NoColorOutput || dst.type == RenderColorType::NoColorOutput) {
return false; 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)}; const std::array regions {MakeColorResolveCopy(src, dst, width, height)};
MarkRenderTargetGpuWritten(dst); 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; return true;
} }
@@ -28,13 +28,12 @@
namespace Libs::Graphics { namespace Libs::Graphics {
void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) { void GraphicsRenderMemoryBarrier(CommandBuffer& buffer) {
EXIT_IF(buffer == nullptr); EXIT_IF(buffer.IsInvalid());
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 {}; VulkanMemoryBarrier mem_barrier {};
mem_barrier.sType = vk::StructureType::eMemoryBarrier; mem_barrier.sType = vk::StructureType::eMemoryBarrier;
@@ -47,8 +46,7 @@ void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) {
&mem_barrier, 0, nullptr, 0, nullptr); &mem_barrier, 0, nullptr, 0, nullptr);
} }
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image) { void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) {
EXIT_IF(image == nullptr);
vk::ImageMemoryBarrier image_memory_barrier {}; vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; 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::eColorAttachmentWrite | vk::AccessFlagBits::eTransferWrite |
vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryRead; vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryRead;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; 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.newLayout = RENDER_COLOR_IMAGE_LAYOUT;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = 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.aspectMask = vk::ImageAspectFlagBits::eColor;
image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers; image_memory_barrier.subresourceRange.layerCount = image.layers;
vk_buffer.pipelineBarrier( vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eColorAttachmentOutput |
@@ -76,21 +74,19 @@ void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* imag
vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); 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) { vk::ImageLayout new_layout) {
EXIT_IF(image == nullptr); if (image.layout != new_layout) {
if (image.type == VulkanImageType::VideoOut &&
if (image->layout != new_layout) { image.layout == vk::ImageLayout::eTransferDstOptimal) {
if (image->type == VulkanImageType::VideoOut &&
image->layout == vk::ImageLayout::eTransferDstOptimal) {
static std::atomic<uint32_t> log_count {0}; static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 128) { if (log_count.fetch_add(1, std::memory_order_relaxed) < 128) {
LOGF("GraphicsRenderColorImageBarrier: image=%p type=%d layout=%s -> %s\n", LOGF("GraphicsRenderColorImageBarrier: image=%p type=%d layout=%s -> %s\n",
VulkanHandleToPointer(image->image), static_cast<int>(image->type), VulkanHandleToPointer(image.image), static_cast<int>(image.type),
VulkanToString(image->layout).c_str(), VulkanToString(new_layout).c_str()); VulkanToString(image.layout).c_str(), VulkanToString(new_layout).c_str());
} }
} }
vk::ImageMemoryBarrier image_memory_barrier {}; vk::ImageMemoryBarrier image_memory_barrier {};
@@ -100,16 +96,16 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i
vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead; vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead;
image_memory_barrier.dstAccessMask = image_memory_barrier.dstAccessMask =
vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead; 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.newLayout = new_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = 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.aspectMask = vk::ImageAspectFlagBits::eColor;
image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0; 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::PipelineStageFlags>( const auto stages = static_cast<vk::PipelineStageFlags>(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | 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, vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1,
&image_memory_barrier); &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) { 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 || if (new_layout == vk::ImageLayout::eUndefined ||
new_layout == vk::ImageLayout::ePreinitialized) { new_layout == vk::ImageLayout::ePreinitialized) {
EXIT("invalid destination depth/stencil image layout: %s\n", EXIT("invalid destination depth/stencil image layout: %s\n",
VulkanToString(new_layout).c_str()); VulkanToString(new_layout).c_str());
} }
if (image->layout == new_layout) { if (image.layout == new_layout) {
return; return;
} }
vk::ImageMemoryBarrier barrier {}; vk::ImageMemoryBarrier barrier {};
barrier.sType = vk::StructureType::eImageMemoryBarrier; barrier.sType = vk::StructureType::eImageMemoryBarrier;
barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
barrier.dstAccessMask = 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.newLayout = new_layout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image->image; barrier.image = image.image;
barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image->format), 0, barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image.format), 0,
VK_REMAINING_MIP_LEVELS, 0, image->layers}; VK_REMAINING_MIP_LEVELS, 0, image.layers};
const auto stages = static_cast<vk::PipelineStageFlags>( const auto stages = static_cast<vk::PipelineStageFlags>(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1,
&barrier); &barrier);
image->layout = new_layout; image.layout = new_layout;
} }
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image) { void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) {
EXIT_IF(image == nullptr); EXIT_IF(image.type != VulkanImageType::DepthStencil);
EXIT_IF(image->type != VulkanImageType::DepthStencil); auto& depth = static_cast<DepthStencilVulkanImage&>(image);
if (depth.compressed) {
auto* depth = static_cast<DepthStencilVulkanImage*>(image);
if (depth->compressed) {
static std::atomic<uint32_t> log_count {0}; static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF( LOGF(
"DepthTexture: decompressing depth target for shader read format=%s extent=%ux%u\n", "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 {}; vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier;
image_memory_barrier.pNext = nullptr; image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = image_memory_barrier.srcAccessMask =
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; 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.newLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = 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 = image_memory_barrier.subresourceRange.aspectMask =
ImageViewOps::DepthAspectMask(image->format); ImageViewOps::DepthAspectMask(image.format);
image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers; image_memory_barrier.subresourceRange.layerCount = image.layers;
vk_buffer.pipelineBarrier( vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
@@ -194,37 +187,35 @@ void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage*
vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); 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) { void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer == nullptr); EXIT_IF(buffer.IsInvalid());
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) { if (native == nullptr) {
EXIT("render-target barrier range has no cached image\n"); 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) { void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer == nullptr); EXIT_IF(buffer.IsInvalid());
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()->FindDepthTargetByRange(buffer, vaddr, size); auto* native = GetRenderContext().GetTextureCache().FindDepthTargetByRange(buffer, vaddr, size);
if (native == nullptr) { if (native == nullptr) {
EXIT("depth-target barrier range has no cached image\n"); EXIT("depth-target barrier range has no cached image\n");
} }
GraphicsRenderDepthStencilBarrier(vk_buffer, native); GraphicsRenderDepthStencilBarrier(vk_buffer, *native);
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -7,12 +7,12 @@ namespace Libs::Graphics {
struct VulkanImage; struct VulkanImage;
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image); void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image);
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image, void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout); vk::ImageLayout new_layout);
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image, void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout); vk::ImageLayout new_layout);
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image); void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image);
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -143,8 +143,7 @@ vk::Sampler SamplerCache::GetSampler(const ShaderSamplerResource& r) {
} }
vk::Sampler vk_sampler = nullptr; vk::Sampler vk_sampler = nullptr;
const auto result = const auto result = m_graphics.device.createSampler(&sampler_info, nullptr, &vk_sampler);
g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || vk_sampler == nullptr); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || vk_sampler == nullptr);
m_samplers.emplace(key, vk_sampler); m_samplers.emplace(key, vk_sampler);
@@ -14,9 +14,13 @@
namespace Libs::Graphics { namespace Libs::Graphics {
struct GraphicContext;
class SamplerCache { class SamplerCache {
public: 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; } ~SamplerCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(SamplerCache); KYTY_CLASS_NO_COPY(SamplerCache);
@@ -37,6 +41,7 @@ private:
} }
}; };
GraphicContext& m_graphics;
Common::Mutex m_mutex; Common::Mutex m_mutex;
std::unordered_map<SamplerKey, vk::Sampler, SamplerKeyHash> m_samplers; std::unordered_map<SamplerKey, vk::Sampler, SamplerKeyHash> m_samplers;
}; };
@@ -4,8 +4,13 @@
namespace Libs::Graphics { namespace Libs::Graphics {
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context, ShaderSubgroupCapabilities::ShaderSubgroupCapabilities(const GraphicContext& graphics)
uint32_t guest_wave_size) { : 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 // 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 // GCN's. AMD RDNA also reports a 64-wide subgroup but uses a different
// lane/pixel layout, which corrupted rendering under "native wave" mode. // lane/pixel layout, which corrupted rendering under "native wave" mode.
@@ -16,7 +21,7 @@ ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context,
return ShaderLaneMaskMode::NativeWave; return ShaderLaneMaskMode::NativeWave;
} }
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& context, ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabilities& capabilities,
vk::ShaderStageFlagBits stage, vk::ShaderStageFlagBits stage,
const ShaderRecompiler::IR::Program& program) { const ShaderRecompiler::IR::Program& program) {
const auto guest_wave_size = program.wave_size; const auto guest_wave_size = program.wave_size;
@@ -24,8 +29,8 @@ ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext&
return {}; return {};
} }
if (stage != vk::ShaderStageFlagBits::eCompute) { if (stage != vk::ShaderStageFlagBits::eCompute) {
const auto expected = SelectGraphicsLaneMaskMode(context, guest_wave_size); const auto expected = SelectGraphicsLaneMaskMode(guest_wave_size);
if (program.lane_mask_mode != expected || (context.subgroup_size != guest_wave_size && if (program.lane_mask_mode != expected || (capabilities.subgroup_size != guest_wave_size &&
expected != ShaderLaneMaskMode::PerInvocation)) { expected != ShaderLaneMaskMode::PerInvocation)) {
return {}; return {};
} }
@@ -37,12 +42,13 @@ ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext&
if (program.lane_mask_mode != ShaderLaneMaskMode::NativeWave) { if (program.lane_mask_mode != ShaderLaneMaskMode::NativeWave) {
return {}; return {};
} }
if (context.subgroup_size == guest_wave_size) { if (capabilities.subgroup_size == guest_wave_size) {
return {ShaderSubgroupMode::Natural, 0}; return {ShaderSubgroupMode::Natural, 0};
} }
if (context.subgroup_size_control_enabled && (context.required_subgroup_size_stages & stage) && if (capabilities.subgroup_size_control_enabled &&
guest_wave_size >= context.min_subgroup_size && (capabilities.required_subgroup_size_stages & stage) &&
guest_wave_size <= context.max_subgroup_size) { guest_wave_size >= capabilities.min_subgroup_size &&
guest_wave_size <= capabilities.max_subgroup_size) {
return {ShaderSubgroupMode::Controlled, guest_wave_size}; return {ShaderSubgroupMode::Controlled, guest_wave_size};
} }
if (!ShaderRecompiler::Spirv::ProgramRequiresExactSubgroupSize(program)) { if (!ShaderRecompiler::Spirv::ProgramRequiresExactSubgroupSize(program)) {
@@ -19,10 +19,19 @@ struct ShaderSubgroupConfiguration {
uint32_t required_size = 0; uint32_t required_size = 0;
}; };
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context, struct ShaderSubgroupCapabilities {
uint32_t guest_wave_size); explicit ShaderSubgroupCapabilities(const GraphicContext& graphics);
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& context, 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, vk::ShaderStageFlagBits stage,
const ShaderRecompiler::IR::Program& program); const ShaderRecompiler::IR::Program& program);
+227 -246
View File
@@ -25,62 +25,59 @@ namespace Libs::Graphics {
// IDK: maybe we can remove it? // IDK: maybe we can remove it?
constexpr uint32_t kTemporaryPs5BufferFormat121 = 121u; constexpr uint32_t kTemporaryPs5BufferFormat121 = 121u;
static bool NarrowInputFormat(vk::Format* format, uint32_t* size, uint32_t used_components) { static bool NarrowInputFormat(vk::Format& format, uint32_t& size, uint32_t used_components) {
EXIT_IF(format == nullptr); if (used_components == 0 || used_components >= size) {
EXIT_IF(size == nullptr);
if (used_components == 0 || used_components >= *size) {
return false; return false;
} }
switch (*format) { switch (format) {
case vk::Format::eR32G32B32A32Sfloat: case vk::Format::eR32G32B32A32Sfloat:
switch (used_components) { switch (used_components) {
case 1: *format = vk::Format::eR32Sfloat; break; case 1: format = vk::Format::eR32Sfloat; break;
case 2: *format = vk::Format::eR32G32Sfloat; break; case 2: format = vk::Format::eR32G32Sfloat; break;
case 3: *format = vk::Format::eR32G32B32Sfloat; break; case 3: format = vk::Format::eR32G32B32Sfloat; break;
default: return false; default: return false;
} }
*size = used_components; size = used_components;
return true; return true;
case vk::Format::eR32G32B32Sfloat: case vk::Format::eR32G32B32Sfloat:
switch (used_components) { switch (used_components) {
case 1: *format = vk::Format::eR32Sfloat; break; case 1: format = vk::Format::eR32Sfloat; break;
case 2: *format = vk::Format::eR32G32Sfloat; break; case 2: format = vk::Format::eR32G32Sfloat; break;
default: return false; default: return false;
} }
*size = used_components; size = used_components;
return true; return true;
case vk::Format::eR16G16B16A16Sfloat: case vk::Format::eR16G16B16A16Sfloat:
switch (used_components) { switch (used_components) {
case 1: *format = vk::Format::eR16Sfloat; break; case 1: format = vk::Format::eR16Sfloat; break;
case 2: *format = vk::Format::eR16G16Sfloat; break; case 2: format = vk::Format::eR16G16Sfloat; break;
default: return false; default: return false;
} }
*size = used_components; size = used_components;
return true; return true;
case vk::Format::eR8G8B8A8Unorm: case vk::Format::eR8G8B8A8Unorm:
switch (used_components) { switch (used_components) {
case 1: *format = vk::Format::eR8Unorm; break; case 1: format = vk::Format::eR8Unorm; break;
case 2: *format = vk::Format::eR8G8Unorm; break; case 2: format = vk::Format::eR8G8Unorm; break;
default: return false; default: return false;
} }
*size = used_components; size = used_components;
return true; return true;
case vk::Format::eR8G8B8A8Snorm: case vk::Format::eR8G8B8A8Snorm:
if (used_components != 2) { if (used_components != 2) {
return false; return false;
} }
*format = vk::Format::eR8G8Snorm; format = vk::Format::eR8G8Snorm;
*size = 2; size = 2;
return true; return true;
case vk::Format::eR8G8B8A8Uint: case vk::Format::eR8G8B8A8Uint:
switch (used_components) { switch (used_components) {
case 1: *format = vk::Format::eR8Uint; break; case 1: format = vk::Format::eR8Uint; break;
case 2: *format = vk::Format::eR8G8Uint; break; case 2: format = vk::Format::eR8G8Uint; break;
default: return false; default: return false;
} }
*size = used_components; size = used_components;
return true; return true;
default: break; default: break;
} }
@@ -88,11 +85,8 @@ static bool NarrowInputFormat(vk::Format* format, uint32_t* size, uint32_t used_
return false; 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) { uint32_t used_components) {
EXIT_IF(format == nullptr);
EXIT_IF(size == nullptr);
auto fmt = res.Format(); auto fmt = res.Format();
if (fmt == Prospero::GpuEnumValue(Prospero::VertexAttribFormat::k16_16SInt)) { if (fmt == Prospero::GpuEnumValue(Prospero::VertexAttribFormat::k16_16SInt)) {
static bool logged_113 = false; static bool logged_113 = false;
@@ -101,11 +95,11 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format,
"vk::Format::eR32G32B32A32Sfloat\n"); "vk::Format::eR32G32B32A32Sfloat\n");
logged_113 = true; logged_113 = true;
} }
*format = vk::Format::eR32G32B32A32Sfloat; format = vk::Format::eR32G32B32A32Sfloat;
*size = 4; size = 4;
if (NarrowInputFormat(format, size, used_components)) { if (NarrowInputFormat(format, size, used_components)) {
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt, 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; 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"); LOGF("InputFormat: accepting PS5 buffer format 121 as vk::Format::eR16G16Sfloat\n");
logged_121 = true; logged_121 = true;
} }
*format = vk::Format::eR16G16Sfloat; format = vk::Format::eR16G16Sfloat;
*size = 2; size = 2;
if (NarrowInputFormat(format, size, used_components)) { if (NarrowInputFormat(format, size, used_components)) {
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt, 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; return;
} }
switch (static_cast<Prospero::BufferFormat>(fmt)) { switch (static_cast<Prospero::BufferFormat>(fmt)) {
case Prospero::BufferFormat::k32_32_32_32Float: case Prospero::BufferFormat::k32_32_32_32Float:
*format = vk::Format::eR32G32B32A32Sfloat; format = vk::Format::eR32G32B32A32Sfloat;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k32_32_32_32SInt: case Prospero::BufferFormat::k32_32_32_32SInt:
*format = vk::Format::eR32G32B32A32Sint; format = vk::Format::eR32G32B32A32Sint;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k32_32_32_32UInt: case Prospero::BufferFormat::k32_32_32_32UInt:
*format = vk::Format::eR32G32B32A32Uint; format = vk::Format::eR32G32B32A32Uint;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k32_32_32Float: case Prospero::BufferFormat::k32_32_32Float:
*format = vk::Format::eR32G32B32Sfloat; format = vk::Format::eR32G32B32Sfloat;
*size = 3; size = 3;
break; break;
case Prospero::BufferFormat::k32_32_32SInt: case Prospero::BufferFormat::k32_32_32SInt:
*format = vk::Format::eR32G32B32Sint; format = vk::Format::eR32G32B32Sint;
*size = 3; size = 3;
break; break;
case Prospero::BufferFormat::k32_32_32UInt: case Prospero::BufferFormat::k32_32_32UInt:
*format = vk::Format::eR32G32B32Uint; format = vk::Format::eR32G32B32Uint;
*size = 3; size = 3;
break; break;
case Prospero::BufferFormat::k16_16_16_16Float: case Prospero::BufferFormat::k16_16_16_16Float:
*format = vk::Format::eR16G16B16A16Sfloat; format = vk::Format::eR16G16B16A16Sfloat;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k16_16_16_16SInt: case Prospero::BufferFormat::k16_16_16_16SInt:
*format = vk::Format::eR16G16B16A16Sint; format = vk::Format::eR16G16B16A16Sint;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k16_16_16_16UInt: case Prospero::BufferFormat::k16_16_16_16UInt:
*format = vk::Format::eR16G16B16A16Uint; format = vk::Format::eR16G16B16A16Uint;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k16_16_16_16SScaled: case Prospero::BufferFormat::k16_16_16_16SScaled:
*format = vk::Format::eR16G16B16A16Sscaled; format = vk::Format::eR16G16B16A16Sscaled;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k16_16_16_16UScaled: case Prospero::BufferFormat::k16_16_16_16UScaled:
*format = vk::Format::eR16G16B16A16Uscaled; format = vk::Format::eR16G16B16A16Uscaled;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k16_16_16_16SNorm: case Prospero::BufferFormat::k16_16_16_16SNorm:
*format = vk::Format::eR16G16B16A16Snorm; format = vk::Format::eR16G16B16A16Snorm;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k16_16_16_16UNorm: case Prospero::BufferFormat::k16_16_16_16UNorm:
*format = vk::Format::eR16G16B16A16Unorm; format = vk::Format::eR16G16B16A16Unorm;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k32_32Float: case Prospero::BufferFormat::k32_32Float:
*format = vk::Format::eR32G32Sfloat; format = vk::Format::eR32G32Sfloat;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k32_32SInt: case Prospero::BufferFormat::k32_32SInt:
*format = vk::Format::eR32G32Sint; format = vk::Format::eR32G32Sint;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k32_32UInt: case Prospero::BufferFormat::k32_32UInt:
*format = vk::Format::eR32G32Uint; format = vk::Format::eR32G32Uint;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k8_8_8_8UInt: case Prospero::BufferFormat::k8_8_8_8UInt:
*format = vk::Format::eR8G8B8A8Uint; format = vk::Format::eR8G8B8A8Uint;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k8_8_8_8SScaled: case Prospero::BufferFormat::k8_8_8_8SScaled:
*format = vk::Format::eR8G8B8A8Sscaled; format = vk::Format::eR8G8B8A8Sscaled;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k8_8_8_8UScaled: case Prospero::BufferFormat::k8_8_8_8UScaled:
*format = vk::Format::eR8G8B8A8Uscaled; format = vk::Format::eR8G8B8A8Uscaled;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k8_8_8_8SNorm: case Prospero::BufferFormat::k8_8_8_8SNorm:
*format = vk::Format::eR8G8B8A8Snorm; format = vk::Format::eR8G8B8A8Snorm;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k8_8_8_8UNorm: case Prospero::BufferFormat::k8_8_8_8UNorm:
*format = vk::Format::eR8G8B8A8Unorm; format = vk::Format::eR8G8B8A8Unorm;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k10_10_10_2UNorm: case Prospero::BufferFormat::k10_10_10_2UNorm:
*format = vk::Format::eA2B10G10R10UnormPack32; format = vk::Format::eA2B10G10R10UnormPack32;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k10_10_10_2SNorm: case Prospero::BufferFormat::k10_10_10_2SNorm:
*format = vk::Format::eA2B10G10R10SnormPack32; format = vk::Format::eA2B10G10R10SnormPack32;
*size = 4; size = 4;
break; break;
case Prospero::BufferFormat::k16_16Float: case Prospero::BufferFormat::k16_16Float:
*format = vk::Format::eR16G16Sfloat; format = vk::Format::eR16G16Sfloat;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k16_16SInt: case Prospero::BufferFormat::k16_16SInt:
*format = vk::Format::eR16G16Sint; format = vk::Format::eR16G16Sint;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k16_16UInt: case Prospero::BufferFormat::k16_16UInt:
*format = vk::Format::eR16G16Uint; format = vk::Format::eR16G16Uint;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k16_16SScaled: case Prospero::BufferFormat::k16_16SScaled:
*format = vk::Format::eR16G16Sscaled; format = vk::Format::eR16G16Sscaled;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k16_16UScaled: case Prospero::BufferFormat::k16_16UScaled:
*format = vk::Format::eR16G16Uscaled; format = vk::Format::eR16G16Uscaled;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k16_16SNorm: case Prospero::BufferFormat::k16_16SNorm:
*format = vk::Format::eR16G16Snorm; format = vk::Format::eR16G16Snorm;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k16_16UNorm: case Prospero::BufferFormat::k16_16UNorm:
*format = vk::Format::eR16G16Unorm; format = vk::Format::eR16G16Unorm;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k32Float: case Prospero::BufferFormat::k32Float:
*format = vk::Format::eR32Sfloat; format = vk::Format::eR32Sfloat;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k32SInt: case Prospero::BufferFormat::k32SInt:
*format = vk::Format::eR32Sint; format = vk::Format::eR32Sint;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k32UInt: case Prospero::BufferFormat::k32UInt:
*format = vk::Format::eR32Uint; format = vk::Format::eR32Uint;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k8_8SInt: case Prospero::BufferFormat::k8_8SInt:
*format = vk::Format::eR8G8Sint; format = vk::Format::eR8G8Sint;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k8_8UInt: case Prospero::BufferFormat::k8_8UInt:
*format = vk::Format::eR8G8Uint; format = vk::Format::eR8G8Uint;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k8_8SScaled: case Prospero::BufferFormat::k8_8SScaled:
*format = vk::Format::eR8G8Sscaled; format = vk::Format::eR8G8Sscaled;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k8_8UScaled: case Prospero::BufferFormat::k8_8UScaled:
*format = vk::Format::eR8G8Uscaled; format = vk::Format::eR8G8Uscaled;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k8_8SNorm: case Prospero::BufferFormat::k8_8SNorm:
*format = vk::Format::eR8G8Snorm; format = vk::Format::eR8G8Snorm;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k8_8UNorm: case Prospero::BufferFormat::k8_8UNorm:
*format = vk::Format::eR8G8Unorm; format = vk::Format::eR8G8Unorm;
*size = 2; size = 2;
break; break;
case Prospero::BufferFormat::k16Float: case Prospero::BufferFormat::k16Float:
*format = vk::Format::eR16Sfloat; format = vk::Format::eR16Sfloat;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k16SInt: case Prospero::BufferFormat::k16SInt:
*format = vk::Format::eR16Sint; format = vk::Format::eR16Sint;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k16UInt: case Prospero::BufferFormat::k16UInt:
*format = vk::Format::eR16Uint; format = vk::Format::eR16Uint;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k16SScaled: case Prospero::BufferFormat::k16SScaled:
*format = vk::Format::eR16Sscaled; format = vk::Format::eR16Sscaled;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k16UScaled: case Prospero::BufferFormat::k16UScaled:
*format = vk::Format::eR16Uscaled; format = vk::Format::eR16Uscaled;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k16SNorm: case Prospero::BufferFormat::k16SNorm:
*format = vk::Format::eR16Snorm; format = vk::Format::eR16Snorm;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k16UNorm: case Prospero::BufferFormat::k16UNorm:
*format = vk::Format::eR16Unorm; format = vk::Format::eR16Unorm;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k8SInt: case Prospero::BufferFormat::k8SInt:
*format = vk::Format::eR8Sint; format = vk::Format::eR8Sint;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k8UInt: case Prospero::BufferFormat::k8UInt:
*format = vk::Format::eR8Uint; format = vk::Format::eR8Uint;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k8SScaled: case Prospero::BufferFormat::k8SScaled:
*format = vk::Format::eR8Sscaled; format = vk::Format::eR8Sscaled;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k8UScaled: case Prospero::BufferFormat::k8UScaled:
*format = vk::Format::eR8Uscaled; format = vk::Format::eR8Uscaled;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k8SNorm: case Prospero::BufferFormat::k8SNorm:
*format = vk::Format::eR8Snorm; format = vk::Format::eR8Snorm;
*size = 1; size = 1;
break; break;
case Prospero::BufferFormat::k8UNorm: case Prospero::BufferFormat::k8UNorm:
*format = vk::Format::eR8Unorm; format = vk::Format::eR8Unorm;
*size = 1; size = 1;
break; break;
default: default:
EXIT("unknown format: fmt = %u\n", fmt); EXIT("unknown format: fmt = %u\n", fmt);
*format = vk::Format::eUndefined; format = vk::Format::eUndefined;
*size = 4; size = 4;
break; break;
} }
@@ -391,43 +385,39 @@ static vk::BlendOp GetBlendOp(uint32_t op) {
return vk::BlendOp::eAdd; return vk::BlendOp::eAdd;
} }
static void CreateLayout(vk::DescriptorSetLayout* set_layouts, uint32_t* set_layouts_num, static void CreateLayout(std::span<vk::DescriptorSetLayout> set_layouts, uint32_t& set_layouts_num,
vk::PushConstantRange* push_constant_info, std::span<vk::PushConstantRange> push_constant_info,
uint32_t* push_constant_info_num, uint32_t& push_constant_info_num,
const ShaderRecompiler::IR::Program& program, const ShaderRecompiler::IR::Program& program,
vk::ShaderStageFlags vk_stage, DescriptorCache::Stage stage) { 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 auto& bindings = program.bindings;
const bool need_descriptor = !bindings.descriptors.empty(); const bool need_descriptor = !bindings.descriptors.empty();
if (bindings.push_constant_size != 0) { 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].stageFlags = vk_stage;
push_constant_info[index].offset = bindings.push_constant_offset; push_constant_info[index].offset = bindings.push_constant_offset;
push_constant_info[index].size = bindings.push_constant_size; push_constant_info[index].size = bindings.push_constant_size;
(*push_constant_info_num)++; push_constant_info_num++;
} }
if (need_descriptor) { if (need_descriptor) {
EXIT_IF(bindings.descriptor_set != *set_layouts_num); EXIT_IF(bindings.descriptor_set != set_layouts_num);
set_layouts[*set_layouts_num] = set_layouts[set_layouts_num] =
g_render_ctx->GetDescriptorCache()->GetDescriptorSetLayout(stage, program); GetRenderContext().GetDescriptorCache().GetDescriptorSetLayout(stage, program);
(*set_layouts_num)++; 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, const ShaderRecompiler::IR::Program& program,
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo* required, vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo& required,
vk::PipelineShaderStageCreateInfo* stage) { vk::PipelineShaderStageCreateInfo& stage) {
EXIT_IF(gctx == nullptr || required == nullptr || stage == nullptr); const auto& graphics = GetRenderContext().GetGraphics();
const auto config = ConfigureShaderSubgroup(*gctx, vk_stage, program); const auto config =
ConfigureShaderSubgroup(ShaderSubgroupCapabilities {graphics}, vk_stage, program);
switch (config.mode) { switch (config.mode) {
case ShaderSubgroupMode::Natural: return; case ShaderSubgroupMode::Natural: return;
case ShaderSubgroupMode::PerInvocationGraphics: { case ShaderSubgroupMode::PerInvocationGraphics: {
@@ -453,33 +443,30 @@ static void ConfigureSubgroupSize(const GraphicContext* gctx, vk::ShaderStageFla
default: default:
EXIT("Vulkan cannot run %u-lane shader stage 0x%08x: default=%u min=%u max=%u " EXIT("Vulkan cannot run %u-lane shader stage 0x%08x: default=%u min=%u max=%u "
"controlled_stages=0x%08x\n", "controlled_stages=0x%08x\n",
program.wave_size, static_cast<uint32_t>(vk_stage), gctx->subgroup_size, program.wave_size, static_cast<uint32_t>(vk_stage), graphics.subgroup_size,
gctx->min_subgroup_size, gctx->max_subgroup_size, graphics.min_subgroup_size, graphics.max_subgroup_size,
static_cast<vk::ShaderStageFlags::MaskType>(gctx->required_subgroup_size_stages)); static_cast<vk::ShaderStageFlags::MaskType>(
graphics.required_subgroup_size_stages));
} }
required->sType = vk::StructureType::ePipelineShaderStageRequiredSubgroupSizeCreateInfo; required.sType = vk::StructureType::ePipelineShaderStageRequiredSubgroupSizeCreateInfo;
required->requiredSubgroupSize = config.required_size; required.requiredSubgroupSize = config.required_size;
stage->pNext = required; stage.pNext = &required;
} }
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::RenderPass render_pass, void CreatePipelineInternal(PipelineCache::GraphicsPipeline& pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo* vs_input_info, const ShaderVertexInputInfo& vs_input_info,
std::span<const uint32_t> vs_shader, std::span<const uint32_t> vs_shader,
const ShaderPixelInputInfo* ps_input_info, const ShaderPixelInputInfo* ps_input_info,
std::span<const uint32_t> ps_shader, std::span<const uint32_t> ps_shader,
const PipelineStaticParameters& static_params, uint32_t vs_hash0, const PipelineStaticParameters& static_params, uint32_t vs_hash0,
uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32, uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32,
bool ps_active) { bool ps_active) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(pipeline == nullptr);
EXIT_IF(render_pass == nullptr); EXIT_IF(render_pass == nullptr);
EXIT_IF(ps_active && ps_input_info == nullptr); EXIT_IF(ps_active && ps_input_info == nullptr);
auto* gctx = g_render_ctx->GetGraphicCtx(); auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(gctx == nullptr);
vk::ShaderModule vert_shader_module = nullptr; vk::ShaderModule vert_shader_module = nullptr;
vk::ShaderModule frag_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.codeSize = vs_shader.size() * 4;
create_info.pCode = vs_shader.data(); 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()) { if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateShaderModule VS done result=%s module=%p\n", LOGF("PipelineTrace: vkCreateShaderModule VS done result=%s module=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(vert_shader_module)); VulkanToString(result).c_str(), static_cast<void*>(vert_shader_module));
@@ -502,7 +489,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
if (ps_active) { if (ps_active) {
create_info.codeSize = ps_shader.size() * 4; create_info.codeSize = ps_shader.size() * 4;
create_info.pCode = ps_shader.data(); 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()) { if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateShaderModule PS done result=%s module=%p\n", LOGF("PipelineTrace: vkCreateShaderModule PS done result=%s module=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(frag_shader_module)); VulkanToString(result).c_str(), static_cast<void*>(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.module = vert_shader_module;
vert_shader_stage_info.pName = "main"; vert_shader_stage_info.pName = "main";
vert_shader_stage_info.pSpecializationInfo = nullptr; vert_shader_stage_info.pSpecializationInfo = nullptr;
EXIT_IF(!vs_input_info->stage); EXIT_IF(!vs_input_info.stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eVertex, *vs_input_info->stage.program, ConfigureSubgroupSize(vk::ShaderStageFlagBits::eVertex, *vs_input_info.stage.program,
&vert_subgroup_size, &vert_shader_stage_info); vert_subgroup_size, vert_shader_stage_info);
vk::PipelineShaderStageCreateInfo frag_shader_stage_info {}; vk::PipelineShaderStageCreateInfo frag_shader_stage_info {};
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo frag_subgroup_size {}; vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo frag_subgroup_size {};
@@ -538,9 +525,8 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
frag_shader_stage_info.pSpecializationInfo = nullptr; frag_shader_stage_info.pSpecializationInfo = nullptr;
if (ps_active) { if (ps_active) {
EXIT_IF(!ps_input_info->stage); EXIT_IF(!ps_input_info->stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eFragment, ConfigureSubgroupSize(vk::ShaderStageFlagBits::eFragment, *ps_input_info->stage.program,
*ps_input_info->stage.program, &frag_subgroup_size, frag_subgroup_size, frag_shader_stage_info);
&frag_shader_stage_info);
} }
vk::PipelineShaderStageCreateInfo shader_stages[] = {vert_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::VertexInputAttributeDescription input_attr[ShaderVertexInputInfo::RES_MAX];
vk::VertexInputBindingDescription input_desc[ShaderVertexInputInfo::RES_MAX]; vk::VertexInputBindingDescription input_desc[ShaderVertexInputInfo::RES_MAX];
for (int bi = 0; bi < vs_input_info->buffers_num; bi++) { for (int bi = 0; bi < vs_input_info.buffers_num; bi++) {
const auto& b = vs_input_info->buffers[bi]; const auto& b = vs_input_info.buffers[bi];
input_desc[bi].binding = bi; input_desc[bi].binding = bi;
input_desc[bi].stride = b.stride; input_desc[bi].stride = b.stride;
input_desc[bi].inputRate = input_desc[bi].inputRate =
@@ -564,11 +550,11 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
input_attr[index].offset = b.attr_offsets[ai]; input_attr[index].offset = b.attr_offsets[ai];
uint32_t attr_size = 4; uint32_t attr_size = 4;
auto registers_num = vs_input_info->resources_dst[index].registers_num; auto registers_num = vs_input_info.resources_dst[index].registers_num;
auto used_components = (vs_input_info->resource_fetch_components[index] > 0 auto used_components = (vs_input_info.resource_fetch_components[index] > 0
? vs_input_info->resource_fetch_components[index] ? vs_input_info.resource_fetch_components[index]
: registers_num); : 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<uint32_t>(used_components)); static_cast<uint32_t>(used_components));
if (graphics_debug_dump_enabled()) { 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", " fetched_components=%u attr_size=%u swizzle=%u,%u,%u,%u\n",
log_id, index, input_attr[index].binding, input_attr[index].offset, log_id, index, input_attr[index].binding, input_attr[index].offset,
input_desc[bi].stride, static_cast<int>(input_attr[index].format), input_desc[bi].stride, static_cast<int>(input_attr[index].format),
static_cast<uint32_t>(vs_input_info->resources[index].Format()), static_cast<uint32_t>(vs_input_info.resources[index].Format()),
static_cast<uint32_t>(vs_input_info->resources_dst[index].register_start), static_cast<uint32_t>(vs_input_info.resources_dst[index].register_start),
static_cast<uint32_t>(registers_num), static_cast<uint32_t>(registers_num),
static_cast<uint32_t>(used_components), attr_size, static_cast<uint32_t>(used_components), attr_size,
static_cast<uint32_t>(vs_input_info->resources[index].DstSelX()), static_cast<uint32_t>(vs_input_info.resources[index].DstSelX()),
static_cast<uint32_t>(vs_input_info->resources[index].DstSelY()), static_cast<uint32_t>(vs_input_info.resources[index].DstSelY()),
static_cast<uint32_t>(vs_input_info->resources[index].DstSelZ()), static_cast<uint32_t>(vs_input_info.resources[index].DstSelZ()),
static_cast<uint32_t>(vs_input_info->resources[index].DstSelW())); static_cast<uint32_t>(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; static bool logged = false;
if (!logged) { if (!logged) {
LOGF("VertexInput: temporary: accepting PS5 out-of-bounds behavior %" PRIu8 LOGF("VertexInput: temporary: accepting PS5 out-of-bounds behavior %" PRIu8
"\n", "\n",
vs_input_info->resources[index].OutOfBounds()); vs_input_info.resources[index].OutOfBounds());
logged = true; logged = true;
} }
} }
EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].AddTid()); 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].SwizzleEnabled());
auto log_unsupported_vertex_swizzle = [index, attr_size, registers_num]( auto log_unsupported_vertex_swizzle = [index, attr_size, registers_num](
uint32_t swizzle, uint32_t expected) { uint32_t swizzle, uint32_t expected) {
@@ -619,14 +605,14 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
switch (registers_num) { switch (registers_num) {
case 1: { case 1: {
auto swizzle = vs_input_info->resources[index].DstSelX(); auto swizzle = vs_input_info.resources[index].DstSelX();
if (swizzle != DstSel(4)) { if (swizzle != DstSel(4)) {
log_unsupported_vertex_swizzle(swizzle, DstSel(4)); log_unsupported_vertex_swizzle(swizzle, DstSel(4));
} }
break; break;
} }
case 2: { 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)); auto expected = (attr_size == 1 ? DstSel(4, 0) : DstSel(4, 5));
if (swizzle != expected) { if (swizzle != expected) {
log_unsupported_vertex_swizzle(swizzle, expected); log_unsupported_vertex_swizzle(swizzle, expected);
@@ -634,7 +620,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
break; break;
} }
case 3: { case 3: {
auto swizzle = vs_input_info->resources[index].DstSelXYZ(); auto swizzle = vs_input_info.resources[index].DstSelXYZ();
auto expected = auto expected =
(attr_size == 1 ? DstSel(4, 0, 0) (attr_size == 1 ? DstSel(4, 0, 0)
: (attr_size == 2 ? DstSel(4, 5, 0) : DstSel(4, 5, 6))); : (attr_size == 2 ? DstSel(4, 5, 0) : DstSel(4, 5, 6)));
@@ -644,7 +630,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
break; break;
} }
case 4: { 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); auto expected = DstSel(4, 5, 6, 7);
bool supported = false; bool supported = false;
switch (attr_size) { switch (attr_size) {
@@ -679,9 +665,9 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vertex_input_info.sType = vk::StructureType::ePipelineVertexInputStateCreateInfo; vertex_input_info.sType = vk::StructureType::ePipelineVertexInputStateCreateInfo;
vertex_input_info.pNext = nullptr; vertex_input_info.pNext = nullptr;
vertex_input_info.flags = {}; 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.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; vertex_input_info.pVertexAttributeDescriptions = input_attr;
vk::PipelineInputAssemblyStateCreateInfo input_assembly {}; vk::PipelineInputAssemblyStateCreateInfo input_assembly {};
@@ -833,13 +819,13 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vk::PushConstantRange push_constant_info[2]; vk::PushConstantRange push_constant_info[2];
uint32_t push_constant_info_num = 0; uint32_t push_constant_info_num = 0;
EXIT_IF(!vs_input_info->stage); EXIT_IF(!vs_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,
*vs_input_info->stage.program, vk::ShaderStageFlagBits::eVertex, *vs_input_info.stage.program, vk::ShaderStageFlagBits::eVertex,
DescriptorCache::Stage::Vertex); DescriptorCache::Stage::Vertex);
if (ps_active) { if (ps_active) {
EXIT_IF(!ps_input_info->stage); 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, *ps_input_info->stage.program, vk::ShaderStageFlagBits::eFragment,
DescriptorCache::Stage::Pixel); DescriptorCache::Stage::Pixel);
} }
@@ -854,7 +840,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
pipeline_layout_info.pPushConstantRanges = pipeline_layout_info.pPushConstantRanges =
push_constant_info_num > 0 ? push_constant_info : nullptr; 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()) { if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=0x%08" PRIx32 "/0x%08" PRIx32 LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=0x%08" PRIx32 "/0x%08" PRIx32
@@ -862,15 +848,15 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
"\n", "\n",
vs_hash0, vs_crc32, ps_hash0, ps_crc32, set_layouts_num, push_constant_info_num); vs_hash0, vs_crc32, ps_hash0, ps_crc32, set_layouts_num, push_constant_info_num);
} }
result = gctx->device.createPipelineLayout(&pipeline_layout_info, nullptr, result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline->pipeline_layout); &pipeline.pipeline_layout);
if (graphics_debug_dump_enabled()) { if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreatePipelineLayout done result=%s layout=%p\n", LOGF("PipelineTrace: vkCreatePipelineLayout done result=%s layout=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline_layout)); VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline_layout));
} }
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); 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 {}; vk::PipelineDepthStencilStateCreateInfo depth_stencil_info {};
depth_stencil_info.sType = vk::StructureType::ePipelineDepthStencilStateCreateInfo; 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.pDepthStencilState = (static_params.with_depth ? &depth_stencil_info : nullptr);
pipeline_info.pColorBlendState = &color_blending; pipeline_info.pColorBlendState = &color_blending;
pipeline_info.pDynamicState = &dynamic_state; pipeline_info.pDynamicState = &dynamic_state;
pipeline_info.layout = pipeline->pipeline_layout; pipeline_info.layout = pipeline.pipeline_layout;
pipeline_info.renderPass = render_pass; pipeline_info.renderPass = render_pass;
pipeline_info.subpass = 0; pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = nullptr; pipeline_info.basePipelineHandle = nullptr;
pipeline_info.basePipelineIndex = -1; pipeline_info.basePipelineIndex = -1;
EXIT_IF(pipeline->pipeline != nullptr); EXIT_IF(pipeline.pipeline != nullptr);
if (graphics_debug_dump_enabled()) { if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=0x%08" PRIx32 "/0x%08" PRIx32 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, viewport.y, viewport.width, viewport.height, scissor.offset.x, scissor.offset.y,
scissor.extent.width, scissor.extent.height); scissor.extent.width, scissor.extent.height);
} }
result = gctx->device.createGraphicsPipelines(nullptr, 1, &pipeline_info, nullptr, result = graphics.device.createGraphicsPipelines(nullptr, 1, &pipeline_info, nullptr,
&pipeline->pipeline); &pipeline.pipeline);
if (graphics_debug_dump_enabled()) { if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateGraphicsPipelines done result=%s pipeline=%p\n", LOGF("PipelineTrace: vkCreateGraphicsPipelines done result=%s pipeline=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline)); VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline));
} }
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline == nullptr); EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
if (frag_shader_module != 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) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline, void CreatePipelineInternal(PipelineCache::ComputePipeline& pipeline,
const ShaderComputeInputInfo* input_info, const ShaderComputeInputInfo& input_info,
std::span<const uint32_t> cs_shader) { std::span<const uint32_t> cs_shader) {
EXIT_IF(g_render_ctx == nullptr); auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(pipeline == nullptr);
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
vk::ShaderModule comp_shader_module = nullptr; vk::ShaderModule comp_shader_module = nullptr;
@@ -984,7 +965,7 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
create_info.pCode = cs_shader.data(); create_info.pCode = cs_shader.data();
LOGF("PipelineTrace: vkCreateShaderModule CS begin words=%" PRIu64 "\n", LOGF("PipelineTrace: vkCreateShaderModule CS begin words=%" PRIu64 "\n",
static_cast<uint64_t>(cs_shader.size())); static_cast<uint64_t>(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", LOGF("PipelineTrace: vkCreateShaderModule CS done result=%s module=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(comp_shader_module)); VulkanToString(result).c_str(), static_cast<void*>(comp_shader_module));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); 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.module = comp_shader_module;
comp_shader_stage_info.pName = "main"; comp_shader_stage_info.pName = "main";
comp_shader_stage_info.pSpecializationInfo = nullptr; comp_shader_stage_info.pSpecializationInfo = nullptr;
EXIT_IF(!input_info->stage); EXIT_IF(!input_info.stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eCompute, *input_info->stage.program, ConfigureSubgroupSize(vk::ShaderStageFlagBits::eCompute, *input_info.stage.program,
&comp_subgroup_size, &comp_shader_stage_info); comp_subgroup_size, comp_shader_stage_info);
vk::DescriptorSetLayout set_layouts[1] = {}; vk::DescriptorSetLayout set_layouts[1] = {};
uint32_t set_layouts_num = 0; uint32_t set_layouts_num = 0;
@@ -1010,9 +991,9 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
vk::PushConstantRange push_constant_info[1]; vk::PushConstantRange push_constant_info[1];
uint32_t push_constant_info_num = 0; uint32_t push_constant_info_num = 0;
EXIT_IF(!input_info->stage); EXIT_IF(!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,
*input_info->stage.program, vk::ShaderStageFlagBits::eCompute, *input_info.stage.program, vk::ShaderStageFlagBits::eCompute,
DescriptorCache::Stage::Compute); DescriptorCache::Stage::Compute);
vk::PipelineLayoutCreateInfo pipeline_layout_info {}; vk::PipelineLayoutCreateInfo pipeline_layout_info {};
@@ -1025,39 +1006,39 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
pipeline_layout_info.pPushConstantRanges = pipeline_layout_info.pPushConstantRanges =
push_constant_info_num > 0 ? push_constant_info : nullptr; 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", LOGF("PipelineTrace: vkCreatePipelineLayout CS begin set_layouts=%u push_constants=%u\n",
set_layouts_num, push_constant_info_num); set_layouts_num, push_constant_info_num);
result = gctx->device.createPipelineLayout(&pipeline_layout_info, nullptr, result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline->pipeline_layout); &pipeline.pipeline_layout);
LOGF("PipelineTrace: vkCreatePipelineLayout CS done result=%s layout=%p\n", LOGF("PipelineTrace: vkCreatePipelineLayout CS done result=%s layout=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline_layout)); VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline_layout));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline_layout == nullptr); EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
vk::ComputePipelineCreateInfo info {}; vk::ComputePipelineCreateInfo info {};
info.sType = vk::StructureType::eComputePipelineCreateInfo; info.sType = vk::StructureType::eComputePipelineCreateInfo;
info.pNext = nullptr; info.pNext = nullptr;
info.flags = {}; info.flags = {};
info.stage = comp_shader_stage_info; info.stage = comp_shader_stage_info;
info.layout = pipeline->pipeline_layout; info.layout = pipeline.pipeline_layout;
info.basePipelineHandle = nullptr; info.basePipelineHandle = nullptr;
info.basePipelineIndex = -1; info.basePipelineIndex = -1;
EXIT_IF(pipeline->pipeline != nullptr); EXIT_IF(pipeline.pipeline != nullptr);
LOGF("PipelineTrace: vkCreateComputePipelines begin layout=%p\n", LOGF("PipelineTrace: vkCreateComputePipelines begin layout=%p\n",
static_cast<void*>(pipeline->pipeline_layout)); static_cast<void*>(pipeline.pipeline_layout));
result = gctx->device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline->pipeline); result = graphics.device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline.pipeline);
LOGF("PipelineTrace: vkCreateComputePipelines done result=%s pipeline=%p\n", LOGF("PipelineTrace: vkCreateComputePipelines done result=%s pipeline=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline)); VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); 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 } // namespace Libs::Graphics
+16 -19
View File
@@ -16,21 +16,20 @@ namespace {
std::atomic<uint64_t> g_stream_buffer_count {0}; std::atomic<uint64_t> g_stream_buffer_count {0};
} // namespace } // namespace
HostStreamBuffer::HostStreamBuffer() = default; HostStreamBuffer::HostStreamBuffer(GraphicContext& graphics): m_graphics(graphics) {}
HostStreamBuffer::~HostStreamBuffer() { HostStreamBuffer::~HostStreamBuffer() {
Release(); Release();
} }
void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) { void HostStreamBuffer::EnsureBuffer() {
if (m_buffer != nullptr) { if (m_buffer != nullptr) {
if (m_ctx != ctx || m_mapped == nullptr) { if (m_mapped == nullptr) {
EXIT("host stream buffer changed graphics context\n"); EXIT("host stream buffer lost its mapped storage\n");
} }
return; return;
} }
KYTY_PROFILER_BLOCK("HostStreamBuffer::create"); KYTY_PROFILER_BLOCK("HostStreamBuffer::create");
m_ctx = ctx;
m_buffer = std::make_unique<VulkanBuffer>(); m_buffer = std::make_unique<VulkanBuffer>();
m_buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer | m_buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eVertexBuffer |
@@ -39,17 +38,16 @@ void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) {
m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible | m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached; vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, CAPACITY, m_buffer.get()); m_graphics.CreateBuffer(CAPACITY, *m_buffer);
VulkanMapMemory(ctx, &m_buffer->memory, &m_mapped); m_graphics.MapMemory(m_buffer->memory, m_mapped);
const auto count = g_stream_buffer_count.fetch_add(1, std::memory_order_relaxed) + 1; 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); LOGF("HostStreamBuffer: created serial=%" PRIu64 " capacity=%" PRIu64 "\n", count, CAPACITY);
} }
bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment, bool HostStreamBuffer::Copy(const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range) { VulkanBuffer*& out_buffer, uint64_t& out_offset, uint64_t& out_range) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
if (ctx == nullptr || src == nullptr || out_buffer == nullptr || out_offset == nullptr || if (src == nullptr) {
out_range == nullptr) {
EXIT("invalid host stream upload\n"); EXIT("invalid host stream upload\n");
} }
std::lock_guard lock(m_mutex); 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) { if (offset > CAPACITY || size > CAPACITY - offset) {
return false; return false;
} }
EnsureBuffer(ctx); EnsureBuffer();
std::memcpy(static_cast<uint8_t*>(m_mapped) + offset, src, static_cast<size_t>(size)); std::memcpy(static_cast<uint8_t*>(m_mapped) + offset, src, static_cast<size_t>(size));
m_offset = offset + size; m_offset = offset + size;
*out_buffer = m_buffer.get(); out_buffer = m_buffer.get();
*out_offset = offset; out_offset = offset;
*out_range = size; out_range = size;
return true; return true;
} }
@@ -83,14 +81,13 @@ void HostStreamBuffer::Reset() noexcept {
void HostStreamBuffer::Release() noexcept { void HostStreamBuffer::Release() noexcept {
std::lock_guard lock(m_mutex); std::lock_guard lock(m_mutex);
if (m_buffer != nullptr) { if (m_buffer != nullptr) {
if (m_ctx == nullptr || m_mapped == nullptr) { if (m_mapped == nullptr) {
EXIT("invalid host stream buffer release state\n"); EXIT("invalid host stream buffer release state\n");
} }
VulkanUnmapMemory(m_ctx, &m_buffer->memory); m_graphics.UnmapMemory(m_buffer->memory);
VulkanDeleteBuffer(m_ctx, m_buffer.get()); m_graphics.DeleteBuffer(*m_buffer);
m_buffer.reset(); m_buffer.reset();
} }
m_ctx = nullptr;
m_mapped = nullptr; m_mapped = nullptr;
m_offset = 0; m_offset = 0;
} }
@@ -18,17 +18,17 @@ struct VulkanBuffer;
// backend with scheduler watches will not change descriptor/render call sites. // backend with scheduler watches will not change descriptor/render call sites.
class HostStreamBuffer final { class HostStreamBuffer final {
public: public:
HostStreamBuffer(); explicit HostStreamBuffer(GraphicContext& graphics);
~HostStreamBuffer(); ~HostStreamBuffer();
KYTY_CLASS_NO_COPY(HostStreamBuffer); KYTY_CLASS_NO_COPY(HostStreamBuffer);
[[nodiscard]] bool Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment, [[nodiscard]] bool Copy(const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range); VulkanBuffer*& out_buffer, uint64_t& out_offset, uint64_t& out_range);
void Reset() noexcept; void Reset() noexcept;
void Release() noexcept; void Release() noexcept;
private: private:
void EnsureBuffer(GraphicContext* ctx); void EnsureBuffer();
// Interim fence-scoped backend: one command processor's eight live command buffers reserve up // 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 // 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; static constexpr uint64_t CAPACITY = 16ull * 1024ull * 1024ull;
mutable std::mutex m_mutex; mutable std::mutex m_mutex;
GraphicContext* m_ctx = nullptr; GraphicContext& m_graphics;
std::unique_ptr<VulkanBuffer> m_buffer; std::unique_ptr<VulkanBuffer> m_buffer;
void* m_mapped = nullptr; void* m_mapped = nullptr;
uint64_t m_offset = 0; uint64_t m_offset = 0;
+43 -58
View File
@@ -24,8 +24,8 @@ constexpr int GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT = 0x00;
constexpr int GRAPHICS_EVENT_EOP = 0x40; constexpr int GRAPHICS_EVENT_EOP = 0x40;
constexpr uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000; constexpr uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000;
bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t* value) { bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t& value) {
if (host_frequency == 0 || value == nullptr) { if (host_frequency == 0) {
return false; 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) { if (whole_value > MAX_VALUE - fractional_value) {
return false; return false;
} }
*value = whole_value + fractional_value; value = whole_value + fractional_value;
return true; return true;
} }
@@ -50,25 +50,22 @@ uint64_t ReadReferenceClock() {
const auto host_frequency = LibKernel::KernelGetTscFrequency(); const auto host_frequency = LibKernel::KernelGetTscFrequency();
const auto host_ticks = LibKernel::KernelReadTsc(); const auto host_ticks = LibKernel::KernelReadTsc();
uint64_t value = 0; 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, EXIT("cannot scale host clock, ticks=0x%016" PRIx64 " frequency=%" PRIu64 "\n", host_ticks,
host_frequency); host_frequency);
} }
return value; 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) { LabelCallback callback_2 = nullptr, const uint64_t* args = nullptr) {
auto* label = LabelCreate(g_render_ctx->GetGraphicCtx(), callback_1, callback_2, args); auto* label = LabelCreate(callback_1, callback_2, args);
LabelSet(buffer, label); LabelSet(buffer, *label);
LabelDelete(label); LabelDelete(*label);
} }
static bool CompleteDisplayBufferFlip(const uint64_t* args) { static bool CompleteDisplayBufferFlip(const uint64_t* args) {
if (g_render_ctx == nullptr || args == nullptr) { EXIT_IF(args == nullptr);
EXIT("GPU flip completion has invalid state, render_ctx=%p args=%p\n",
static_cast<const void*>(g_render_ctx), static_cast<const void*>(args));
}
Presentation::DisplayBufferCompleteFlipFromGpu(args[0]); Presentation::DisplayBufferCompleteFlipFromGpu(args[0]);
return true; return true;
} }
@@ -90,20 +87,17 @@ enum class EndOfPipeWriteSize : uint32_t { Dword = 4, Qword = 8 };
enum class EndOfPipeWriteAction { Write, WriteBack, Interrupt, InterruptWriteBack }; enum class EndOfPipeWriteAction { Write, WriteBack, Interrupt, InterruptWriteBack };
static bool TriggerEopEventCallback(const uint64_t* args) { static bool TriggerEopEventCallback(const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(args == nullptr); EXIT_IF(args == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0])); GetRenderContext().TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true; return true;
} }
static bool TriggerDefaultEopEventCallback(const uint64_t* /*args*/) { static bool TriggerDefaultEopEventCallback(const uint64_t* /*args*/) {
EXIT_IF(g_render_ctx == nullptr); GetRenderContext().TriggerEopEvent(0);
g_render_ctx->TriggerEopEvent(0);
return true; return true;
} }
static void ValidateEndOfPipeSignal(const EndOfPipeSignal& signal) { static void ValidateEndOfPipeSignal(const EndOfPipeSignal& signal) {
EXIT_IF(g_render_ctx == nullptr);
if (signal.destination.has_value()) { if (signal.destination.has_value()) {
EXIT_IF(*signal.destination == 0); EXIT_IF(*signal.destination == 0);
} }
@@ -121,13 +115,13 @@ static void RecordEndOfPipeSignal(const EndOfPipeSignal& signal) {
switch (signal.completion) { switch (signal.completion) {
case EndOfPipeCompletion::None: return; case EndOfPipeCompletion::None: return;
case EndOfPipeCompletion::Interrupt: case EndOfPipeCompletion::Interrupt:
SubmitLabel(signal.buffer, nullptr, TriggerEopEventCallback, args); SubmitLabel(*signal.buffer, nullptr, TriggerEopEventCallback, args);
return; return;
case EndOfPipeCompletion::Flip: case EndOfPipeCompletion::Flip:
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, nullptr, args); SubmitLabel(*signal.buffer, CompleteDisplayBufferFlip, nullptr, args);
return; return;
case EndOfPipeCompletion::FlipAndInterrupt: case EndOfPipeCompletion::FlipAndInterrupt:
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback, SubmitLabel(*signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback,
args); args);
return; return;
} }
@@ -149,7 +143,7 @@ static bool TriggersInterrupt(EndOfPipeWriteAction action) {
action == EndOfPipeWriteAction::InterruptWriteBack; 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, uint64_t value, EndOfPipeWriteSize size,
EndOfPipeWriteAction action, uint32_t context_id = 0) { EndOfPipeWriteAction action, uint32_t context_id = 0) {
const auto width = static_cast<uint32_t>(size); const auto width = static_cast<uint32_t>(size);
@@ -158,7 +152,7 @@ static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer* buffer, uint
const bool interrupt = TriggersInterrupt(action); const bool interrupt = TriggersInterrupt(action);
EndOfPipeSignal signal { EndOfPipeSignal signal {
.buffer = buffer, .buffer = &buffer,
.submit_id = submit_id, .submit_id = submit_id,
.debug_operation = DebugOperation(action), .debug_operation = DebugOperation(action),
.debug_args = interrupt ? std::array {width, context_id, value_low, value_high} .debug_args = interrupt ? std::array {width, context_id, value_low, value_high}
@@ -179,21 +173,20 @@ void TriggerAgcUserInterrupt() {
} }
void TriggerEopEvent(uint32_t context_id) { void TriggerEopEvent(uint32_t context_id) {
EXIT_IF(g_render_ctx == nullptr); GetRenderContext().TriggerEopEvent(context_id);
g_render_ctx->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) { uint32_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Write); 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) { uint32_t dw_offset, uint32_t dw_num) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr); const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({ RecordEndOfPipeSignal({
.buffer = buffer, .buffer = &buffer,
.submit_id = submit_id, .submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopWrite, .debug_operation = CommandBufferDebugOp::EopWrite,
.debug_args = {dw_offset, dw_num, 0, 0}, .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) { uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write); 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) { uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write); EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write);
@@ -218,7 +211,7 @@ void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uin
reinterpret_cast<uint64_t>(dst_gpu_addr), value); reinterpret_cast<uint64_t>(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) { uint64_t* dst_gpu_addr, uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack); EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
@@ -228,19 +221,19 @@ void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer
reinterpret_cast<uint64_t>(dst_gpu_addr), value); reinterpret_cast<uint64_t>(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) { uint64_t* dst_gpu_addr, uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack); 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) { uint32_t* dst_gpu_addr, uint32_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::WriteBack); 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, uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id) { uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
@@ -248,7 +241,7 @@ void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer*
context_id); 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* dst_gpu_addr, uint32_t value,
uint32_t context_id) { uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
@@ -256,24 +249,24 @@ void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer*
context_id); 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) { uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Interrupt, context_id); 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) { uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value, RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Interrupt, context_id); 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) { int64_t flip_arg) {
for (;;) { for (;;) {
uint64_t request_id = 0; uint64_t request_id = 0;
const auto result = Presentation::DisplayBufferSubmitFlipFromGpu( 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) { if (result == OK) {
EXIT_IF(request_id == 0); EXIT_IF(request_id == 0);
return request_id; 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, uint32_t* dst_gpu_addr, uint32_t value,
int handle, int index, int flip_mode, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id) { int64_t flip_arg, uint64_t request_id) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr); const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({ RecordEndOfPipeSignal({
.buffer = buffer, .buffer = &buffer,
.submit_id = submit_id, .submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopWriteBackFlip, .debug_operation = CommandBufferDebugOp::EopWriteBackFlip,
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index), .debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(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, uint32_t value, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id) { int64_t flip_arg, uint64_t request_id) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr); const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({ RecordEndOfPipeSignal({
.buffer = buffer, .buffer = &buffer,
.submit_id = submit_id, .submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopFlip, .debug_operation = CommandBufferDebugOp::EopFlip,
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index), .debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(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) { int flip_mode, int64_t flip_arg, uint64_t request_id) {
RecordEndOfPipeSignal({ RecordEndOfPipeSignal({
.buffer = buffer, .buffer = &buffer,
.submit_id = submit_id, .submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopOnlyFlip, .debug_operation = CommandBufferDebugOp::EopOnlyFlip,
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index), .debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
@@ -336,8 +329,8 @@ void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int han
}); });
} }
void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id) { void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id) {
ValidateEndOfPipeSignal({.buffer = buffer}); ValidateEndOfPipeSignal({.buffer = &buffer});
uint64_t args[LABEL_ARGS_MAX] = {static_cast<uint64_t>(context_id)}; uint64_t args[LABEL_ARGS_MAX] = {static_cast<uint64_t>(context_id)};
SubmitLabel(buffer, nullptr, TriggerEopEventCallback, args); SubmitLabel(buffer, nullptr, TriggerEopEventCallback, args);
@@ -353,11 +346,10 @@ static void EopEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) {
static void EopEventDeleteFunc(LibKernel::EventQueue::KernelEqueue eq, static void EopEventDeleteFunc(LibKernel::EventQueue::KernelEqueue eq,
LibKernel::EventQueue::KernelEqueueEvent* event) { LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr); EXIT_IF(event == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_NOT_IMPLEMENTED(event->event.filter != LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS); EXIT_NOT_IMPLEMENTED(event->event.filter != LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS);
if (event->event.ident == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || if (event->event.ident == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT ||
event->event.ident == GRAPHICS_EVENT_EOP) { event->event.ident == GRAPHICS_EVENT_EOP) {
g_render_ctx->DeleteEopEq(eq, static_cast<int>(event->event.ident)); GetRenderContext().DeleteEopEq(eq, static_cast<int>(event->event.ident));
} }
} }
@@ -377,8 +369,6 @@ static void EopEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event,
} }
int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) { int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) {
EXIT_IF(g_render_ctx == nullptr);
LibKernel::EventQueue::KernelEqueueEvent event; LibKernel::EventQueue::KernelEqueueEvent event;
event.triggered = false; event.triggered = false;
event.event.ident = static_cast<uintptr_t>(id); event.event.ident = static_cast<uintptr_t>(id);
@@ -395,15 +385,13 @@ int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) {
if (result == 0 && if (result == 0 &&
(id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP)) { (id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP)) {
g_render_ctx->AddEopEq(eq, id); GetRenderContext().AddEopEq(eq, id);
} }
return result; return result;
} }
int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) { int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) {
EXIT_IF(g_render_ctx == nullptr);
int result = LibKernel::EventQueue::KernelDeleteEvent( int result = LibKernel::EventQueue::KernelDeleteEvent(
eq, static_cast<uintptr_t>(id), LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS); eq, static_cast<uintptr_t>(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) { void ReadGds(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) {
EXIT_IF(g_render_ctx == nullptr); GetRenderContext().GetGdsBuffer().Read(dst, dw_offset, dw_size);
g_render_ctx->GetGdsBuffer()->Read(g_render_ctx->GetGraphicCtx(), dst, dw_offset, dw_size);
} }
void DeleteBuffers() { void DeleteBuffers() {
EXIT_IF(g_render_ctx == nullptr); GetRenderContext().GetBufferCache().ResetNullBuffer();
g_render_ctx->GetBufferCache()->ResetNullBuffer();
} }
} // namespace Libs::Graphics::Sync } // namespace Libs::Graphics::Sync
+17 -17
View File
@@ -12,48 +12,48 @@ class CommandBuffer;
namespace Sync { namespace Sync {
[[nodiscard]] bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, [[nodiscard]] bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency,
uint64_t* value); uint64_t& value);
[[nodiscard]] uint64_t ReadReferenceClock(); [[nodiscard]] uint64_t ReadReferenceClock();
void TriggerAgcUserInterrupt(); void TriggerAgcUserInterrupt();
void TriggerEopEvent(uint32_t context_id); 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); 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); 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); 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); 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); 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); 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); 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* dst_gpu_addr, uint32_t value,
uint32_t context_id = 0); 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, uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id = 0); 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* dst_gpu_addr, uint32_t value,
uint32_t context_id = 0); 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, uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id = 0); 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); 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); 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, uint32_t value, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id); 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, uint32_t* dst_gpu_addr, uint32_t value,
int handle, int index, int flip_mode, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id); int64_t flip_arg, uint64_t request_id);
File diff suppressed because it is too large. Load diff
+41 -48
View File
@@ -53,66 +53,60 @@ public:
bool full = false; bool full = false;
}; };
TextureCache(PageManager& page_manager, BufferCache& buffer_cache, TextureCache(GraphicContext& graphics, PageManager& page_manager, BufferCache& buffer_cache,
ResourceMutex& resource_mutex); ResourceMutex& resource_mutex);
~TextureCache(); ~TextureCache();
KYTY_CLASS_NO_COPY(TextureCache); KYTY_CLASS_NO_COPY(TextureCache);
[[nodiscard]] VulkanImage* FindTexture(CommandBuffer* command, GraphicContext* ctx, [[nodiscard]] VulkanImage& FindTexture(CommandBuffer& command, const ImageInfo& info,
const ImageInfo& info, bool metadata_read); bool metadata_read);
[[nodiscard]] StorageTextureVulkanImage* [[nodiscard]] StorageTextureVulkanImage& FindStorageTexture(CommandBuffer& command,
FindStorageTexture(CommandBuffer* command, GraphicContext* ctx, const ImageInfo& info); const ImageInfo& info);
[[nodiscard]] RenderTextureVulkanImage* [[nodiscard]] RenderTextureVulkanImage& FindRenderTarget(CommandBuffer& command,
FindRenderTarget(CommandBuffer* command, GraphicContext* ctx, const RenderTargetInfo& info); const RenderTargetInfo& info);
[[nodiscard]] DepthStencilVulkanImage* [[nodiscard]] DepthStencilVulkanImage& FindDepthTarget(CommandBuffer& command,
FindDepthTarget(CommandBuffer* command, GraphicContext* ctx, const DepthTargetInfo& info); const DepthTargetInfo& info);
[[nodiscard]] std::vector<VideoOutVulkanImage*> [[nodiscard]] std::vector<VideoOutVulkanImage*>
RegisterVideoOutSurfaces(GraphicContext* ctx, const std::vector<VideoOutInfo>& infos); RegisterVideoOutSurfaces(const std::vector<VideoOutInfo>& infos);
void RefreshVideoOut(VideoOutVulkanImage* image, bool render_target = false); void RefreshVideoOut(VideoOutVulkanImage& image, bool render_target = false);
void UnregisterVideoOutSurfaces(const std::vector<VideoOutVulkanImage*>& images); void UnregisterVideoOutSurfaces(const std::vector<VideoOutVulkanImage*>& images);
[[nodiscard]] bool ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, [[nodiscard]] bool ClearImageFromBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
uint32_t packed_clear); uint32_t packed_clear);
void MarkGpuWritten(VulkanImage* image); void MarkGpuWritten(VulkanImage& image);
void PrepareHostWrite(uint64_t vaddr, uint64_t size); void PrepareHostWrite(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size, [[nodiscard]] bool InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size,
bool formatted_buffer_write = false); bool formatted_buffer_write = false);
[[nodiscard]] RenderTextureVulkanImage* FindRenderTargetByRange(CommandBuffer* command, [[nodiscard]] RenderTextureVulkanImage* FindRenderTargetByRange(CommandBuffer& command,
uint64_t vaddr, uint64_t size); uint64_t vaddr, uint64_t size);
[[nodiscard]] vk::ImageView GetRenderTargetAttachmentView(GraphicContext* ctx, [[nodiscard]] vk::ImageView GetRenderTargetAttachmentView(RenderTextureVulkanImage& image,
RenderTextureVulkanImage* image,
vk::Format format, uint32_t level, vk::Format format, uint32_t level,
uint32_t base_layer, uint32_t base_layer,
uint32_t layer_count); uint32_t layer_count);
[[nodiscard]] vk::ImageView GetDepthTargetAttachmentView(GraphicContext* ctx, [[nodiscard]] vk::ImageView GetDepthTargetAttachmentView(DepthStencilVulkanImage& image,
DepthStencilVulkanImage* image,
uint32_t base_layer, uint32_t base_layer,
uint32_t layer_count); uint32_t layer_count);
[[nodiscard]] vk::ImageView [[nodiscard]] vk::ImageView
GetDepthTargetSampledView(GraphicContext* ctx, DepthStencilVulkanImage* image, GetDepthTargetSampledView(DepthStencilVulkanImage& image, vk::Format view_format,
vk::Format view_format, uint32_t swizzle, uint32_t base_level, uint32_t swizzle, uint32_t base_level, uint32_t level_count,
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);
[[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); vk::ImageViewType type, uint32_t base_layer, uint32_t layer_count);
[[nodiscard]] vk::ImageView GetStorageTextureSampledView(GraphicContext* ctx, [[nodiscard]] vk::ImageView GetSampledColorView(VulkanImage& image, vk::Format view_format,
StorageTextureVulkanImage* image, 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(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); const ImageInfo& info);
[[nodiscard]] vk::ImageView GetStorageTextureStorageView(GraphicContext* ctx, [[nodiscard]] vk::ImageView GetStorageTextureStorageView(StorageTextureVulkanImage& image,
StorageTextureVulkanImage* image,
uint32_t base_level); uint32_t base_level);
[[nodiscard]] DepthStencilVulkanImage* [[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); bool allow_containing_sampled = false);
[[nodiscard]] RegionInfo QueryRegion(uint64_t vaddr, uint64_t size); [[nodiscard]] RegionInfo QueryRegion(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo* info); [[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); void RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers = 1);
[[nodiscard]] bool IsMeta(uint64_t vaddr); [[nodiscard]] bool IsMeta(uint64_t vaddr);
[[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size); [[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice); [[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice);
@@ -122,8 +116,8 @@ public:
PageFaultPhase phase) noexcept; PageFaultPhase phase) noexcept;
void UnmapMemory(uint64_t vaddr, uint64_t size); void UnmapMemory(uint64_t vaddr, uint64_t size);
VulkanImage* GetDummySampledTexture(bool uint_format, bool image_3d); VulkanImage& GetDummySampledTexture(bool uint_format, bool image_3d);
VulkanImage* GetDummyStorageTexture(bool uint_format, bool image_3d); VulkanImage& GetDummyStorageTexture(bool uint_format, bool image_3d);
private: private:
struct CachedImage; struct CachedImage;
@@ -135,19 +129,18 @@ private:
uint32_t clear_mask = 0; uint32_t clear_mask = 0;
bool gpu_modified = false; bool gpu_modified = false;
}; };
[[nodiscard]] vk::ImageView GetImageView(GraphicContext* ctx, VulkanImage* image, [[nodiscard]] vk::ImageView GetImageView(VulkanImage& image, const ImageViewInfo& info);
const ImageViewInfo& info);
[[nodiscard]] bool HasMetaOverlapLocked(uint64_t vaddr, uint64_t size) const; [[nodiscard]] bool HasMetaOverlapLocked(uint64_t vaddr, uint64_t size) const;
[[nodiscard]] CachedImage* FindGpuReadbackPageCandidateLocked(uint64_t vaddr, uint64_t size); [[nodiscard]] CachedImage* FindGpuReadbackPageCandidateLocked(uint64_t vaddr, uint64_t size);
void RequireNoMetaOverlapLocked(uint64_t vaddr, uint64_t size) const; void RequireNoMetaOverlapLocked(uint64_t vaddr, uint64_t size) const;
void ResolveImageMetadataOverlapsLocked(GraphicContext* ctx, uint64_t vaddr, uint64_t size); void ResolveImageMetadataOverlapsLocked(uint64_t vaddr, uint64_t size);
void MarkSampledAliasesCpuDirtyLocked(uint64_t vaddr, uint64_t size); void MarkSampledAliasesCpuDirtyLocked(uint64_t vaddr, uint64_t size);
void RetireSampledTargetAliases(GraphicContext* ctx, const ImageInfo& requested); void RetireSampledTargetAliases(const ImageInfo& requested);
void ResolveStorageImageOverlaps(GraphicContext* ctx, const ImageInfo& requested); void ResolveStorageImageOverlaps(const ImageInfo& requested);
void RetireStorageDepthAliasLocked(GraphicContext* ctx, const ImageInfo& requested); void RetireStorageDepthAliasLocked(const ImageInfo& requested);
void RegisterImageLocked(CachedImage& image); void RegisterImageLocked(CachedImage& image);
void UnregisterImageLocked(CachedImage& image, bool release_tracking); void UnregisterImageLocked(CachedImage& image, bool release_tracking);
[[nodiscard]] VulkanImage* PublishImage(CommandBuffer* command, [[nodiscard]] VulkanImage& PublishImage(CommandBuffer& command,
std::shared_ptr<CachedImage> image); std::shared_ptr<CachedImage> image);
[[nodiscard]] std::vector<CachedImage*> FindImagesInRegionLocked(uint64_t vaddr, uint64_t size, [[nodiscard]] std::vector<CachedImage*> FindImagesInRegionLocked(uint64_t vaddr, uint64_t size,
bool page_overlap); bool page_overlap);
@@ -157,13 +150,13 @@ private:
const CachedImage* native_image_source = nullptr); const CachedImage* native_image_source = nullptr);
void RetireDepthMetadataLocked(const std::vector<CachedImage*>& retire, void RetireDepthMetadataLocked(const std::vector<CachedImage*>& retire,
uint64_t preserve_address = 0); uint64_t preserve_address = 0);
void MaterializeImagesToGuestLocked(GraphicContext* ctx, void MaterializeImagesToGuestLocked(const std::vector<std::shared_ptr<CachedImage>>& images);
const std::vector<std::shared_ptr<CachedImage>>& images);
void SynchronizeColorImageToBufferLocked(CachedImage& cached, uint64_t write_address, void SynchronizeColorImageToBufferLocked(CachedImage& cached, uint64_t write_address,
uint64_t write_size); uint64_t write_size);
void SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint64_t write_address, void SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint64_t write_address,
uint64_t write_size); uint64_t write_size);
GraphicContext& m_graphics;
std::unique_ptr<DummyTextureCache> m_dummy_textures; std::unique_ptr<DummyTextureCache> m_dummy_textures;
TrackingSpinLock m_lock; TrackingSpinLock m_lock;
std::mutex m_fault_mutex; std::mutex m_fault_mutex;
+28 -29
View File
@@ -26,7 +26,7 @@ DepthTransfer MakeDepthTransfer(uint64_t size, uint32_t layers, uint32_t format,
EXIT_IF(size == 0 || layers == 0 || size % layers != 0); EXIT_IF(size == 0 || layers == 0 || size % layers != 0);
TileBlockLayout block {}; TileBlockLayout block {};
EXIT_NOT_IMPLEMENTED( EXIT_NOT_IMPLEMENTED(
!TileGetBlockLayout(TileBlockFamily::Depth64KB, bytes_per_element, &block) || !TileGetBlockLayout(TileBlockFamily::Depth64KB, bytes_per_element, block) ||
Prospero::NumBytesPerElement(format) != bytes_per_element); Prospero::NumBytesPerElement(format) != bytes_per_element);
const uint64_t slice_size = size / layers; const uint64_t slice_size = size / layers;
@@ -61,21 +61,20 @@ DepthTransfer MakeDepthTransfer(uint64_t size, uint32_t layers, uint32_t format,
return transfer; return transfer;
} }
void UploadDepth(GraphicContext* ctx, DepthStencilVulkanImage* image, uint64_t source_address, void UploadDepth(DepthStencilVulkanImage& image, uint64_t source_address, uint64_t size,
uint64_t size, uint32_t layers, uint32_t format, uint32_t bytes_per_element, uint32_t layers, uint32_t format, uint32_t bytes_per_element, uint32_t width,
uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_layer, uint32_t height, uint32_t pitch, uint32_t base_layer,
vk::ImageAspectFlags aspect) { vk::ImageAspectFlags aspect) {
auto transfer = MakeDepthTransfer(size, layers, format, bytes_per_element, width, height, pitch, auto transfer = MakeDepthTransfer(size, layers, format, bytes_per_element, width, height, pitch,
base_layer, aspect); base_layer, aspect);
Transfer::UploadTiledImage(ctx, image, reinterpret_cast<const void*>(source_address), size, Transfer::UploadTiledImage(image, reinterpret_cast<const void*>(source_address), size, size,
size, transfer.infos, transfer.regions, transfer.infos, transfer.regions,
vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::ImageLayout::eDepthStencilAttachmentOptimal);
} }
template <uint32_t (*Encode)(uint16_t)> template <uint32_t (*Encode)(uint16_t)>
void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image, void UploadPromotedD16Depth(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const DepthTargetInfo& info, const BufferImageCopySource& source, const BufferImageCopySource& source, uint32_t base_layer) {
uint32_t base_layer) {
const uint64_t guest_slice_size = info.size / info.layers; const uint64_t guest_slice_size = info.size / info.layers;
const uint64_t texels = static_cast<uint64_t>(info.pitch) * info.height; const uint64_t texels = static_cast<uint64_t>(info.pitch) * info.height;
const uint64_t host_slice_size = texels * sizeof(uint32_t); 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, info.bytes_per_element, info.width, info.height, info.pitch,
base_layer, vk::ImageAspectFlagBits::eDepth); base_layer, vk::ImageAspectFlagBits::eDepth);
std::vector<uint16_t> guest_linear(info.size / sizeof(uint16_t)); std::vector<uint16_t> guest_linear(info.size / sizeof(uint16_t));
GpuDetile(ctx, reinterpret_cast<const void*>(source.address), guest_linear.data(), info.size, GpuDetile(reinterpret_cast<const void*>(source.address), guest_linear.data(), info.size,
info.size, transfer.infos); info.size, transfer.infos);
Transfer::ScratchBuffer host_linear(host_upload_size); Transfer::ScratchBuffer host_linear(host_upload_size);
@@ -99,63 +98,63 @@ void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image,
} }
transfer.regions[layer].offset = static_cast<uint32_t>(host_slice_size * layer); transfer.regions[layer].offset = static_cast<uint32_t>(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); vk::ImageLayout::eDepthStencilAttachmentOptimal);
} }
} // namespace } // 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 { 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 array_texture = TextureIsLayeredTexture(info.type);
const bool volume_texture = TextureIs3DTexture(info.type); const bool volume_texture = TextureIs3DTexture(info.type);
auto layout = TextureCalcUploadLayout( auto layout = TextureCalcUploadLayout(
info.format, info.width, info.height, info.levels, info.depth, info.pitch, info.tile, info.format, info.width, info.height, info.levels, info.depth, info.pitch, info.tile,
info.size, true, volume_texture, storage ? "StorageTextureCache" : "TextureCache"); 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, info.depth, info.levels, array_texture, volume_texture,
TextureUploadDestination::MipLevels); TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(source.address), info.size, TextureUploadGuestImage(image, reinterpret_cast<const void*>(source.address), info.size,
regions, layout, info.format, info.width, info.height, info.depth, regions, layout, info.format, info.width, info.height, info.depth,
info.levels, storage ? "StorageTextureCache" : "TextureCache", info.levels, storage ? "StorageTextureCache" : "TextureCache",
storage ? vk::ImageLayout::eGeneral storage ? vk::ImageLayout::eGeneral
: vk::ImageLayout::eShaderReadOnlyOptimal); : vk::ImageLayout::eShaderReadOnlyOptimal);
} }
void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image, void Tiler::DetileImage(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const DepthTargetInfo& info, const BufferImageCopySource& source, const BufferImageCopySource& source, bool refresh,
bool refresh, uint32_t base_layer) const { uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image->samples != 1); EXIT_NOT_IMPLEMENTED(info.samples != 1 || image.samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle(ctx); if (refresh) Transfer::WaitForGraphicsIdle();
if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) { if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) {
switch (info.format) { switch (info.format) {
case vk::Format::eD24UnormS8Uint: case vk::Format::eD24UnormS8Uint:
UploadPromotedD16Depth<EncodeD16AsD24>(ctx, image, info, source, base_layer); UploadPromotedD16Depth<EncodeD16AsD24>(image, info, source, base_layer);
return; return;
case vk::Format::eD32SfloatS8Uint: case vk::Format::eD32SfloatS8Uint:
UploadPromotedD16Depth<EncodeD16AsD32>(ctx, image, info, source, base_layer); UploadPromotedD16Depth<EncodeD16AsD32>(image, info, source, base_layer);
return; return;
default: EXIT_NOT_IMPLEMENTED(true); 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, info.bytes_per_element, info.width, info.height, info.pitch, base_layer,
vk::ImageAspectFlagBits::eDepth); vk::ImageAspectFlagBits::eDepth);
} }
void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image, void Tiler::DetileStencil(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const DepthTargetInfo& info, const BufferImageCopySource& source, const BufferImageCopySource& source, bool refresh,
bool refresh, uint32_t base_layer) const { uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image->samples != 1); EXIT_NOT_IMPLEMENTED(info.samples != 1 || image.samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle(ctx); if (refresh) Transfer::WaitForGraphicsIdle();
const auto format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt); const auto format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt);
const auto pitch = TileGetTexturePitch(format, info.width, 1, const auto pitch = TileGetTexturePitch(format, info.width, 1,
Prospero::GpuEnumValue(Prospero::TileMode::kDepth)); 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); info.height, pitch, base_layer, vk::ImageAspectFlagBits::eStencil);
} }
+6 -8
View File
@@ -9,21 +9,19 @@ namespace Libs::Graphics {
struct DepthStencilVulkanImage; struct DepthStencilVulkanImage;
struct GpuTextureVulkanImage; struct GpuTextureVulkanImage;
struct GraphicContext;
class Tiler final { class Tiler final {
public: public:
Tiler() = default; Tiler() = default;
KYTY_CLASS_NO_COPY(Tiler); 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; const BufferImageCopySource& source, bool refresh, bool storage) const;
void DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image, void DetileImage(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const DepthTargetInfo& info, const BufferImageCopySource& source, bool refresh, 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; 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;
}; };
} // namespace Libs::Graphics } // namespace Libs::Graphics
+244 -235
View File
@@ -82,13 +82,14 @@ bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size) {
return true; return true;
} }
void WaitForGraphicsIdle(GraphicContext* ctx) { void WaitForGraphicsIdle() {
auto& graphics = GetRenderContext().GetGraphics();
Common::Mutex* locked[GraphicContext::QUEUES_NUM] {}; Common::Mutex* locked[GraphicContext::QUEUES_NUM] {};
int locked_num = 0; int locked_num = 0;
for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) { for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) {
auto* mutex = ctx->queues[id].mutex; auto* mutex = graphics.queues[id].mutex;
if (mutex == nullptr || ctx->queues[id].vk_queue == nullptr) { if (mutex == nullptr || graphics.queues[id].vk_queue == nullptr) {
continue; 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--) { for (int i = locked_num - 1; i >= 0; i--) {
locked[i]->Unlock(); locked[i]->Unlock();
@@ -119,7 +120,7 @@ void WaitForGraphicsIdle(GraphicContext* ctx) {
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); 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, uint32_t levels, vk::ImageAspectFlags aspect_mask,
vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout); vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout);
@@ -129,7 +130,7 @@ static void ExecuteImmediateCommands(const Recorder& recorder) {
// not touch every caller. // not touch every caller.
CommandBuffer command(GraphicContext::QUEUE_UTIL); CommandBuffer command(GraphicContext::QUEUE_UTIL);
command.Begin(); command.Begin();
recorder(&command, command.Handle()); recorder(command, command.Handle());
command.End(); command.End();
command.Execute(); command.Execute();
command.WaitForFence(); command.WaitForFence();
@@ -205,12 +206,12 @@ static void RecordBufferToImageCopy(CommandBuffer& command, VulkanBuffer& src_bu
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer); 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); initial_layout, vk::ImageLayout::eTransferDstOptimal);
vk_command.copyBufferToImage(src_buffer.buffer, dst_image.image, vk_command.copyBufferToImage(src_buffer.buffer, dst_image.image,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferDstOptimal,
static_cast<uint32_t>(regions.size()), regions.data()); static_cast<uint32_t>(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); vk::ImageLayout::eTransferDstOptimal, final_layout);
} }
@@ -251,7 +252,7 @@ RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image, VulkanBuffer
for (const auto& region: regions) { for (const auto& region: regions) {
aspects |= GetTransferAspects(src_image, region.aspect); 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); vk::ImageLayout::eTransferSrcOptimal);
SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, VK_WHOLE_SIZE, SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, 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, SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eTransferWrite, final_access, vk::AccessFlagBits::eTransferWrite, final_access,
vk::PipelineStageFlagBits::eTransfer, final_stage); 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); vk::ImageLayout::eTransferSrcOptimal, final_layout);
} }
@@ -279,28 +280,27 @@ static void RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image,
class ReusableStagingBuffer { class ReusableStagingBuffer {
public: public:
ReusableStagingBuffer() = default; explicit ReusableStagingBuffer(GraphicContext& graphics): m_graphics(graphics) {}
~ReusableStagingBuffer() = default; ~ReusableStagingBuffer() = default;
KYTY_CLASS_NO_COPY(ReusableStagingBuffer); KYTY_CLASS_NO_COPY(ReusableStagingBuffer);
void UploadToBuffer(GraphicContext* ctx, VulkanBuffer* dst_buffer, const void* src_data, void UploadToBuffer(VulkanBuffer& dst_buffer, const void* src_data, uint64_t size,
uint64_t size, uint64_t dst_offset) { uint64_t dst_offset) {
RecordUpload<true>(ctx, src_data, size, [&](CommandBuffer*, vk::CommandBuffer vk_command) { RecordUpload<true>(src_data, size, [&](CommandBuffer&, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier( SetBufferMemoryBarrier(
vk_command, m_buffer.buffer, 0, size, vk::AccessFlagBits::eMemoryWrite, vk_command, m_buffer.buffer, 0, size, vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands, vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
SetBufferMemoryBarrier( 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::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eAllCommands, vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
const vk::BufferCopy copy_region { const vk::BufferCopy copy_region {
.srcOffset = 0, .dstOffset = dst_offset, .size = size}; .srcOffset = 0, .dstOffset = dst_offset, .size = size};
vk_command.copyBuffer(m_buffer.buffer, dst_buffer->buffer, 1, &copy_region); vk_command.copyBuffer(m_buffer.buffer, dst_buffer.buffer, 1, &copy_region);
SetBufferMemoryBarrier( SetBufferMemoryBarrier(
vk_command, dst_buffer->buffer, dst_offset, size, vk_command, dst_buffer.buffer, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndexRead | vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndexRead |
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
@@ -310,61 +310,57 @@ public:
}); });
} }
void UploadToImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size, void UploadToImage(VulkanImage& image, const void* src_data, uint64_t size, uint32_t src_pitch,
uint32_t src_pitch, vk::ImageAspectFlags copy_aspect, vk::ImageAspectFlags copy_aspect, vk::ImageLayout initial_layout,
vk::ImageLayout initial_layout, vk::ImageLayout final_layout) { vk::ImageLayout final_layout) {
const auto transition_aspects = GetTransferAspects(*image, copy_aspect); const auto transition_aspects = GetTransferAspects(image, copy_aspect);
RecordUpload<false>(ctx, src_data, size, [&](CommandBuffer* command, vk::CommandBuffer) { RecordUpload<false>(src_data, size, [&](CommandBuffer& command, vk::CommandBuffer) {
const auto region = MakeBufferImageCopy(0, src_pitch, copy_aspect, 0, 0, {0, 0, 0}, const auto region = MakeBufferImageCopy(0, src_pitch, copy_aspect, 0, 0, {0, 0, 0},
{image->extent.width, image->extent.height, 1}); {image.extent.width, image.extent.height, 1});
RecordBufferToImageCopy(*command, m_buffer, *image, RecordBufferToImageCopy(command, m_buffer, image,
std::span<const vk::BufferImageCopy>(&region, 1), std::span<const vk::BufferImageCopy>(&region, 1),
transition_aspects, initial_layout, final_layout); transition_aspects, initial_layout, final_layout);
}); });
} }
void UploadToImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, void UploadToImage(VulkanImage& dst_image, const void* src_data, uint64_t size,
uint64_t size, std::span<const BufferImageCopy> regions, std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
vk::ImageLayout dst_layout) { RecordUpload<false>(src_data, size, [&](CommandBuffer& command, vk::CommandBuffer) {
RecordUpload<false>(ctx, src_data, size, [&](CommandBuffer* command, vk::CommandBuffer) {
vk::ImageAspectFlags transition_aspects = {}; vk::ImageAspectFlags transition_aspects = {};
for (const auto& region: regions) { 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, RecordBufferToImageCopy(command, m_buffer, dst_image, ConvertBufferImageCopies(regions),
ConvertBufferImageCopies(regions), transition_aspects, transition_aspects, dst_image.layout, dst_layout);
dst_image->layout, dst_layout);
}); });
} }
void DownloadFromImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch, void DownloadFromImage(void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout, VulkanImage& src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect) { vk::ImageAspectFlags aspect) {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst); EnsureBuffer(size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) { ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) {
RecordImageToBuffer(*command, *src_image, m_buffer, dst_pitch, src_layout, aspect); RecordImageToBuffer(command, src_image, m_buffer, dst_pitch, src_layout, aspect);
}); });
std::memcpy(dst_data, m_mapped_data, size); std::memcpy(dst_data, m_mapped_data, size);
} }
void DownloadFromImage(GraphicContext* ctx, void* dst_data, uint64_t size, void DownloadFromImage(void* dst_data, uint64_t size, std::span<const ImageBufferCopy> regions,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, VulkanImage& src_image, vk::ImageLayout src_layout) {
vk::ImageLayout src_layout) { WithDownloadedImage(size, regions, src_image, src_layout,
WithDownloadedImage(ctx, size, regions, src_image, src_layout,
[&](std::span<const uint8_t> data) { [&](std::span<const uint8_t> data) {
std::memcpy(dst_data, data.data(), data.size()); std::memcpy(dst_data, data.data(), data.size());
}); });
} }
void ProcessDownloadedImage(GraphicContext* ctx, uint64_t size, void ProcessDownloadedImage(uint64_t size, std::span<const ImageBufferCopy> regions,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, VulkanImage& src_image, vk::ImageLayout src_layout,
vk::ImageLayout src_layout,
const DownloadedImageConsumer& consumer) { const DownloadedImageConsumer& consumer) {
WithDownloadedImage(ctx, size, regions, src_image, src_layout, WithDownloadedImage(size, regions, src_image, src_layout,
[&](std::span<const uint8_t> data) { [&](std::span<const uint8_t> data) {
if (m_host_cached) { if (m_host_cached) {
consumer(data); consumer(data);
@@ -378,12 +374,12 @@ public:
}); });
} }
void Release(GraphicContext* ctx) { void Release() {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
if (m_buffer.buffer != nullptr) { if (m_buffer.buffer != nullptr) {
EXIT_IF(ctx == nullptr || m_mapped_data == nullptr); EXIT_IF(m_mapped_data == nullptr);
VulkanUnmapMemory(ctx, &m_buffer.memory); m_graphics.UnmapMemory(m_buffer.memory);
VulkanDeleteBuffer(ctx, &m_buffer); m_graphics.DeleteBuffer(m_buffer);
} }
m_capacity = 0; m_capacity = 0;
m_mapped_data = nullptr; m_mapped_data = nullptr;
@@ -392,42 +388,40 @@ public:
private: private:
template <typename Consumer> template <typename Consumer>
void WithDownloadedImage(GraphicContext* ctx, uint64_t size, void WithDownloadedImage(uint64_t size, std::span<const ImageBufferCopy> regions,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, VulkanImage& src_image, vk::ImageLayout src_layout,
vk::ImageLayout src_layout, const Consumer& consumer) { const Consumer& consumer) {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst); EnsureBuffer(size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) { ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) {
RecordImageToBuffer(*command, *src_image, m_buffer, regions, src_layout); RecordImageToBuffer(command, src_image, m_buffer, regions, src_layout);
}); });
consumer(std::span<const uint8_t>(static_cast<const uint8_t*>(m_mapped_data), consumer(std::span<const uint8_t>(static_cast<const uint8_t*>(m_mapped_data),
static_cast<size_t>(size))); static_cast<size_t>(size)));
} }
template <bool WaitIdle, typename Recorder> template <bool WaitIdle, typename Recorder>
void RecordUpload(GraphicContext* ctx, const void* src_data, uint64_t size, void RecordUpload(const void* src_data, uint64_t size, const Recorder& recorder) {
const Recorder& recorder) {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
CopyFromHost(ctx, src_data, size, vk::BufferUsageFlagBits::eTransferSrc); CopyFromHost(src_data, size, vk::BufferUsageFlagBits::eTransferSrc);
if constexpr (WaitIdle) { if constexpr (WaitIdle) {
WaitForGraphicsIdle(ctx); WaitForGraphicsIdle();
} }
ExecuteImmediateCommands(recorder); ExecuteImmediateCommands(recorder);
} }
void CopyFromHost(GraphicContext* ctx, const void* src_data, uint64_t size, void CopyFromHost(const void* src_data, uint64_t size, vk::BufferUsageFlags usage) {
vk::BufferUsageFlags usage) { EnsureBuffer(size, usage);
EnsureBuffer(ctx, size, usage);
std::memcpy(m_mapped_data, src_data, size); 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_capacity < size || m_buffer.usage != usage) {
if (m_buffer.buffer != nullptr) { if (m_buffer.buffer != nullptr) {
VulkanUnmapMemory(ctx, &m_buffer.memory); m_graphics.UnmapMemory(m_buffer.memory);
m_mapped_data = nullptr; m_mapped_data = nullptr;
VulkanDeleteBuffer(ctx, &m_buffer); m_graphics.DeleteBuffer(m_buffer);
} }
m_buffer.usage = usage; m_buffer.usage = usage;
@@ -439,18 +433,19 @@ private:
usage & vk::BufferUsageFlagBits::eTransferDst usage & vk::BufferUsageFlagBits::eTransferDst
? vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eHostCached) ? vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eHostCached)
: vk::MemoryPropertyFlags {}; : vk::MemoryPropertyFlags {};
VulkanCreateBuffer(ctx, size, &m_buffer); m_graphics.CreateBuffer(size, m_buffer);
m_capacity = size; m_capacity = size;
const auto& properties = ctx->GetPhysicalDeviceMemoryProperties(); const auto& properties = m_graphics.GetPhysicalDeviceMemoryProperties();
EXIT_IF(m_buffer.memory.type >= properties.memoryTypeCount); EXIT_IF(m_buffer.memory.type >= properties.memoryTypeCount);
m_host_cached = m_host_cached =
static_cast<bool>(properties.memoryTypes[m_buffer.memory.type].propertyFlags & static_cast<bool>(properties.memoryTypes[m_buffer.memory.type].propertyFlags &
vk::MemoryPropertyFlagBits::eHostCached); 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; Common::Mutex m_mutex;
VulkanBuffer m_buffer; VulkanBuffer m_buffer;
uint64_t m_capacity = 0; uint64_t m_capacity = 0;
@@ -459,10 +454,26 @@ private:
std::vector<uint8_t> m_cached_readback; std::vector<uint8_t> m_cached_readback;
}; };
// Do not replace with one struct TransferResources {
static ReusableStagingBuffer g_texture_staging_buffer; explicit TransferResources(GraphicContext& graphics)
static ReusableStagingBuffer g_vertex_staging_buffer; : graphics(graphics), texture(graphics), vertex(graphics), readback(graphics) {}
static ReusableStagingBuffer g_readback_staging_buffer;
GraphicContext& graphics;
ReusableStagingBuffer texture;
ReusableStagingBuffer vertex;
ReusableStagingBuffer readback;
};
static Common::Mutex g_resources_mutex;
static std::unique_ptr<TransferResources> g_resources;
static TransferResources& GetResources() {
Common::LockGuard lock(g_resources_mutex);
if (!g_resources) {
g_resources = std::make_unique<TransferResources>(GetRenderContext().GetGraphics());
}
return *g_resources;
}
bool IsBlockCompressedFormat(vk::Format format) { bool IsBlockCompressedFormat(vk::Format format) {
return format == vk::Format::eBc1RgbUnormBlock || format == vk::Format::eBc1RgbSrgbBlock || 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) { switch (type) {
case StagingBufferType::Texture: return &g_texture_staging_buffer; case StagingBufferType::Texture: return resources.texture;
case StagingBufferType::Vertex: return &g_vertex_staging_buffer; case StagingBufferType::Vertex: return resources.vertex;
case StagingBufferType::ReadBack: return &g_readback_staging_buffer; case StagingBufferType::ReadBack: return resources.readback;
default: EXIT("unknown staging buffer type\n"); default: EXIT("unknown staging buffer type\n");
} }
return resources.texture;
return nullptr;
} }
void ReleaseCachedResources(GraphicContext* ctx) { void ReleaseCachedResources() {
EXIT_IF(ctx == nullptr); GpuTileRelease();
GpuTileRelease(ctx); Common::LockGuard lock(g_resources_mutex);
g_texture_staging_buffer.Release(ctx); if (g_resources) {
g_vertex_staging_buffer.Release(ctx); g_resources->texture.Release();
g_readback_staging_buffer.Release(ctx); g_resources->vertex.Release();
g_resources->readback.Release();
}
} }
void UploadTiledImage(GraphicContext* ctx, VulkanImage* dst_image, const void* tiled_data, void UploadTiledImage(VulkanImage& dst_image, const void* tiled_data, uint64_t tiled_size,
uint64_t tiled_size, uint64_t linear_size, std::span<const GpuTileInfo> infos, uint64_t linear_size, std::span<const GpuTileInfo> infos,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) { std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
EXIT_IF(ctx == nullptr || dst_image == nullptr || tiled_data == nullptr || regions.empty()); EXIT_IF(tiled_data == nullptr || regions.empty());
GpuDetile(ctx, tiled_data, nullptr, tiled_size, linear_size, infos, GpuDetile(tiled_data, nullptr, tiled_size, linear_size, infos,
[&](CommandBuffer* command, VulkanBuffer* linear) { [&](CommandBuffer& command, VulkanBuffer& linear) {
vk::ImageAspectFlags aspects {}; vk::ImageAspectFlags aspects {};
for (const auto& region: regions) { 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, ConvertBufferImageCopies(regions), aspects,
dst_image->layout, dst_layout); dst_image.layout, dst_layout);
}); });
} }
void DownloadTiledImage(GraphicContext* ctx, void* tiled_data, uint64_t tiled_size, void DownloadTiledImage(void* tiled_data, uint64_t tiled_size, uint64_t linear_size,
uint64_t linear_size, std::span<const GpuTileInfo> infos, std::span<const GpuTileInfo> infos,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, std::span<const ImageBufferCopy> regions, VulkanImage& src_image,
vk::ImageLayout src_layout) { vk::ImageLayout src_layout) {
EXIT_IF(ctx == nullptr || tiled_data == nullptr || src_image == nullptr || regions.empty()); EXIT_IF(tiled_data == nullptr || regions.empty());
GpuTile(ctx, nullptr, tiled_data, tiled_size, linear_size, infos, GpuTile(nullptr, tiled_data, tiled_size, linear_size, infos,
[&](CommandBuffer* command, VulkanBuffer* linear) { [&](CommandBuffer& command, VulkanBuffer& linear) {
RecordImageToBuffer(*command, *src_image, *linear, regions, src_layout, RecordImageToBuffer(command, src_image, linear, regions, src_layout,
vk::AccessFlagBits::eShaderRead, vk::AccessFlagBits::eShaderRead,
vk::PipelineStageFlagBits::eComputeShader); 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, uint32_t levels, vk::ImageAspectFlags aspect_mask,
vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout) { vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout) {
if ((old_image_layout == vk::ImageLayout::eTransferDstOptimal && 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) { 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 " LOGF("set_image_layout: image=%p type=%d tracked=%d requested=%d->%d base=%u "
"levels=%u\n", "levels=%u\n",
VulkanHandleToPointer(dst_image->image), static_cast<int>(dst_image->type), VulkanHandleToPointer(dst_image.image), static_cast<int>(dst_image.type),
static_cast<int>(dst_image->layout), static_cast<int>(old_image_layout), static_cast<int>(dst_image.layout), static_cast<int>(old_image_layout),
static_cast<int>(new_image_layout), base_level, levels); static_cast<int>(new_image_layout), base_level, levels);
} }
} }
if (old_image_layout == new_image_layout) { if (old_image_layout == new_image_layout) {
dst_image->layout = new_image_layout; dst_image.layout = new_image_layout;
return; 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.newLayout = new_image_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = 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.aspectMask = aspect_mask;
image_memory_barrier.subresourceRange.baseMipLevel = base_level; image_memory_barrier.subresourceRange.baseMipLevel = base_level;
image_memory_barrier.subresourceRange.levelCount = levels; image_memory_barrier.subresourceRange.levelCount = levels;
image_memory_barrier.subresourceRange.baseArrayLayer = 0; 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) { switch (old_image_layout) {
case vk::ImageLayout::eColorAttachmentOptimal: 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, buffer.pipelineBarrier(src_stages, dest_stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr,
1, &image_memory_barrier); 1, &image_memory_barrier);
dst_image->layout = new_image_layout; dst_image.layout = new_image_layout;
} }
static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r, static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r,
@@ -674,7 +687,7 @@ static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r,
return 0; 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); auto dst_block_size = BlockCompressedBytesPerBlock(dst_image.format);
if (src_texel_size == 0 || src_texel_size != dst_block_size) { if (src_texel_size == 0 || src_texel_size != dst_block_size) {
return 0; return 0;
@@ -682,16 +695,16 @@ static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r,
auto block_width = (r.width + 3u) / 4u; auto block_width = (r.width + 3u) / 4u;
auto block_height = (r.height + 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 0;
} }
return static_cast<uint64_t>(block_width) * block_height * dst_block_size; return static_cast<uint64_t>(block_width) * block_height * dst_block_size;
} }
static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r, static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r,
VulkanImage* dst_image, VulkanBuffer* copy_buffer) { VulkanImage& dst_image, VulkanBuffer& copy_buffer) {
const auto copy_size = CompressedImageCopyBufferSize(r, *dst_image); const auto copy_size = CompressedImageCopyBufferSize(r, dst_image);
EXIT_IF(copy_size == 0 || copy_buffer == nullptr || copy_buffer->buffer_size < copy_size); EXIT_IF(copy_size == 0 || copy_buffer.buffer_size < copy_size);
const auto block_width = (r.width + 3u) / 4u; const auto block_width = (r.width + 3u) / 4u;
const auto block_height = (r.height + 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, MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.src_level, r.src_layer,
{r.src_x, r.src_y, 0}, {block_width, block_height, 1}); {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, SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor,
src_layout, vk::ImageLayout::eTransferSrcOptimal); 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::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
vk_buffer.copyImageToBuffer(r.src_image->image, vk::ImageLayout::eTransferSrcOptimal, vk_buffer.copyImageToBuffer(r.src_image.image, vk::ImageLayout::eTransferSrcOptimal,
copy_buffer->buffer, 1, &src_region); copy_buffer.buffer, 1, &src_region);
SetBufferMemoryBarrier(vk_buffer, copy_buffer->buffer, 0, VK_WHOLE_SIZE, SetBufferMemoryBarrier(vk_buffer, copy_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
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, MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.dst_level, r.dst_layer,
{r.dst_x, r.dst_y, 0}, {r.width, r.height, 1}); {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); vk::ImageLayout::eTransferDstOptimal, 1, &dst_region);
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor, SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eTransferSrcOptimal, src_layout); vk::ImageLayout::eTransferSrcOptimal, src_layout);
} }
void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions, void CopyImage(CommandBuffer& buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) { VulkanImage& dst_image, vk::ImageLayout dst_layout) {
auto vk_buffer = buffer->Handle(); auto vk_buffer = buffer.Handle();
bool same_image_copy = false; bool same_image_copy = false;
vk::ImageAspectFlags dst_transition_aspects = {}; vk::ImageAspectFlags dst_transition_aspects = {};
for (const auto& r: regions) { for (const auto& r: regions) {
dst_transition_aspects |= GetTransferAspects(*dst_image, r.dst_aspect); dst_transition_aspects |= GetTransferAspects(dst_image, r.dst_aspect);
if (r.src_image == dst_image) { if (&r.src_image == &dst_image) {
same_image_copy = true; same_image_copy = true;
break; break;
} }
@@ -742,7 +755,7 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
if (same_image_copy) { if (same_image_copy) {
SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects, 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) { for (const auto& r: regions) {
vk::ImageCopy region; vk::ImageCopy region;
@@ -761,20 +774,20 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
auto src_layout = vk::ImageLayout::eGeneral; auto src_layout = vk::ImageLayout::eGeneral;
auto restore_layout = vk::ImageLayout::eGeneral; auto restore_layout = vk::ImageLayout::eGeneral;
if (r.src_image != dst_image) { if (&r.src_image != &dst_image) {
restore_layout = r.src_image->layout; restore_layout = r.src_image.layout;
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, 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); vk::ImageLayout::eTransferSrcOptimal);
src_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, &region); vk::ImageLayout::eGeneral, 1, &region);
if (r.src_image != dst_image) { if (&r.src_image != &dst_image) {
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, 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); vk::ImageLayout::eTransferSrcOptimal, restore_layout);
} }
} }
@@ -785,11 +798,11 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
} }
SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects, 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; uint64_t compressed_copy_size = 0;
for (const auto& r: regions) { for (const auto& r: regions) {
compressed_copy_size = 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; VulkanBuffer* compressed_copy_buffer = nullptr;
if (compressed_copy_size != 0) { if (compressed_copy_size != 0) {
@@ -797,17 +810,17 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
compressed_copy_buffer->usage = compressed_copy_buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
compressed_copy_buffer->memory.property = {}; compressed_copy_buffer->memory.property = {};
VulkanCreateBuffer(WindowGetGraphicContext(), compressed_copy_size, compressed_copy_buffer); buffer.GetGraphics().CreateBuffer(compressed_copy_size, *compressed_copy_buffer);
buffer->DeleteAfterFence(compressed_copy_buffer); buffer.DeleteAfterFence(*compressed_copy_buffer);
} }
for (const auto& r: regions) { for (const auto& r: regions) {
vk::ImageCopy region; vk::ImageCopy region;
auto src_layout = r.src_image->layout; auto src_layout = r.src_image.layout;
if (CompressedImageCopyBufferSize(r, *dst_image) != 0) { if (CompressedImageCopyBufferSize(r, dst_image) != 0) {
CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, compressed_copy_buffer); CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, *compressed_copy_buffer);
continue; continue;
} }
@@ -824,14 +837,14 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
region.extent = {r.width, r.height, 1}; region.extent = {r.width, r.height, 1};
SetImageLayout(vk_buffer, r.src_image, r.src_level, 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::ImageLayout::eTransferSrcOptimal);
vk_buffer.copyImage(r.src_image->image, vk::ImageLayout::eTransferSrcOptimal, vk_buffer.copyImage(r.src_image.image, vk::ImageLayout::eTransferSrcOptimal,
dst_image->image, vk::ImageLayout::eTransferDstOptimal, 1, &region); dst_image.image, vk::ImageLayout::eTransferDstOptimal, 1, &region);
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, 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); vk::ImageLayout::eTransferSrcOptimal, src_layout);
} }
@@ -839,59 +852,60 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
vk::ImageLayout::eTransferDstOptimal, dst_layout); vk::ImageLayout::eTransferDstOptimal, dst_layout);
} }
void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image, void CopyImageViaBuffer(CommandBuffer& buffer, VulkanImage& src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image, vk::ImageAspectFlags src_aspect, VulkanImage& dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element, vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout) { vk::ImageLayout dst_layout) {
if (!IsSingleImageAspect(src_aspect) || !IsSingleImageAspect(dst_aspect) || if (!IsSingleImageAspect(src_aspect) || !IsSingleImageAspect(dst_aspect) ||
(bytes_per_element != 2 && bytes_per_element != 4) || src_image->layers != 1 || (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 || 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 == 0 || src_image.extent.height == 0 ||
src_image->extent.width != dst_image->extent.width || src_image.extent.width != dst_image.extent.width ||
src_image->extent.height != dst_image->extent.height) { src_image.extent.height != dst_image.extent.height) {
EXIT("unsupported image-buffer-image copy, src_aspect=0x%x dst_aspect=0x%x bpe=%u " 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", "src=%ux%u/%u/%u dst=%ux%u/%u/%u\n",
static_cast<vk::ImageAspectFlags::MaskType>(src_aspect), static_cast<vk::ImageAspectFlags::MaskType>(src_aspect),
static_cast<vk::ImageAspectFlags::MaskType>(dst_aspect), bytes_per_element, static_cast<vk::ImageAspectFlags::MaskType>(dst_aspect), bytes_per_element,
src_image->extent.width, src_image->extent.height, src_image->layers, src_image.extent.width, src_image.extent.height, src_image.layers,
src_image->mip_levels, dst_image->extent.width, dst_image->extent.height, src_image.mip_levels, dst_image.extent.width, dst_image.extent.height,
dst_image->layers, dst_image->mip_levels); dst_image.layers, dst_image.mip_levels);
} }
const uint64_t row_bytes = static_cast<uint64_t>(src_image->extent.width) * bytes_per_element; const uint64_t row_bytes = static_cast<uint64_t>(src_image.extent.width) * bytes_per_element;
constexpr uint64_t MAX_COPY_BUFFER_SIZE = 16ull * 1024ull * 1024ull; constexpr uint64_t MAX_COPY_BUFFER_SIZE = 16ull * 1024ull * 1024ull;
if (row_bytes == 0 || row_bytes > MAX_COPY_BUFFER_SIZE) { if (row_bytes == 0 || row_bytes > MAX_COPY_BUFFER_SIZE) {
EXIT("unsupported image-buffer-image row size: 0x%016" PRIx64 "\n", row_bytes); EXIT("unsupported image-buffer-image row size: 0x%016" PRIx64 "\n", row_bytes);
} }
const auto rows_per_chunk = static_cast<uint32_t>( const auto rows_per_chunk = static_cast<uint32_t>(
std::min<uint64_t>(src_image->extent.height, MAX_COPY_BUFFER_SIZE / row_bytes)); std::min<uint64_t>(src_image.extent.height, MAX_COPY_BUFFER_SIZE / row_bytes));
const auto copy_buffer_size = row_bytes * rows_per_chunk; const auto copy_buffer_size = row_bytes * rows_per_chunk;
// Kyty does not yet have a cross-queue scheduler. Drain submitted work once before // 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 // 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 // barriers below. The preservation policy stays isolated here so a future scheduler can replace
// this synchronization without changing texture-cache ownership logic. // this synchronization without changing texture-cache ownership logic.
WaitForGraphicsIdle(ctx); auto& graphics = buffer.GetGraphics();
WaitForGraphicsIdle();
auto* copy_buffer = new VulkanBuffer; auto* copy_buffer = new VulkanBuffer;
copy_buffer->usage = copy_buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
copy_buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; copy_buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
VulkanCreateBuffer(ctx, copy_buffer_size, copy_buffer); graphics.CreateBuffer(copy_buffer_size, *copy_buffer);
buffer->DeleteAfterFence(copy_buffer); buffer.DeleteAfterFence(*copy_buffer);
auto vk_buffer = buffer->Handle(); auto vk_buffer = buffer.Handle();
const auto src_layout = src_image->layout; const auto src_layout = src_image.layout;
const auto final_layout = dst_layout; const auto final_layout = dst_layout;
SetImageLayout(vk_buffer, src_image, 0, 1, src_aspect, src_layout, SetImageLayout(vk_buffer, src_image, 0, 1, src_aspect, src_layout,
vk::ImageLayout::eTransferSrcOptimal); 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); vk::ImageLayout::eTransferDstOptimal);
for (uint32_t row = 0; row < src_image->extent.height; row += rows_per_chunk) { 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); 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<int32_t>(row), 0}, auto copy = MakeBufferImageCopy(0, 0, src_aspect, 0, 0, {0, static_cast<int32_t>(row), 0},
{src_image->extent.width, rows, 1}); {src_image.extent.width, rows, 1});
vk_buffer.copyImageToBuffer(src_image->image, vk::ImageLayout::eTransferSrcOptimal, vk_buffer.copyImageToBuffer(src_image.image, vk::ImageLayout::eTransferSrcOptimal,
copy_buffer->buffer, 1, &copy); copy_buffer->buffer, 1, &copy);
SetBufferMemoryBarrier( SetBufferMemoryBarrier(
@@ -900,9 +914,9 @@ void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage*
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
copy.imageSubresource.aspectMask = dst_aspect; 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, &copy); vk::ImageLayout::eTransferDstOptimal, 1, &copy);
if (row + rows < src_image->extent.height) { if (row + rows < src_image.extent.height) {
SetBufferMemoryBarrier( SetBufferMemoryBarrier(
vk_buffer, copy_buffer->buffer, 0, copy_buffer_size, vk_buffer, copy_buffer->buffer, 0, copy_buffer_size,
vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite,
@@ -916,22 +930,20 @@ void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage*
final_layout); final_layout);
} }
void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, void BlitToSwapchain(CommandBuffer& buffer, VulkanImage& src_image,
VulkanSwapchain* dst_swapchain) { VulkanSwapchain& dst_swapchain) {
auto vk_buffer = buffer->Handle(); auto vk_buffer = buffer.Handle();
if (src_image->layout != vk::ImageLayout::eTransferSrcOptimal) { if (src_image.layout != vk::ImageLayout::eTransferSrcOptimal) {
EXIT("invalid prepared presentation image, image=%p vk_image=%p layout=%d\n", EXIT("invalid prepared presentation image, vk_image=%p layout=%d\n",
static_cast<const void*>(src_image), static_cast<void*>(src_image.image), static_cast<int>(src_image.layout));
src_image != nullptr ? static_cast<void*>(src_image->image) : nullptr,
src_image != nullptr ? static_cast<int>(src_image->layout) : -1);
} }
VulkanImage swapchain_image(VulkanImageType::Unknown); 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; 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::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
vk::ImageBlit region {}; vk::ImageBlit region {};
@@ -942,8 +954,8 @@ void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image,
region.srcOffsets[0].x = 0; region.srcOffsets[0].x = 0;
region.srcOffsets[0].y = 0; region.srcOffsets[0].y = 0;
region.srcOffsets[0].z = 0; region.srcOffsets[0].z = 0;
region.srcOffsets[1].x = static_cast<int>(src_image->extent.width); region.srcOffsets[1].x = static_cast<int>(src_image.extent.width);
region.srcOffsets[1].y = static_cast<int>(src_image->extent.height); region.srcOffsets[1].y = static_cast<int>(src_image.extent.height);
region.srcOffsets[1].z = 1; region.srcOffsets[1].z = 1;
region.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; region.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
region.dstSubresource.mipLevel = 0; region.dstSubresource.mipLevel = 0;
@@ -952,135 +964,132 @@ void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image,
region.dstOffsets[0].x = 0; region.dstOffsets[0].x = 0;
region.dstOffsets[0].y = 0; region.dstOffsets[0].y = 0;
region.dstOffsets[0].z = 0; region.dstOffsets[0].z = 0;
region.dstOffsets[1].x = static_cast<int>(dst_swapchain->swapchain_extent.width); region.dstOffsets[1].x = static_cast<int>(dst_swapchain.swapchain_extent.width);
region.dstOffsets[1].y = static_cast<int>(dst_swapchain->swapchain_extent.height); region.dstOffsets[1].y = static_cast<int>(dst_swapchain.swapchain_extent.height);
region.dstOffsets[1].z = 1; 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, &region, swapchain_image.image, vk::ImageLayout::eTransferDstOptimal, 1, &region,
vk::Filter::eLinear); vk::Filter::eLinear);
} }
void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color) { void ClearColorImage(CommandBuffer& buffer, VulkanImage& image, const vk::ClearColorValue& color) {
auto vk_buffer = buffer->Handle(); auto vk_buffer = buffer.Handle();
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image->layout, SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image.layout,
vk::ImageLayout::eTransferDstOptimal); vk::ImageLayout::eTransferDstOptimal);
const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
vk_buffer.clearColorImage(image->image, vk::ImageLayout::eTransferDstOptimal, &color, 1, vk_buffer.clearColorImage(image.image, vk::ImageLayout::eTransferDstOptimal, &color, 1, &range);
&range);
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal); vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal);
} }
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size, uint32_t src_pitch,
uint32_t src_pitch, vk::ImageLayout dst_layout) { vk::ImageLayout dst_layout) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0); EXIT_IF(size == 0);
GetStagingBuffer(StagingBufferType::Texture) GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, dst_image, src_data, size, src_pitch, vk::ImageAspectFlagBits::eColor, .UploadToImage(dst_image, src_data, size, src_pitch, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eUndefined, dst_layout); vk::ImageLayout::eUndefined, dst_layout);
} }
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch, void DownloadImage(void* dst_data, uint64_t size, uint32_t dst_pitch, VulkanImage& src_image,
VulkanImage* src_image, vk::ImageLayout src_layout, vk::ImageLayout src_layout, vk::ImageAspectFlags aspect) {
vk::ImageAspectFlags aspect) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0); EXIT_IF(size == 0);
GetStagingBuffer(StagingBufferType::ReadBack) 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, void DownloadImage(void* dst_data, uint64_t size, std::span<const ImageBufferCopy> regions,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, VulkanImage& src_image, vk::ImageLayout src_layout) {
vk::ImageLayout src_layout) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0 || regions.empty()); EXIT_IF(size == 0 || regions.empty());
GetStagingBuffer(StagingBufferType::ReadBack) 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, void ProcessDownloadedImage(uint64_t size, std::span<const ImageBufferCopy> regions,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, VulkanImage& src_image, vk::ImageLayout src_layout,
vk::ImageLayout src_layout, const DownloadedImageConsumer& consumer) { const DownloadedImageConsumer& consumer) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0 || regions.empty() || !consumer); EXIT_IF(size == 0 || regions.empty() || !consumer);
GetStagingBuffer(StagingBufferType::ReadBack) 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<const BufferImageCopy> regions, vk::ImageLayout dst_layout) { std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
EXIT_IF(size == 0 || regions.empty()); EXIT_IF(size == 0 || regions.empty());
GetStagingBuffer(StagingBufferType::Texture) 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<const ImageImageCopy> regions, void CopyImageImmediate(std::span<const ImageImageCopy> regions, VulkanImage& dst_image,
VulkanImage* dst_image, vk::ImageLayout dst_layout) { vk::ImageLayout dst_layout) {
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) { ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) {
CopyImage(command, regions, dst_image, dst_layout); CopyImage(command, regions, dst_image, dst_layout);
}); });
} }
void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data, void UploadImage(DepthStencilVulkanImage& image, const void* src_data, uint64_t size,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) { uint32_t src_pitch, vk::ImageAspectFlags aspect) {
EXIT_IF(size == 0); EXIT_IF(size == 0);
GetStagingBuffer(StagingBufferType::Texture) GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, image, src_data, size, src_pitch, aspect, image->layout, .UploadToImage(image, src_data, size, src_pitch, aspect, image.layout,
vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::ImageLayout::eDepthStencilAttachmentOptimal);
} }
void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer, void UploadBuffer(StagingBufferType type, VulkanBuffer& dst_buffer, uint64_t dst_offset,
uint64_t dst_offset, const void* src_data, uint64_t size) { const void* src_data, uint64_t size) {
EXIT_IF(size == 0); EXIT_IF(size == 0);
EXIT_IF(dst_offset > dst_buffer->buffer_size || size > dst_buffer->buffer_size - dst_offset); 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); GetStagingBuffer(type).UploadToBuffer(dst_buffer, src_data, size, dst_offset);
} }
void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t 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); EXIT_IF(size == 0 || size > src_buffer.buffer_size || size > dst_buffer.buffer_size);
ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) { ExecuteImmediateCommands([&](CommandBuffer&, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer->buffer, 0, size, SetBufferMemoryBarrier(vk_command, src_buffer.buffer, 0, size,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer); 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::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferWrite,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
const vk::BufferCopy copy_region {.srcOffset = 0, .dstOffset = 0, .size = size}; const vk::BufferCopy copy_region {.srcOffset = 0, .dstOffset = 0, .size = size};
vk_command.copyBuffer(src_buffer->buffer, dst_buffer->buffer, 1, &copy_region); vk_command.copyBuffer(src_buffer.buffer, dst_buffer.buffer, 1, &copy_region);
SetBufferMemoryBarrier( 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::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands); vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands);
}); });
} }
void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset, void DownloadBuffer(VulkanBuffer& src_buffer, uint64_t src_offset, void* dst_data, uint64_t size) {
void* dst_data, uint64_t size) { auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(size == 0); EXIT_IF(size == 0);
EXIT_IF(src_offset > src_buffer->buffer_size || size > src_buffer->buffer_size - src_offset); EXIT_IF(src_offset > src_buffer.buffer_size || size > src_buffer.buffer_size - src_offset);
const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family; const auto family = graphics.queues[GraphicContext::QUEUE_UTIL].family;
EXIT_IF(family == static_cast<uint32_t>(-1)); EXIT_IF(family == static_cast<uint32_t>(-1));
for (int i = GraphicContext::QUEUE_COMPUTE_START; for (int i = GraphicContext::QUEUE_COMPUTE_START;
i < GraphicContext::QUEUE_COMPUTE_START + GraphicContext::QUEUE_COMPUTE_NUM; i++) { 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; void* mapped = nullptr;
VulkanMapMemory(ctx, &src_buffer->memory, &mapped); graphics.MapMemory(src_buffer.memory, mapped);
std::memcpy(dst_data, static_cast<const uint8_t*>(mapped) + src_offset, size); std::memcpy(dst_data, static_cast<const uint8_t*>(mapped) + src_offset, size);
VulkanUnmapMemory(ctx, &src_buffer->memory); graphics.UnmapMemory(src_buffer.memory);
return; return;
} }
@@ -1089,15 +1098,15 @@ void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_
readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible | readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached; vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, size, &readback); graphics.CreateBuffer(size, readback);
ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) { ExecuteImmediateCommands([&](CommandBuffer&, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer->buffer, src_offset, size, SetBufferMemoryBarrier(vk_command, src_buffer.buffer, src_offset, size,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
const vk::BufferCopy copy {.srcOffset = src_offset, .dstOffset = 0, .size = size}; const vk::BufferCopy copy {.srcOffset = src_offset, .dstOffset = 0, .size = size};
vk_command.copyBuffer(src_buffer->buffer, readback.buffer, 1, &copy); vk_command.copyBuffer(src_buffer.buffer, readback.buffer, 1, &copy);
SetBufferMemoryBarrier(vk_command, readback.buffer, 0, size, SetBufferMemoryBarrier(vk_command, readback.buffer, 0, size,
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eHostRead, vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eHostRead,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
@@ -1105,10 +1114,10 @@ void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_
}); });
void* mapped = nullptr; void* mapped = nullptr;
VulkanMapMemory(ctx, &readback.memory, &mapped); graphics.MapMemory(readback.memory, mapped);
std::memcpy(dst_data, mapped, size); std::memcpy(dst_data, mapped, size);
VulkanUnmapMemory(ctx, &readback.memory); graphics.UnmapMemory(readback.memory);
VulkanDeleteBuffer(ctx, &readback); graphics.DeleteBuffer(readback);
} }
} // namespace Libs::Graphics::Transfer } // namespace Libs::Graphics::Transfer
+34 -34
View File
@@ -49,7 +49,9 @@ struct ImageBufferCopy {
}; };
struct ImageImageCopy { struct ImageImageCopy {
VulkanImage* src_image; explicit ImageImageCopy(VulkanImage& source): src_image(source) {}
VulkanImage& src_image;
uint32_t src_level; uint32_t src_level;
uint32_t dst_level; uint32_t dst_level;
uint32_t width; uint32_t width;
@@ -89,52 +91,50 @@ private:
void* m_data = nullptr; void* m_data = nullptr;
}; };
void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions, void CopyImage(CommandBuffer& buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout); VulkanImage& dst_image, vk::ImageLayout dst_layout);
void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image, void CopyImageViaBuffer(CommandBuffer& buffer, VulkanImage& src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image, vk::ImageAspectFlags src_aspect, VulkanImage& dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element, vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout); vk::ImageLayout dst_layout);
void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchain* dst_swapchain); void BlitToSwapchain(CommandBuffer& buffer, VulkanImage& src_image, VulkanSwapchain& dst_swapchain);
void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color); void ClearColorImage(CommandBuffer& buffer, VulkanImage& image, const vk::ClearColorValue& color);
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size, uint32_t src_pitch,
uint32_t src_pitch, vk::ImageLayout dst_layout); vk::ImageLayout dst_layout);
void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* dst_image, const void* src_data, void UploadImage(DepthStencilVulkanImage& dst_image, const void* src_data, uint64_t size,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect); uint32_t src_pitch, vk::ImageAspectFlags aspect);
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout); std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout);
void UploadTiledImage(GraphicContext* ctx, VulkanImage* dst_image, const void* tiled_data, void UploadTiledImage(VulkanImage& dst_image, const void* tiled_data, uint64_t tiled_size,
uint64_t tiled_size, uint64_t linear_size, std::span<const GpuTileInfo> infos, uint64_t linear_size, std::span<const GpuTileInfo> infos,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout); std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout);
void CopyImageImmediate(GraphicContext* ctx, std::span<const ImageImageCopy> regions, void CopyImageImmediate(std::span<const ImageImageCopy> regions, VulkanImage& dst_image,
VulkanImage* dst_image, vk::ImageLayout dst_layout); vk::ImageLayout dst_layout);
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch, void DownloadImage(void* dst_data, uint64_t size, uint32_t dst_pitch, VulkanImage& src_image,
VulkanImage* src_image, vk::ImageLayout src_layout, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor); vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, void DownloadImage(void* dst_data, uint64_t size, std::span<const ImageBufferCopy> regions,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, VulkanImage& src_image, vk::ImageLayout src_layout);
vk::ImageLayout src_layout);
// Invokes consumer synchronously after the image copy fence while the readback staging buffer is // 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 // reserved. The supplied span is valid only for the call; the consumer must not retain it or
// re-enter Transfer. // re-enter Transfer.
void ProcessDownloadedImage(GraphicContext* ctx, uint64_t size, void ProcessDownloadedImage(uint64_t size, std::span<const ImageBufferCopy> regions,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, VulkanImage& src_image, vk::ImageLayout src_layout,
vk::ImageLayout src_layout, const DownloadedImageConsumer& consumer); const DownloadedImageConsumer& consumer);
void DownloadTiledImage(GraphicContext* ctx, void* tiled_data, uint64_t tiled_size, void DownloadTiledImage(void* tiled_data, uint64_t tiled_size, uint64_t linear_size,
uint64_t linear_size, std::span<const GpuTileInfo> infos, std::span<const GpuTileInfo> infos,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, std::span<const ImageBufferCopy> regions, VulkanImage& src_image,
vk::ImageLayout src_layout); vk::ImageLayout src_layout);
void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer, void UploadBuffer(StagingBufferType type, VulkanBuffer& dst_buffer, uint64_t dst_offset,
uint64_t dst_offset, const void* src_data, uint64_t size); const void* src_data, uint64_t size);
void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, 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 DownloadBuffer(VulkanBuffer& src_buffer, uint64_t src_offset, void* dst_data, uint64_t size);
void* dst_data, uint64_t size); void ReleaseCachedResources();
void ReleaseCachedResources(GraphicContext* ctx);
bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size); bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size);
bool IsBlockCompressedFormat(vk::Format format); bool IsBlockCompressedFormat(vk::Format format);
uint32_t BlockCompressedBytesPerBlock(vk::Format format); uint32_t BlockCompressedBytesPerBlock(vk::Format format);
void WaitForGraphicsIdle(GraphicContext* ctx); void WaitForGraphicsIdle();
inline std::pair<int, int> MipmapAtlasOffset(uint32_t lod, uint32_t width, uint32_t height) { inline std::pair<int, int> MipmapAtlasOffset(uint32_t lod, uint32_t width, uint32_t height) {
uint32_t mip_width = width; uint32_t mip_width = width;
+69 -76
View File
@@ -48,34 +48,32 @@ void UntrackAllocationImpl(const VulkanMemory& memory) {
} // namespace } // namespace
void VulkanTrackAllocation(const VulkanMemory* memory) { void VulkanTrackAllocation(const VulkanMemory& memory) {
EXIT_IF(memory == nullptr); TrackAllocationImpl(memory);
TrackAllocationImpl(*memory);
} }
void VulkanUntrackAllocation(const VulkanMemory* memory) { void VulkanUntrackAllocation(const VulkanMemory& memory) {
EXIT_IF(memory == nullptr); UntrackAllocationImpl(memory);
UntrackAllocationImpl(*memory);
} }
bool VulkanCreateAllocator(GraphicContext* ctx) { bool GraphicContext::CreateAllocator() {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->instance == nullptr || ctx->physical_device == nullptr || EXIT_IF(instance == nullptr || physical_device == nullptr || device == nullptr ||
ctx->device == nullptr || ctx->allocator != nullptr); allocator != nullptr);
VmaVulkanFunctions functions {}; VmaVulkanFunctions functions {};
functions.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr; functions.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr;
functions.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr; functions.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr;
VmaAllocatorCreateInfo info {}; VmaAllocatorCreateInfo info {};
info.instance = ctx->instance; info.instance = instance;
info.physicalDevice = ctx->physical_device; info.physicalDevice = physical_device;
info.device = ctx->device; info.device = device;
info.pVulkanFunctions = &functions; info.pVulkanFunctions = &functions;
info.vulkanApiVersion = VULKAN_TARGET_API_VERSION; 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<vk::Result>(vmaCreateAllocator(&info, &ctx->allocator)); const auto result = static_cast<vk::Result>(vmaCreateAllocator(&info, &allocator));
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
LOGF("vmaCreateAllocator failed: %s\n", VulkanToString(result).c_str()); LOGF("vmaCreateAllocator failed: %s\n", VulkanToString(result).c_str());
return false; return false;
@@ -83,12 +81,12 @@ bool VulkanCreateAllocator(GraphicContext* ctx) {
return true; return true;
} }
void VulkanDestroyAllocator(GraphicContext* ctx) { void GraphicContext::DestroyAllocator() {
if (ctx == nullptr || ctx->allocator == nullptr) { if (allocator == nullptr) {
return; return;
} }
vmaDestroyAllocator(ctx->allocator); vmaDestroyAllocator(allocator);
ctx->allocator = nullptr; allocator = nullptr;
} }
uint64_t VulkanNextMemoryUniqueId() { uint64_t VulkanNextMemoryUniqueId() {
@@ -96,14 +94,14 @@ uint64_t VulkanNextMemoryUniqueId() {
return ++sequence; return ++sequence;
} }
void VulkanLogMemoryBudget(GraphicContext* ctx) { void GraphicContext::LogMemoryBudget() const {
if (ctx == nullptr || ctx->allocator == nullptr || ctx->physical_device == nullptr) { if (allocator == nullptr || physical_device == nullptr) {
return; return;
} }
const auto& properties = ctx->GetPhysicalDeviceMemoryProperties(); const auto& properties = GetPhysicalDeviceMemoryProperties();
VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {}; VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {};
vmaGetHeapBudgets(ctx->allocator, budgets); vmaGetHeapBudgets(allocator, budgets);
for (uint32_t i = 0; i < properties.memoryHeapCount; i++) { for (uint32_t i = 0; i < properties.memoryHeapCount; i++) {
LOGF("VMA heap %u: usage=%" PRIu64 ", budget=%" PRIu64 ", allocation=%" PRIu64 LOGF("VMA heap %u: usage=%" PRIu64 ", budget=%" PRIu64 ", allocation=%" PRIu64
", blocks=%" PRIu64 "\n", ", 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(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr || EXIT_IF(allocator == nullptr || buffer.buffer != nullptr ||
buffer->buffer != nullptr || buffer->memory.allocation != nullptr || size == 0); buffer.memory.allocation != nullptr || size == 0);
vk::BufferCreateInfo buffer_info {}; vk::BufferCreateInfo buffer_info {};
buffer_info.sType = vk::StructureType::eBufferCreateInfo; buffer_info.sType = vk::StructureType::eBufferCreateInfo;
buffer_info.size = size; buffer_info.size = size;
buffer_info.usage = buffer->usage; buffer_info.usage = buffer.usage;
buffer_info.sharingMode = vk::SharingMode::eExclusive; buffer_info.sharingMode = vk::SharingMode::eExclusive;
VmaAllocationCreateInfo alloc_info {}; VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags = alloc_info.requiredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(buffer->memory.property); static_cast<vk::MemoryPropertyFlags::MaskType>(buffer.memory.property);
alloc_info.preferredFlags = alloc_info.preferredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(buffer->memory.preferred_property); static_cast<vk::MemoryPropertyFlags::MaskType>(buffer.memory.preferred_property);
vk::Buffer::CType native_buffer = VK_NULL_HANDLE; vk::Buffer::CType native_buffer = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateBuffer( const auto result = static_cast<vk::Result>(vmaCreateBuffer(
ctx->allocator, static_cast<const vk::BufferCreateInfo::NativeType*>(buffer_info), allocator, static_cast<const vk::BufferCreateInfo::NativeType*>(buffer_info), &alloc_info,
&alloc_info, &native_buffer, &buffer->memory.allocation, &buffer->memory.allocation_info)); &native_buffer, &buffer.memory.allocation, &buffer.memory.allocation_info));
buffer->buffer = native_buffer; buffer.buffer = native_buffer;
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(ctx); LogMemoryBudget();
} }
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
ctx->device.getBufferMemoryRequirements(buffer->buffer, &buffer->memory.requirements); device.getBufferMemoryRequirements(buffer.buffer, &buffer.memory.requirements);
buffer->memory.type = buffer->memory.allocation_info.memoryType; buffer.memory.type = buffer.memory.allocation_info.memoryType;
buffer->memory.memory = buffer->memory.allocation_info.deviceMemory; buffer.memory.memory = buffer.memory.allocation_info.deviceMemory;
buffer->memory.offset = buffer->memory.allocation_info.offset; buffer.memory.offset = buffer.memory.allocation_info.offset;
buffer->memory.unique_id = VulkanNextMemoryUniqueId(); buffer.memory.unique_id = VulkanNextMemoryUniqueId();
buffer->buffer_size = size; buffer.buffer_size = size;
VulkanTrackAllocation(&buffer->memory); VulkanTrackAllocation(buffer.memory);
} }
void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer) { void GraphicContext::DeleteBuffer(VulkanBuffer& buffer) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr || EXIT_IF(allocator == nullptr || buffer.buffer == nullptr ||
buffer->buffer == nullptr || buffer->memory.allocation == nullptr); buffer.memory.allocation == nullptr);
VulkanUntrackAllocation(&buffer->memory); VulkanUntrackAllocation(buffer.memory);
vmaDestroyBuffer(ctx->allocator, buffer->buffer, buffer->memory.allocation); vmaDestroyBuffer(allocator, buffer.buffer, buffer.memory.allocation);
buffer->buffer = nullptr; buffer.buffer = nullptr;
buffer->memory.memory = nullptr; buffer.memory.memory = nullptr;
buffer->memory.allocation = nullptr; buffer.memory.allocation = nullptr;
buffer->memory.allocation_info = {}; buffer.memory.allocation_info = {};
buffer->memory.offset = 0; buffer.memory.offset = 0;
} }
bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info, bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanImage& image) {
VulkanImage* image) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr || EXIT_IF(allocator == nullptr || image.image != nullptr || image.memory.allocation != nullptr);
image->image != nullptr || image->memory.allocation != nullptr);
auto& memory = image->memory; auto& memory = image.memory;
VmaAllocationCreateInfo alloc_info {}; VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory.property); alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory.property);
alloc_info.preferredFlags = alloc_info.preferredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(memory.preferred_property); static_cast<vk::MemoryPropertyFlags::MaskType>(memory.preferred_property);
vk::Image::CType native_image = VK_NULL_HANDLE; vk::Image::CType native_image = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateImage( const auto result = static_cast<vk::Result>(
ctx->allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info), vmaCreateImage(allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info),
&alloc_info, &native_image, &memory.allocation, &memory.allocation_info)); &alloc_info, &native_image, &memory.allocation, &memory.allocation_info));
image->image = native_image; image.image = native_image;
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(ctx); LogMemoryBudget();
return false; return false;
} }
ctx->device.getImageMemoryRequirements(image->image, &memory.requirements); device.getImageMemoryRequirements(image.image, &memory.requirements);
memory.type = memory.allocation_info.memoryType; memory.type = memory.allocation_info.memoryType;
memory.memory = memory.allocation_info.deviceMemory; memory.memory = memory.allocation_info.deviceMemory;
memory.offset = memory.allocation_info.offset; memory.offset = memory.allocation_info.offset;
memory.unique_id = VulkanNextMemoryUniqueId(); memory.unique_id = VulkanNextMemoryUniqueId();
VulkanTrackAllocation(&memory); VulkanTrackAllocation(memory);
return true; return true;
} }
void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image) { void GraphicContext::DeleteImage(VulkanImage& image) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr || EXIT_IF(allocator == nullptr || image.image == nullptr || image.memory.allocation == nullptr);
image->image == nullptr || image->memory.allocation == nullptr);
auto& memory = image->memory; auto& memory = image.memory;
VulkanUntrackAllocation(&memory); VulkanUntrackAllocation(memory);
vmaDestroyImage(ctx->allocator, image->image, memory.allocation); vmaDestroyImage(allocator, image.image, memory.allocation);
image->image = nullptr; image.image = nullptr;
memory.memory = nullptr; memory.memory = nullptr;
memory.allocation = nullptr; memory.allocation = nullptr;
memory.allocation_info = {}; memory.allocation_info = {};
memory.offset = 0; memory.offset = 0;
} }
void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data) { void GraphicContext::MapMemory(VulkanMemory& memory, void*& data) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || memory == nullptr || data == nullptr || ctx->allocator == nullptr || EXIT_IF(allocator == nullptr || memory.allocation == nullptr);
memory->allocation == nullptr); EXIT_NOT_IMPLEMENTED(static_cast<vk::Result>(vmaMapMemory(allocator, memory.allocation,
EXIT_NOT_IMPLEMENTED(static_cast<vk::Result>(vmaMapMemory(ctx->allocator, memory->allocation, &data)) != vk::Result::eSuccess);
data)) != vk::Result::eSuccess);
} }
void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory) { void GraphicContext::UnmapMemory(VulkanMemory& memory) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || memory == nullptr || ctx->allocator == nullptr || EXIT_IF(allocator == nullptr || memory.allocation == nullptr);
memory->allocation == nullptr); vmaUnmapMemory(allocator, memory.allocation);
vmaUnmapMemory(ctx->allocator, memory->allocation);
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
+3 -18
View File
@@ -2,28 +2,13 @@
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_VMA_H_ #define EMULATOR_SRC_GRAPHICS_HOST_GPU_VMA_H_
#include "common/common.h" #include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/graphicContext.h"
namespace Libs::Graphics { namespace Libs::Graphics {
struct GraphicContext;
struct VulkanBuffer;
struct VulkanImage;
struct VulkanMemory;
bool VulkanCreateAllocator(GraphicContext* ctx);
void VulkanDestroyAllocator(GraphicContext* ctx);
uint64_t VulkanNextMemoryUniqueId(); uint64_t VulkanNextMemoryUniqueId();
void VulkanTrackAllocation(const VulkanMemory* memory); void VulkanTrackAllocation(const VulkanMemory& memory);
void VulkanUntrackAllocation(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);
} // namespace Libs::Graphics } // namespace Libs::Graphics
+3 -3
View File
@@ -18,9 +18,9 @@ struct DisplayBufferImage {
}; };
DisplayBufferImage DisplayBufferFind(uint64_t addr, bool render_target = false); DisplayBufferImage DisplayBufferFind(uint64_t addr, bool render_target = false);
int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer* buffer, int handle, int index, int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t* request_id); int flip_mode, int64_t flip_arg, uint64_t& request_id);
uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer* buffer); uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer& buffer);
void DisplayBufferCompleteFlipFromGpu(uint64_t request_id); void DisplayBufferCompleteFlipFromGpu(uint64_t request_id);
void DisplayBufferWaitForFlipQueueSlot(); void DisplayBufferWaitForFlipQueueSlot();
+67 -92
View File
@@ -172,16 +172,16 @@ public:
~FlipQueue() { KYTY_NOT_IMPLEMENTED; } ~FlipQueue() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FlipQueue); KYTY_CLASS_NO_COPY(FlipQueue);
bool Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRequestSource source, bool Reserve(VideoOutConfig& cfg, int index, int64_t flip_arg, FlipRequestSource source,
uint64_t* request_id); uint64_t& request_id);
void Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer); void Prepare(uint64_t request_id, Graphics::CommandBuffer& buffer);
uint64_t PrepareNextCpu(Graphics::CommandBuffer* buffer); uint64_t PrepareNextCpu(Graphics::CommandBuffer& buffer);
void Complete(uint64_t request_id); void Complete(uint64_t request_id);
void WaitForSubmitSlot(); void WaitForSubmitSlot();
bool Flip(uint32_t micros); bool Flip(uint32_t micros);
bool HasPending(VideoOutConfig* cfg, int start_index, int count); bool HasPending(VideoOutConfig& cfg, int start_index, int count);
void GetFlipStatus(VideoOutConfig* cfg, VideoOutFlipStatus* out); void GetFlipStatus(VideoOutConfig& cfg, VideoOutFlipStatus& out);
void Wait(VideoOutConfig* cfg, int index); void Wait(VideoOutConfig& cfg, int index);
private: private:
enum class RequestState { Reserved, Recording, Ready, Presenting }; enum class RequestState { Reserved, Recording, Ready, Presenting };
@@ -225,16 +225,6 @@ public:
void Init(uint32_t width, uint32_t height); 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; } FlipQueue& GetFlipQueue() { return m_flip_queue; }
void VblankBegin(); void VblankBegin();
@@ -243,7 +233,6 @@ public:
private: private:
Common::Mutex m_mutex; Common::Mutex m_mutex;
VideoOutConfig m_video_out_ctx[VIDEO_OUT_NUM_MAX]; VideoOutConfig m_video_out_ctx[VIDEO_OUT_NUM_MAX];
Graphics::GraphicContext* m_graphic_ctx = nullptr;
FlipQueue m_flip_queue; FlipQueue m_flip_queue;
}; };
@@ -438,14 +427,12 @@ static void WaitForNextVblank() {
} while (next_vblank_ticks <= now); } while (next_vblank_ticks <= now);
} }
static bool IsFlipDue(VideoOutConfig* cfg) { static bool IsFlipDue(VideoOutConfig& cfg) {
EXIT_IF(cfg == nullptr); 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<uint64_t>(interval)) == 0;
return interval <= 1 || (cfg->vblank_status.count % static_cast<uint64_t>(interval)) == 0;
} }
static bool IsValidBufferIndex(int index) { 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, static int ReserveFlipRequest(int handle, int index, int flip_mode, int64_t flip_arg,
FlipRequestSource source, uint64_t* request_id) { FlipRequestSource source, uint64_t& request_id) {
EXIT_IF(g_video_out_context == nullptr || request_id == nullptr); EXIT_IF(g_video_out_context == nullptr);
auto* video_out = g_video_out_context->Get(handle); auto* video_out = g_video_out_context->Get(handle);
if (video_out == nullptr) { 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))) { (video_out->unregistering[index] || video_out->buffers[index].buffer_vulkan == nullptr))) {
return VIDEO_OUT_ERROR_INVALID_INDEX; 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)) { request_id)) {
return VIDEO_OUT_ERROR_FLIP_QUEUE_FULL; 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"); EXIT("unsupported or invalid video-out surface attributes\n");
} }
Graphics::VideoOutPixelFormatInfo pixel_format {}; 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); EXIT("unsupported video-out pixel format: 0x%016" PRIx64 "\n", attribute.pixel_format);
} }
const auto tile_mode = 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::TileGetTexturePitch(pixel_format.guest_format, attribute.width, 1, tile_mode);
Graphics::TileSizeAlign total {}; Graphics::TileSizeAlign total {};
Graphics::TileGetTextureTotalSize(pixel_format.guest_format, attribute.width, attribute.height, 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) { if (total.size == 0 || total.align != 65536 || (address & (total.align - 1u)) != 0) {
EXIT("invalid video-out surface footprint or alignment\n"); 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"); EXIT("video-out handle is already closing\n");
} }
config.closing = true; 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)) { VIDEO_OUT_BUFFER_NUM_MAX - VIDEO_OUT_BUFFER_INDEX_BLACK)) {
EXIT("cannot close video-out handle with pending flips\n"); EXIT("cannot close video-out handle with pending flips\n");
} }
@@ -629,10 +616,7 @@ void VideoOutContext::Close(int handle) {
} }
} }
if (!images.empty()) { if (!images.empty()) {
if (Graphics::g_render_ctx == nullptr) { Graphics::GetRenderContext().GetTextureCache().UnregisterVideoOutSurfaces(images);
EXIT("cannot unregister video-out surfaces without a render context\n");
}
Graphics::g_render_ctx->GetTextureCache()->UnregisterVideoOutSurfaces(images);
} }
for (auto& buffer: config.buffers) { for (auto& buffer: config.buffers) {
buffer = VideoOutBufferInfo {}; buffer = VideoOutBufferInfo {};
@@ -722,7 +706,7 @@ Presentation::DisplayBufferImage VideoOutContext::FindImage(const void* buffer,
ret.size = ctx.buffers[j].buffer_size; ret.size = ctx.buffers[j].buffer_size;
ret.pitch = ctx.buffers[j].buffer_pitch; ret.pitch = ctx.buffers[j].buffer_pitch;
ret.index = j - set.start_index; ret.index = j - set.start_index;
Graphics::g_render_ctx->GetTextureCache()->RefreshVideoOut(ret.image, Graphics::GetRenderContext().GetTextureCache().RefreshVideoOut(*ret.image,
render_target); render_target);
return ret; return ret;
} }
@@ -732,9 +716,8 @@ Presentation::DisplayBufferImage VideoOutContext::FindImage(const void* buffer,
return ret; return ret;
} }
bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRequestSource source, bool FlipQueue::Reserve(VideoOutConfig& cfg, int index, int64_t flip_arg, FlipRequestSource source,
uint64_t* request_id) { uint64_t& request_id) {
EXIT_IF(cfg == nullptr || request_id == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
if (m_requests.size() + m_cpu_requests.size() >= VIDEO_OUT_FLIP_QUEUE_CAPACITY) { 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 {}; Request r {};
r.id = m_next_request_id++; r.id = m_next_request_id++;
r.cfg = cfg; r.cfg = &cfg;
r.index = index; r.index = index;
r.flip_arg = flip_arg; r.flip_arg = flip_arg;
r.submit_ptc = LibKernel::KernelGetProcessTimeCounter(); 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; r.state = RequestState::Reserved;
pending.push_back(r); pending.push_back(r);
*request_id = r.id; request_id = r.id;
cfg->flip_status.flipPendingNum = static_cast<int>(m_requests.size() + m_cpu_requests.size()); cfg.flip_status.flipPendingNum = static_cast<int>(m_requests.size() + m_cpu_requests.size());
cfg->flip_status.submitProcessTimeCounter = r.submit_ptc; cfg.flip_status.submitProcessTimeCounter = r.submit_ptc;
if (source == FlipRequestSource::GpuEop) { if (source == FlipRequestSource::GpuEop) {
cfg->flip_status.gcQueueNum++; cfg.flip_status.gcQueueNum++;
} }
return true; return true;
} }
void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer) { void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer& buffer) {
EXIT_IF(buffer == nullptr);
VideoOutConfig* cfg = nullptr; VideoOutConfig* cfg = nullptr;
int index = 0; 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) index == VIDEO_OUT_BUFFER_INDEX_BLACK)
: Graphics::WindowPrepareFrame(buffer, source); : Graphics::WindowPrepareFrame(buffer, *source);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
auto request = std::find_if(m_requests.begin(), m_requests.end(), 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) { request->frame != nullptr) {
EXIT("video-out request changed while recording, id=%" PRIu64 "\n", request_id); 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; uint64_t request_id = 0;
{ {
Common::LockGuard lock(m_mutex); 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); Common::LockGuard lock(m_mutex);
auto has_request = [this, cfg, index] { auto has_request = [this, &cfg, index] {
auto matches = [cfg, index](const auto& r) { return r.cfg == cfg && r.index == 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) || return std::any_of(m_requests.begin(), m_requests.end(), matches) ||
std::any_of(m_cpu_requests.begin(), m_cpu_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) { bool FlipQueue::HasPending(VideoOutConfig& cfg, int start_index, int count) {
if (cfg == nullptr || count <= 0 || start_index > INT_MAX - count) { if (count <= 0 || start_index > INT_MAX - count) {
EXIT("invalid video-out pending-flip query range\n"); EXIT("invalid video-out pending-flip query range\n");
} }
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
auto matches = [&](const auto& request) { 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; request.index < start_index + count;
}; };
return std::any_of(m_requests.begin(), m_requests.end(), matches) || return std::any_of(m_requests.begin(), m_requests.end(), matches) ||
@@ -910,7 +891,7 @@ bool FlipQueue::Flip(uint32_t micros) {
m_processing = true; m_processing = true;
auto r = m_requests.front(); auto r = m_requests.front();
m_mutex.Unlock(); m_mutex.Unlock();
if (!IsFlipDue(r.cfg)) { if (!IsFlipDue(*r.cfg)) {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
m_processing = false; m_processing = false;
return false; return false;
@@ -924,7 +905,7 @@ bool FlipQueue::Flip(uint32_t micros) {
m_requests.front().state = RequestState::Presenting; m_requests.front().state = RequestState::Presenting;
m_mutex.Unlock(); m_mutex.Unlock();
Graphics::WindowPresentFrame(r.frame); Graphics::WindowPresentFrame(*r.frame);
m_mutex.Lock(); m_mutex.Lock();
if (m_requests.empty() || m_requests.front().id != r.id || if (m_requests.empty() || m_requests.front().id != r.id ||
@@ -962,13 +943,10 @@ bool FlipQueue::Flip(uint32_t micros) {
return true; return true;
} }
void FlipQueue::GetFlipStatus(VideoOutConfig* cfg, VideoOutFlipStatus* out) { void FlipQueue::GetFlipStatus(VideoOutConfig& cfg, VideoOutFlipStatus& out) {
EXIT_IF(cfg == nullptr);
EXIT_IF(out == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
*out = cfg->flip_status; out = cfg.flip_status;
} }
bool VideoOutFlipWindow(uint32_t micros) { bool VideoOutFlipWindow(uint32_t micros) {
@@ -1116,10 +1094,10 @@ KYTY_SYSV_ABI int VideoOutAddOutputModeEvent(LibKernel::EventQueue::KernelEqueue
return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::OutputMode, udata); 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 void* const* addresses, int buffer_num,
const std::vector<Graphics::VideoOutInfo>& infos) { const std::vector<Graphics::VideoOutInfo>& infos) {
if (ctx == nullptr || addresses == nullptr || buffer_num <= 0 || if (addresses == nullptr || buffer_num <= 0 ||
infos.size() != static_cast<size_t>(buffer_num)) { infos.size() != static_cast<size_t>(buffer_num)) {
EXIT("invalid internal video-out buffer registration arguments\n"); 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::WindowWaitForGraphicInitialized();
Graphics::GraphicsRenderCreateContext(); Graphics::GraphicsRenderCreateContext();
auto* graphic_ctx = g_video_out_context->GetGraphicCtx(); Common::LockGuard lock(ctx.mutex);
Common::LockGuard lock(ctx->mutex); if (ctx.closing) {
if (ctx->closing) {
EXIT("cannot register buffers on a closing video-out handle\n"); 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; })) { [set_id](const auto& set) { return set.set_id == set_id; })) {
return VIDEO_OUT_ERROR_INVALID_INDEX; return VIDEO_OUT_ERROR_INVALID_INDEX;
} }
for (int i = 0; i < buffer_num; i++) { 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"); 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; return VIDEO_OUT_ERROR_SLOT_OCCUPIED;
} }
} }
auto images = auto images = Graphics::GetRenderContext().GetTextureCache().RegisterVideoOutSurfaces(infos);
Graphics::g_render_ctx->GetTextureCache()->RegisterVideoOutSurfaces(graphic_ctx, infos);
if (images.size() != infos.size()) { if (images.size() != infos.size()) {
EXIT("video-out texture cache returned an incomplete surface set\n"); 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++) { 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.set_id = set_id;
dst.buffer = addresses[i]; dst.buffer = addresses[i];
dst.buffer_size = infos[i].size; 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)); infos.push_back(MakeVideoOutInfo(*attribute, data_address, metadata_address, compression));
} }
return RegisterBuffersInternal(ctx, set_index, buffer_index_start, addresses.data(), buffer_num, return RegisterBuffersInternal(*ctx, set_index, buffer_index_start, addresses.data(),
infos); buffer_num, infos);
} }
KYTY_SYSV_ABI int VideoOutSubmitChangeBufferAttribute2(int handle, int set_index, 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); 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"); 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++) { for (int i = set_it->start_index; i < set_it->start_index + set_it->num; i++) {
ctx->buffers[i] = VideoOutBufferInfo {}; ctx->buffers[i] = VideoOutBufferInfo {};
ctx->unregistering[i] = false; 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; uint64_t request_id = 0;
const int result = 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) { if (result == VIDEO_OUT_ERROR_INVALID_VALUE) {
LOGF("\t unsupported flip_mode = %d\n", flip_mode); 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 { namespace Libs::Presentation {
int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer* buffer, int handle, int index, int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t* request_id) { int flip_mode, int64_t flip_arg, 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 || buffer.IsInvalid());
buffer == nullptr || request_id == nullptr);
const int result = VideoOut::ReserveFlipRequest( const int result = VideoOut::ReserveFlipRequest(
handle, index, flip_mode, flip_arg, VideoOut::FlipRequestSource::GpuEop, request_id); handle, index, flip_mode, flip_arg, VideoOut::FlipRequestSource::GpuEop, request_id);
if (result != OK) { if (result != OK) {
return result; return result;
} }
VideoOut::g_video_out_context->GetFlipQueue().Prepare(*request_id, buffer); VideoOut::g_video_out_context->GetFlipQueue().Prepare(request_id, buffer);
return OK; return OK;
} }
uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer* buffer) { uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer& buffer) {
EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr); EXIT_IF(VideoOut::g_video_out_context == nullptr);
return VideoOut::g_video_out_context->GetFlipQueue().PrepareNextCpu(buffer); return VideoOut::g_video_out_context->GetFlipQueue().PrepareNextCpu(buffer);
} }
void DisplayBufferCompleteFlipFromGpu(uint64_t request_id) { 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); VideoOut::g_video_out_context->GetFlipQueue().Complete(request_id);
} }
void DisplayBufferWaitForFlipQueueSlot() { 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(); VideoOut::g_video_out_context->GetFlipQueue().WaitForSubmitSlot();
} }
@@ -1398,7 +1373,7 @@ void VideoOutWaitFlipDone(int handle, int index) {
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_NOT_IMPLEMENTED(!IsValidBufferIndex(index)); 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) { 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; 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" LOGF("\t count = %" PRIu64 "\n"
"\t processTime = %" PRIu64 "\n" "\t processTime = %" PRIu64 "\n"
@@ -1443,7 +1418,7 @@ KYTY_SYSV_ABI int VideoOutIsFlipPending(int handle) {
} }
VideoOutFlipStatus status {}; 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); LOGF("\t flipPendingNum = %d\n", status.flipPendingNum);
+4 -4
View File
@@ -14,15 +14,15 @@ struct PreparedFrame;
vk::SurfaceCapabilitiesKHR* VulkanGetSurfaceCapabilities(); vk::SurfaceCapabilitiesKHR* VulkanGetSurfaceCapabilities();
GraphicContext* WindowGetGraphicContext(); GraphicContext& WindowGetGraphicContext();
void WindowInit(uint32_t width, uint32_t height); void WindowInit(uint32_t width, uint32_t height);
void WindowRun(); void WindowRun();
void WindowWaitForGraphicInitialized(); void WindowWaitForGraphicInitialized();
PreparedFrame* WindowPrepareFrame(CommandBuffer* buffer, VideoOutVulkanImage* image); PreparedFrame& WindowPrepareFrame(CommandBuffer& buffer, VideoOutVulkanImage& image);
PreparedFrame* WindowPrepareBlankFrame(CommandBuffer* buffer, uint32_t width, uint32_t height, PreparedFrame& WindowPrepareBlankFrame(CommandBuffer& buffer, uint32_t width, uint32_t height,
bool opaque); bool opaque);
void WindowPresentFrame(PreparedFrame* frame); void WindowPresentFrame(PreparedFrame& frame);
} // namespace Libs::Graphics } // namespace Libs::Graphics
+76 -83
View File
@@ -138,16 +138,15 @@ static PreparedFramePool* GetPreparedFramePool() {
return pool; return pool;
} }
static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk::Format format) { static void ConfigurePreparedFrame(PreparedFrame& frame, vk::Extent2D extent, vk::Format format) {
EXIT_IF(frame == nullptr);
EXIT_IF(g_window_ctx == nullptr); EXIT_IF(g_window_ctx == nullptr);
if (extent.width == 0 || extent.height == 0 || format == vk::Format::eUndefined) { 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, EXIT("unsupported prepared frame, extent=%ux%u format=%d\n", extent.width, extent.height,
static_cast<int>(format)); static_cast<int>(format));
} }
auto* ctx = &g_window_ctx->graphic_ctx; auto& graphics = g_window_ctx->graphic_ctx;
auto& dst = frame->image; auto& dst = frame.image;
const bool compatible = dst.image != nullptr && dst.extent.width == extent.width && const bool compatible = dst.image != nullptr && dst.extent.width == extent.width &&
dst.extent.height == extent.height && dst.format == format; dst.extent.height == extent.height && dst.format == format;
if (compatible) { if (compatible) {
@@ -155,7 +154,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk
} }
if (dst.image != nullptr) { if (dst.image != nullptr) {
EXIT_IF(!dst.view_cache.views.empty()); EXIT_IF(!dst.view_cache.views.empty());
VulkanDeleteImage(ctx, &dst); graphics.DeleteImage(dst);
dst.memory = {}; dst.memory = {};
} }
@@ -178,7 +177,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk
create.usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst; create.usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
create.sharingMode = vk::SharingMode::eExclusive; create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vk::SampleCountFlagBits::e1; 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", EXIT("failed to allocate prepared presentation image, extent=%ux%u format=%d\n",
dst.extent.width, dst.extent.height, static_cast<int>(dst.format)); dst.extent.width, dst.extent.height, static_cast<int>(dst.format));
} }
@@ -188,28 +187,22 @@ VulkanSwapchain::~VulkanSwapchain() = default;
[[maybe_unused]] static vk::SwapchainKHR VulkanCreateSwapchainInternal( [[maybe_unused]] static vk::SwapchainKHR VulkanCreateSwapchainInternal(
vk::Device device, vk::SurfaceKHR surface, uint32_t width, uint32_t height, vk::Device device, vk::SurfaceKHR surface, uint32_t width, uint32_t height,
uint32_t image_count, SurfaceCapabilities* r, vk::Format* swapchain_format, uint32_t image_count, SurfaceCapabilities& r, vk::Format& swapchain_format,
vk::Extent2D* swapchain_extent, std::unique_ptr<vk::Image[]>* swapchain_images, vk::Extent2D& swapchain_extent, std::unique_ptr<vk::Image[]>& swapchain_images,
std::unique_ptr<vk::ImageView[]>* swapchain_image_views, uint32_t* swapchain_images_count) { std::unique_ptr<vk::ImageView[]>& swapchain_image_views, uint32_t& swapchain_images_count) {
EXIT_IF(device == nullptr); EXIT_IF(device == nullptr);
EXIT_IF(surface == 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 {}; vk::Extent2D extent {};
extent.width = std::clamp(width, r->capabilities.minImageExtent.width, extent.width =
r->capabilities.maxImageExtent.width); std::clamp(width, r.capabilities.minImageExtent.width, r.capabilities.maxImageExtent.width);
extent.height = std::clamp(height, r->capabilities.minImageExtent.height, extent.height = std::clamp(height, r.capabilities.minImageExtent.height,
r->capabilities.maxImageExtent.height); r.capabilities.maxImageExtent.height);
image_count = 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 {}; vk::SwapchainCreateInfoKHR create_info {};
create_info.sType = vk::StructureType::eSwapchainCreateInfoKHR; create_info.sType = vk::StructureType::eSwapchainCreateInfoKHR;
@@ -218,14 +211,14 @@ VulkanSwapchain::~VulkanSwapchain() = default;
create_info.surface = surface; create_info.surface = surface;
create_info.minImageCount = image_count; create_info.minImageCount = image_count;
if (r->format_unorm_bgra32) { if (r.format_unorm_bgra32) {
create_info.imageFormat = vk::Format::eB8G8R8A8Unorm; create_info.imageFormat = vk::Format::eB8G8R8A8Unorm;
create_info.imageColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear; 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.imageFormat = vk::Format::eB8G8R8A8Srgb;
create_info.imageColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear; create_info.imageColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
} else { } else {
const auto& format = r->formats[0]; const auto& format = r.formats[0];
create_info.imageFormat = format.format; create_info.imageFormat = format.format;
create_info.imageColorSpace = format.colorSpace; create_info.imageColorSpace = format.colorSpace;
} }
@@ -237,14 +230,14 @@ VulkanSwapchain::~VulkanSwapchain() = default;
create_info.imageSharingMode = vk::SharingMode::eExclusive; create_info.imageSharingMode = vk::SharingMode::eExclusive;
create_info.queueFamilyIndexCount = 0; create_info.queueFamilyIndexCount = 0;
create_info.pQueueFamilyIndices = nullptr; create_info.pQueueFamilyIndices = nullptr;
create_info.preTransform = r->capabilities.currentTransform; create_info.preTransform = r.capabilities.currentTransform;
create_info.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque; create_info.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
create_info.presentMode = vk::PresentModeKHR::eFifo; create_info.presentMode = vk::PresentModeKHR::eFifo;
create_info.clipped = VK_TRUE; create_info.clipped = VK_TRUE;
create_info.oldSwapchain = nullptr; create_info.oldSwapchain = nullptr;
*swapchain_format = create_info.imageFormat; swapchain_format = create_info.imageFormat;
*swapchain_extent = extent; swapchain_extent = extent;
vk::SwapchainKHR swapchain = nullptr; vk::SwapchainKHR swapchain = nullptr;
@@ -258,19 +251,19 @@ VulkanSwapchain::~VulkanSwapchain() = default;
}); });
EXIT_NOT_IMPLEMENTED(images.empty()); EXIT_NOT_IMPLEMENTED(images.empty());
*swapchain_images_count = static_cast<uint32_t>(images.size()); swapchain_images_count = static_cast<uint32_t>(images.size());
*swapchain_images = std::make_unique<vk::Image[]>(images.size()); swapchain_images = std::make_unique<vk::Image[]>(images.size());
std::copy(images.begin(), images.end(), swapchain_images->get()); std::copy(images.begin(), images.end(), swapchain_images.get());
*swapchain_image_views = std::make_unique<vk::ImageView[]>(*swapchain_images_count); swapchain_image_views = std::make_unique<vk::ImageView[]>(swapchain_images_count);
for (uint32_t i = 0; i < *swapchain_images_count; i++) { for (uint32_t i = 0; i < swapchain_images_count; i++) {
vk::ImageViewCreateInfo create_info {}; vk::ImageViewCreateInfo create_info {};
create_info.sType = vk::StructureType::eImageViewCreateInfo; create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = nullptr; create_info.pNext = nullptr;
create_info.flags = {}; create_info.flags = {};
create_info.image = (*swapchain_images)[i]; create_info.image = (swapchain_images)[i];
create_info.viewType = vk::ImageViewType::e2D; 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.r = vk::ComponentSwizzle::eIdentity;
create_info.components.g = vk::ComponentSwizzle::eIdentity; create_info.components.g = vk::ComponentSwizzle::eIdentity;
create_info.components.b = vk::ComponentSwizzle::eIdentity; create_info.components.b = vk::ComponentSwizzle::eIdentity;
@@ -282,19 +275,19 @@ VulkanSwapchain::~VulkanSwapchain() = default;
create_info.subresourceRange.levelCount = 1; create_info.subresourceRange.levelCount = 1;
RequireVulkanSuccess( RequireVulkanSuccess(
device.createImageView(&create_info, nullptr, &((*swapchain_image_views)[i])), device.createImageView(&create_info, nullptr, &((swapchain_image_views)[i])),
"vkCreateImageView"); "vkCreateImageView");
EXIT_IF((*swapchain_image_views)[i] == nullptr); EXIT_IF((swapchain_image_views)[i] == nullptr);
} }
return swapchain; return swapchain;
} }
VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count) { VulkanSwapchain* VulkanCreateSwapchain(uint32_t image_count) {
EXIT_IF(g_window_ctx == nullptr); EXIT_IF(g_window_ctx == nullptr);
EXIT_IF(ctx == nullptr); auto& graphics = g_window_ctx->graphic_ctx;
EXIT_IF(ctx->screen_width == 0); EXIT_IF(graphics.screen_width == 0);
EXIT_IF(ctx->screen_height == 0); EXIT_IF(graphics.screen_height == 0);
Common::LockGuard lock(g_window_ctx->mutex); Common::LockGuard lock(g_window_ctx->mutex);
@@ -302,9 +295,9 @@ VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count
auto* s = swapchain_owner.get(); auto* s = swapchain_owner.get();
s->swapchain = VulkanCreateSwapchainInternal( s->swapchain = VulkanCreateSwapchainInternal(
ctx->device, g_window_ctx->surface, ctx->screen_width, ctx->screen_height, image_count, graphics.device, g_window_ctx->surface, graphics.screen_width, graphics.screen_height,
g_window_ctx->surface_capabilities, &s->swapchain_format, &s->swapchain_extent, image_count, *g_window_ctx->surface_capabilities, s->swapchain_format, s->swapchain_extent,
&s->swapchain_images, &s->swapchain_image_views, &s->swapchain_images_count); s->swapchain_images, s->swapchain_image_views, s->swapchain_images_count);
if (s->swapchain == nullptr) { if (s->swapchain == nullptr) {
EXIT("Could not create swapchain"); EXIT("Could not create swapchain");
} }
@@ -320,11 +313,11 @@ VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count
s->image_acquired_semaphores = std::make_unique<vk::Semaphore[]>(s->swapchain_images_count); s->image_acquired_semaphores = std::make_unique<vk::Semaphore[]>(s->swapchain_images_count);
s->render_complete_semaphores = std::make_unique<vk::Semaphore[]>(s->swapchain_images_count); s->render_complete_semaphores = std::make_unique<vk::Semaphore[]>(s->swapchain_images_count);
for (uint32_t i = 0; i < s->swapchain_images_count; i++) { for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
auto result = auto result = graphics.device.createSemaphore(&semaphore_info, nullptr,
ctx->device.createSemaphore(&semaphore_info, nullptr, &s->image_acquired_semaphores[i]); &s->image_acquired_semaphores[i]);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
result = ctx->device.createSemaphore(&semaphore_info, nullptr, result = graphics.device.createSemaphore(&semaphore_info, nullptr,
&s->render_complete_semaphores[i]); &s->render_complete_semaphores[i]);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
} }
@@ -333,38 +326,39 @@ VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count
return swapchain_owner.release(); return swapchain_owner.release();
} }
static void VulkanDeleteSwapchain(GraphicContext* ctx, VulkanSwapchain* s) { static void VulkanDeleteSwapchain(VulkanSwapchain* s) {
if (ctx == nullptr || s == nullptr) { if (s == nullptr) {
return; return;
} }
auto swapchain_owner = std::unique_ptr<VulkanSwapchain>(s); auto swapchain_owner = std::unique_ptr<VulkanSwapchain>(s);
auto& graphics = g_window_ctx->graphic_ctx;
Transfer::WaitForGraphicsIdle(ctx); Transfer::WaitForGraphicsIdle();
if (s->image_acquired_semaphores != nullptr) { if (s->image_acquired_semaphores != nullptr) {
for (uint32_t i = 0; i < s->swapchain_images_count; i++) { for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
if (s->image_acquired_semaphores[i] != nullptr) { 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) { if (s->render_complete_semaphores != nullptr) {
for (uint32_t i = 0; i < s->swapchain_images_count; i++) { for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
if (s->render_complete_semaphores[i] != nullptr) { 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) { if (s->swapchain_image_views != nullptr) {
for (uint32_t i = 0; i < s->swapchain_images_count; i++) { for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
if (s->swapchain_image_views[i] != nullptr) { 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) { 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, 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() { static void VulkanRecreateSwapchain() {
@@ -390,61 +384,60 @@ static void VulkanRecreateSwapchain() {
LOGF("Recreating Vulkan swapchain\n"); LOGF("Recreating Vulkan swapchain\n");
VulkanRefreshSurfaceSize(); VulkanRefreshSurfaceSize();
VulkanDeleteSwapchain(&g_window_ctx->graphic_ctx, g_window_ctx->swapchain); VulkanDeleteSwapchain(g_window_ctx->swapchain);
g_window_ctx->swapchain = VulkanCreateSwapchain(&g_window_ctx->graphic_ctx, 2); g_window_ctx->swapchain = VulkanCreateSwapchain(2);
} }
static void ValidatePreparedCommand(CommandBuffer* buffer) { static void ValidatePreparedCommand(CommandBuffer& buffer) {
if (buffer == nullptr || buffer->IsInvalid() || if (buffer.IsInvalid() || buffer.GetQueue() != GraphicContext::QUEUE_GFX) {
buffer->GetQueue() != GraphicContext::QUEUE_GFX) {
EXIT("prepared frames must be recorded on the graphics queue\n"); 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(); KYTY_PROFILER_FUNCTION();
ValidatePreparedCommand(buffer); ValidatePreparedCommand(buffer);
if (image->format == vk::Format::eUndefined) { if (image.format == vk::Format::eUndefined) {
EXIT("unsupported presentation source, image=%p\n", static_cast<const void*>(image)); EXIT("unsupported presentation source, image=%p\n", static_cast<const void*>(&image));
} }
auto* frame = GetPreparedFramePool()->Acquire(); auto* frame = GetPreparedFramePool()->Acquire();
Common::LockGuard render_lock(g_render_ctx->GetMutex()); Common::LockGuard render_lock(GetRenderContext().GetMutex());
g_render_ctx->GetTextureCache()->RefreshVideoOut(image); GetRenderContext().GetTextureCache().RefreshVideoOut(image);
ConfigurePreparedFrame(frame, image->extent, image->format); ConfigurePreparedFrame(*frame, image.extent, image.format);
const std::array copies {ImageImageCopy { ImageImageCopy copy {image};
.src_image = image, .width = image->extent.width, .height = image->extent.height}}; copy.width = image.extent.width;
Transfer::CopyImage(buffer, copies, &frame->image, vk::ImageLayout::eTransferSrcOptimal); copy.height = image.extent.height;
return frame; 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) { bool opaque) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
ValidatePreparedCommand(buffer); ValidatePreparedCommand(buffer);
auto* pool = GetPreparedFramePool(); auto* pool = GetPreparedFramePool();
auto format = pool->GetFormat(); auto format = pool->GetFormat();
auto* frame = pool->Acquire(); auto* frame = pool->Acquire();
Common::LockGuard render_lock(g_render_ctx->GetMutex()); Common::LockGuard render_lock(GetRenderContext().GetMutex());
ConfigurePreparedFrame(frame, {width, height}, format); ConfigurePreparedFrame(*frame, {width, height}, format);
vk::ClearColorValue clear {}; vk::ClearColorValue clear {};
clear.float32[3] = opaque ? 1.0f : 0.0f; clear.float32[3] = opaque ? 1.0f : 0.0f;
Transfer::ClearColorImage(buffer, &frame->image, clear); Transfer::ClearColorImage(buffer, frame->image, clear);
return frame; return *frame;
} }
void WindowPresentFrame(PreparedFrame* frame) { void WindowPresentFrame(PreparedFrame& frame) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(frame == nullptr);
EXIT_IF(g_window_ctx == nullptr); EXIT_IF(g_window_ctx == nullptr);
EXIT_IF(g_window_ctx->swapchain == nullptr); EXIT_IF(g_window_ctx->swapchain == nullptr);
struct ReleaseScope { struct ReleaseScope {
PreparedFrame* frame; PreparedFrame* frame;
~ReleaseScope() { GetPreparedFramePool()->Release(frame); } ~ReleaseScope() { GetPreparedFramePool()->Release(frame); }
}; };
ReleaseScope release {frame}; ReleaseScope release {&frame};
if (g_window_ctx->window_hidden) { if (g_window_ctx->window_hidden) {
WindowUpdateIcon(); WindowUpdateIcon();
@@ -478,17 +471,17 @@ void WindowPresentFrame(PreparedFrame* frame) {
default: EXIT("vkAcquireNextImageKHR failed: %s\n", VulkanToString(result).c_str()); default: EXIT("vkAcquireNextImageKHR failed: %s\n", VulkanToString(result).c_str());
} }
EXIT_NOT_IMPLEMENTED(swapchain->current_index == static_cast<uint32_t>(-1)); EXIT_NOT_IMPLEMENTED(swapchain->current_index == static_cast<uint32_t>(-1));
if (frame->present_commands == nullptr) { if (frame.present_commands == nullptr) {
frame->present_commands = std::make_unique<CommandBuffer>(GraphicContext::QUEUE_GFX); frame.present_commands = std::make_unique<CommandBuffer>(GraphicContext::QUEUE_GFX);
} }
frame->present_commands->WaitForFenceAndReset(); frame.present_commands->WaitForFenceAndReset();
auto& buffer = *frame->present_commands; auto& buffer = *frame.present_commands;
auto vk_buffer = buffer.Handle(); auto vk_buffer = buffer.Handle();
buffer.Begin(); buffer.Begin();
Transfer::BlitToSwapchain(&buffer, &frame->image, swapchain); Transfer::BlitToSwapchain(buffer, frame.image, *swapchain);
vk::ImageMemoryBarrier pre_present_barrier {}; vk::ImageMemoryBarrier pre_present_barrier {};
pre_present_barrier.sType = vk::StructureType::eImageMemoryBarrier; pre_present_barrier.sType = vk::StructureType::eImageMemoryBarrier;
+115 -116
View File
@@ -80,35 +80,35 @@ static bool HasLayer(const std::vector<vk::LayerProperties>& layers, const char*
} }
void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface, void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface,
SurfaceCapabilities* r) { SurfaceCapabilities& r) {
RequireVulkanSuccess(physical_device.getSurfaceCapabilitiesKHR(surface, &r->capabilities), RequireVulkanSuccess(physical_device.getSurfaceCapabilitiesKHR(surface, &r.capabilities),
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
r->formats = EnumerateVulkan<vk::SurfaceFormatKHR>( // @suppress("Ambiguous problem") r.formats = EnumerateVulkan<vk::SurfaceFormatKHR>( // @suppress("Ambiguous problem")
"vkGetPhysicalDeviceSurfaceFormatsKHR", [&](uint32_t* count, vk::SurfaceFormatKHR* values) { "vkGetPhysicalDeviceSurfaceFormatsKHR", [&](uint32_t* count, vk::SurfaceFormatKHR* values) {
return physical_device.getSurfaceFormatsKHR(surface, count, values); return physical_device.getSurfaceFormatsKHR(surface, count, values);
}); });
EXIT_NOT_IMPLEMENTED(r->formats.empty()); EXIT_NOT_IMPLEMENTED(r.formats.empty());
r->present_modes = EnumerateVulkan<vk::PresentModeKHR>( // @suppress("Ambiguous problem") r.present_modes = EnumerateVulkan<vk::PresentModeKHR>( // @suppress("Ambiguous problem")
"vkGetPhysicalDeviceSurfacePresentModesKHR", "vkGetPhysicalDeviceSurfacePresentModesKHR",
[&](uint32_t* count, vk::PresentModeKHR* values) { [&](uint32_t* count, vk::PresentModeKHR* values) {
return physical_device.getSurfacePresentModesKHR(surface, count, 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_srgb_bgra32 = false;
r->format_unorm_bgra32 = false; r.format_unorm_bgra32 = false;
for (const auto& f: r->formats) { for (const auto& f: r.formats) {
if (f.format == vk::Format::eB8G8R8A8Srgb && if (f.format == vk::Format::eB8G8R8A8Srgb &&
f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
r->format_srgb_bgra32 = true; r.format_srgb_bgra32 = true;
} }
if (f.format == vk::Format::eB8G8R8A8Unorm && if (f.format == vk::Format::eB8G8R8A8Unorm &&
f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { 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; break;
} }
} }
@@ -244,13 +244,10 @@ static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR s
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surface, static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surface,
const std::vector<const char*>& device_extensions, const std::vector<const char*>& device_extensions,
SurfaceCapabilities* out_capabilities, SurfaceCapabilities& out_capabilities,
vk::PhysicalDevice* out_device, VulkanQueues* out_queues) { vk::PhysicalDevice& out_device, VulkanQueues& out_queues) {
EXIT_IF(instance == nullptr); EXIT_IF(instance == nullptr);
EXIT_IF(surface == nullptr); EXIT_IF(surface == nullptr);
EXIT_IF(out_capabilities == nullptr);
EXIT_IF(out_device == nullptr);
EXIT_IF(out_queues == nullptr);
auto devices = EnumerateVulkan<vk::PhysicalDevice>( auto devices = EnumerateVulkan<vk::PhysicalDevice>(
"vkEnumeratePhysicalDevices", [&](uint32_t* count, vk::PhysicalDevice* values) { "vkEnumeratePhysicalDevices", [&](uint32_t* count, vk::PhysicalDevice* values) {
@@ -408,7 +405,7 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
SurfaceCapabilities candidate_capabilities; SurfaceCapabilities candidate_capabilities;
if (!skip_device) { if (!skip_device) {
VulkanGetSurfaceCapabilities(device, surface, &candidate_capabilities); VulkanGetSurfaceCapabilities(device, surface, candidate_capabilities);
if (!(candidate_capabilities.capabilities.supportedUsageFlags & if (!(candidate_capabilities.capabilities.supportedUsageFlags &
vk::ImageUsageFlagBits::eTransferDst)) { vk::ImageUsageFlagBits::eTransferDst)) {
@@ -512,16 +509,16 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
} }
} }
*out_device = best_device; out_device = best_device;
*out_queues = best_queues; out_queues = best_queues;
if (best_device != nullptr) { 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(physical_device == nullptr);
EXIT_IF(ctx == nullptr); auto& graphics = g_window_ctx->graphic_ctx;
vk::PhysicalDeviceSubgroupSizeControlProperties subgroup_size_control {}; vk::PhysicalDeviceSubgroupSizeControlProperties subgroup_size_control {};
subgroup_size_control.sType = vk::StructureType::ePhysicalDeviceSubgroupSizeControlProperties; subgroup_size_control.sType = vk::StructureType::ePhysicalDeviceSubgroupSizeControlProperties;
@@ -547,28 +544,26 @@ static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device, Gr
physical_device.getFeatures2(&features2); physical_device.getFeatures2(&features2);
ctx->subgroup_size = properties11.subgroupSize; graphics.subgroup_size = properties11.subgroupSize;
ctx->min_subgroup_size = subgroup_size_control.minSubgroupSize; graphics.min_subgroup_size = subgroup_size_control.minSubgroupSize;
ctx->max_subgroup_size = subgroup_size_control.maxSubgroupSize; graphics.max_subgroup_size = subgroup_size_control.maxSubgroupSize;
ctx->required_subgroup_size_stages = subgroup_size_control.requiredSubgroupSizeStages; graphics.required_subgroup_size_stages = subgroup_size_control.requiredSubgroupSizeStages;
ctx->subgroup_size_control_enabled = features13.subgroupSizeControl == VK_TRUE && graphics.subgroup_size_control_enabled = features13.subgroupSizeControl == VK_TRUE &&
subgroup_size_control.minSubgroupSize <= 64 && subgroup_size_control.minSubgroupSize <= 64 &&
subgroup_size_control.maxSubgroupSize >= 64; subgroup_size_control.maxSubgroupSize >= 64;
LOGF("Vulkan subgroup: default=%u min=%u max=%u stages=0x%08x size_control=%s\n", 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, graphics.subgroup_size, graphics.min_subgroup_size, graphics.max_subgroup_size,
static_cast<vk::ShaderStageFlags::MaskType>(ctx->required_subgroup_size_stages), static_cast<vk::ShaderStageFlags::MaskType>(graphics.required_subgroup_size_stages),
ctx->subgroup_size_control_enabled ? "true" : "false"); graphics.subgroup_size_control_enabled ? "true" : "false");
} }
static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface, static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface,
const VulkanExtensions* r, const VulkanQueues& queues, const VulkanExtensions& r, const VulkanQueues& queues,
const std::vector<const char*>& device_extensions, const std::vector<const char*>& device_extensions) {
GraphicContext* ctx) {
EXIT_IF(physical_device == nullptr); EXIT_IF(physical_device == nullptr);
EXIT_IF(r == nullptr); auto& graphics = g_window_ctx->graphic_ctx;
EXIT_IF(surface == nullptr); EXIT_IF(surface == nullptr);
EXIT_IF(ctx == nullptr);
std::vector<vk::DeviceQueueCreateInfo> queue_create_info(queues.family_count); std::vector<vk::DeviceQueueCreateInfo> queue_create_info(queues.family_count);
std::vector<std::vector<float>> queue_priority(queues.family_count); std::vector<std::vector<float>> queue_priority(queues.family_count);
@@ -647,11 +642,12 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::Sur
device_features.independentBlend = VK_TRUE; device_features.independentBlend = VK_TRUE;
device_features.tessellationShader = VK_TRUE; device_features.tessellationShader = VK_TRUE;
device_features.sampleRateShading = supported_features2.features.sampleRateShading; device_features.sampleRateShading = supported_features2.features.sampleRateShading;
ctx->sample_rate_shading_enabled = device_features.sampleRateShading == VK_TRUE; graphics.sample_rate_shading_enabled = device_features.sampleRateShading == VK_TRUE;
device_features.vertexPipelineStoresAndAtomics = device_features.vertexPipelineStoresAndAtomics =
supported_features2.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; 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.pQueueCreateInfos = queue_create_info.data();
create_info.queueCreateInfoCount = queue_create_info_num; create_info.queueCreateInfoCount = queue_create_info_num;
create_info.enabledLayerCount = create_info.enabledLayerCount =
(r->enable_validation_layers ? static_cast<uint32_t>(r->required_layers.size()) : 0); (r.enable_validation_layers ? static_cast<uint32_t>(r.required_layers.size()) : 0);
create_info.ppEnabledLayerNames = 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<uint32_t>(device_extensions.size()); create_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions.size());
create_info.ppEnabledExtensionNames = device_extensions.data(); create_info.ppEnabledExtensionNames = device_extensions.data();
create_info.pEnabledFeatures = &device_features; create_info.pEnabledFeatures = &device_features;
@@ -703,9 +699,8 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::Sur
return device; return device;
} }
static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) { static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions& r) {
EXIT_IF(window == nullptr); EXIT_IF(window == nullptr);
EXIT_IF(r == nullptr);
uint32_t required_extensions_count = 0; 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(sdl_result == SDL_FALSE);
EXIT_NOT_IMPLEMENTED(required_extensions_count == 0); EXIT_NOT_IMPLEMENTED(required_extensions_count == 0);
r->required_extensions = r.required_extensions =
std::vector<const char*>(required_extensions_count); // @suppress("Ambiguous problem") std::vector<const char*>(required_extensions_count); // @suppress("Ambiguous problem")
std::memset(r->required_extensions.data(), 0, std::memset(r.required_extensions.data(), 0,
sizeof(const char*) * r->required_extensions.size()); sizeof(const char*) * r.required_extensions.size());
sdl_result = SDL_Vulkan_GetInstanceExtensions(window, &required_extensions_count, 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(sdl_result == SDL_FALSE);
EXIT_NOT_IMPLEMENTED(required_extensions_count == 0); 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<vk::ExtensionProperties>( // @suppress("Ambiguous problem") EnumerateVulkan<vk::ExtensionProperties>( // @suppress("Ambiguous problem")
"vkEnumerateInstanceExtensionProperties", "vkEnumerateInstanceExtensionProperties",
[](uint32_t* count, vk::ExtensionProperties* values) { [](uint32_t* count, vk::ExtensionProperties* values) {
return vk::enumerateInstanceExtensionProperties(nullptr, count, 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)) { if (HasExtension(r.available_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
r->required_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); r.required_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
} else { } 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); 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(), LOGF("Vulkan available extension: %s, version = %u\n", ext.extensionName.data(),
ext.specVersion); ext.specVersion);
} }
r->available_layers = EnumerateVulkan<vk::LayerProperties>( // @suppress("Ambiguous problem") r.available_layers = EnumerateVulkan<vk::LayerProperties>( // @suppress("Ambiguous problem")
"vkEnumerateInstanceLayerProperties", [](uint32_t* count, vk::LayerProperties* values) { "vkEnumerateInstanceLayerProperties", [](uint32_t* count, vk::LayerProperties* values) {
return vk::enumerateInstanceLayerProperties(count, 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", LOGF("Vulkan available layer: %s, specVersion = %u, implVersion = %u, %s\n",
l.layerName.data(), l.specVersion, l.implementationVersion, l.description.data()); 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) { if (r.enable_validation_layers) {
for (const char* l: r->required_layers) { for (const char* l: r.required_layers) {
if (!HasLayer(r->available_layers, l)) { if (!HasLayer(r.available_layers, l)) {
LOGF("no validation layer: %s\n", l); LOGF("no validation layer: %s\n", l);
r->enable_validation_layers = false; r.enable_validation_layers = false;
break; break;
} }
} }
} }
if (r->enable_validation_layers) { if (r.enable_validation_layers) {
auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>( auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>(
"vkEnumerateInstanceExtensionProperties", "vkEnumerateInstanceExtensionProperties",
[](uint32_t* count, vk::ExtensionProperties* values) { [](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)) { 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 { } 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; return vk::Result::eErrorExtensionNotPresent;
} }
static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues) { static void VulkanCreateQueues(const VulkanQueues& queues) {
EXIT_IF(ctx == nullptr); auto& graphics = g_window_ctx->graphic_ctx;
EXIT_IF(ctx->device == nullptr); EXIT_IF(graphics.device == nullptr);
EXIT_IF(queues.graphics.size() != 1); EXIT_IF(queues.graphics.size() != 1);
EXIT_IF(queues.present.size() != 1); EXIT_IF(queues.present.size() != 1);
EXIT_IF(!(queues.compute.size() >= 1 && EXIT_IF(!(queues.compute.size() >= 1 &&
queues.compute.size() <= GraphicContext::QUEUE_COMPUTE_NUM)); queues.compute.size() <= GraphicContext::QUEUE_COMPUTE_NUM));
auto get_queue = [ctx](int id, const QueueInfo& info) { auto get_queue = [&graphics](int id, const QueueInfo& info) {
ctx->queues[id].family = info.family; graphics.queues[id].family = info.family;
ctx->queues[id].index = info.index; graphics.queues[id].index = info.index;
EXIT_IF(ctx->queues[id].vk_queue != nullptr); EXIT_IF(graphics.queues[id].vk_queue != nullptr);
ctx->device.getQueue(ctx->queues[id].family, ctx->queues[id].index, graphics.device.getQueue(graphics.queues[id].family, graphics.queues[id].index,
&ctx->queues[id].vk_queue); &graphics.queues[id].vk_queue);
EXIT_NOT_IMPLEMENTED(ctx->queues[id].vk_queue == nullptr); EXIT_NOT_IMPLEMENTED(graphics.queues[id].vk_queue == nullptr);
}; };
get_queue(GraphicContext::QUEUE_GFX, queues.graphics[0]); get_queue(GraphicContext::QUEUE_GFX, queues.graphics[0]);
ctx->queues[GraphicContext::QUEUE_UTIL].family = ctx->queues[GraphicContext::QUEUE_GFX].family; graphics.queues[GraphicContext::QUEUE_UTIL].family =
ctx->queues[GraphicContext::QUEUE_UTIL].index = ctx->queues[GraphicContext::QUEUE_GFX].index; graphics.queues[GraphicContext::QUEUE_GFX].family;
ctx->queues[GraphicContext::QUEUE_UTIL].vk_queue = graphics.queues[GraphicContext::QUEUE_UTIL].index =
ctx->queues[GraphicContext::QUEUE_GFX].vk_queue; 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 " LOGF("Vulkan queue: using graphics queue for utility submissions to preserve resource "
"ordering\n"); "ordering\n");
get_queue(GraphicContext::QUEUE_PRESENT, queues.present[0]); 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++) { for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) {
auto& queue = ctx->queues[id]; auto& queue = graphics.queues[id];
if (queue.vk_queue == nullptr) { if (queue.vk_queue == nullptr) {
continue; continue;
} }
EXIT_IF(queue.mutex != nullptr); EXIT_IF(queue.mutex != nullptr);
for (int other_id = 0; other_id < id; other_id++) { 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) { if (other.vk_queue != queue.vk_queue) {
continue; continue;
} }
@@ -921,7 +918,7 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues)
} }
if (queue.mutex == nullptr) { 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) { void VulkanCreate(WindowContext& window) {
EXIT_IF(ctx->window == nullptr); EXIT_IF(window.window == nullptr);
EXIT_IF(ctx->graphic_ctx.instance != nullptr); EXIT_IF(window.graphic_ctx.instance != nullptr);
EXIT_IF(ctx->graphic_ctx.physical_device != nullptr); EXIT_IF(window.graphic_ctx.physical_device != nullptr);
EXIT_IF(ctx->graphic_ctx.device != nullptr); EXIT_IF(window.graphic_ctx.device != nullptr);
EXIT_IF(ctx->surface_capabilities != nullptr); EXIT_IF(window.surface_capabilities != nullptr);
auto get_instance_proc_addr = auto get_instance_proc_addr =
reinterpret_cast<PFN_vkGetInstanceProcAddr>(SDL_Vulkan_GetVkGetInstanceProcAddr()); reinterpret_cast<PFN_vkGetInstanceProcAddr>(SDL_Vulkan_GetVkGetInstanceProcAddr());
@@ -961,7 +958,7 @@ void VulkanCreate(WindowContext* ctx) {
VULKAN_HPP_DEFAULT_DISPATCHER.init(get_instance_proc_addr); VULKAN_HPP_DEFAULT_DISPATCHER.init(get_instance_proc_addr);
VulkanExtensions r; VulkanExtensions r;
VulkanGetExtensions(ctx->window, &r); VulkanGetExtensions(window.window, r);
VulkanCheckInstanceVersion(); VulkanCheckInstanceVersion();
vk::ApplicationInfo app_info {}; vk::ApplicationInfo app_info {};
@@ -1025,31 +1022,31 @@ void VulkanCreate(WindowContext* ctx) {
inst_info.ppEnabledLayerNames = inst_info.ppEnabledLayerNames =
(r.enable_validation_layers ? r.required_layers.data() : nullptr); (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) { switch (result) {
case vk::Result::eSuccess: break; case vk::Result::eSuccess: break;
case vk::Result::eErrorIncompatibleDriver: case vk::Result::eErrorIncompatibleDriver:
EXIT("Unable to find a compatible Vulkan Driver"); EXIT("Unable to find a compatible Vulkan Driver");
default: EXIT("Could not create a Vulkan instance (for unknown reasons)"); 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) { if (r.enable_validation_layers) {
dbg_create_info.pNext = nullptr; dbg_create_info.pNext = nullptr;
if (VulkanCreateDebugUtilsMessengerEXT(ctx->graphic_ctx.instance, &dbg_create_info, nullptr, if (VulkanCreateDebugUtilsMessengerEXT(window.graphic_ctx.instance, &dbg_create_info,
&ctx->graphic_ctx.debug_messenger) != nullptr, &window.graphic_ctx.debug_messenger) !=
vk::Result::eSuccess) { vk::Result::eSuccess) {
EXIT("Could not create debug messenger"); EXIT("Could not create debug messenger");
} }
} }
vk::SurfaceKHR::CType native_surface = VK_NULL_HANDLE; vk::SurfaceKHR::CType native_surface = VK_NULL_HANDLE;
if (SDL_Vulkan_CreateSurface(ctx->window, if (SDL_Vulkan_CreateSurface(window.window,
static_cast<vk::Instance::CType>(ctx->graphic_ctx.instance), static_cast<vk::Instance::CType>(window.graphic_ctx.instance),
&native_surface) == SDL_FALSE) { &native_surface) == SDL_FALSE) {
EXIT("Could not create a Vulkan surface"); EXIT("Could not create a Vulkan surface");
} }
ctx->surface = native_surface; window.surface = native_surface;
std::vector<const char*> device_extensions = { std::vector<const char*> device_extensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME,
@@ -1062,21 +1059,23 @@ void VulkanCreate(WindowContext* ctx) {
} }
#endif #endif
ctx->surface_capabilities = new SurfaceCapabilities {}; window.surface_capabilities = new SurfaceCapabilities {};
VulkanQueues queues; VulkanQueues queues;
VulkanFindPhysicalDevice(ctx->graphic_ctx.instance, ctx->surface, device_extensions, VulkanFindPhysicalDevice(window.graphic_ctx.instance, window.surface, device_extensions,
ctx->surface_capabilities, &ctx->graphic_ctx.physical_device, &queues); *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"); EXIT("Could not find suitable device");
} }
ctx->graphic_ctx.physical_device.getProperties(&ctx->graphic_ctx.physical_device_properties); window.graphic_ctx.physical_device.getProperties(
ctx->graphic_ctx.physical_device.getMemoryProperties( &window.graphic_ctx.physical_device_properties);
&ctx->graphic_ctx.physical_device_memory_properties); window.graphic_ctx.physical_device.getMemoryProperties(
const auto& device_properties = ctx->graphic_ctx.GetPhysicalDeviceProperties(); &window.graphic_ctx.physical_device_memory_properties);
const auto& device_properties = window.graphic_ctx.GetPhysicalDeviceProperties();
LOGF("Select device: %s\n", device_properties.deviceName.data()); LOGF("Select device: %s\n", device_properties.deviceName.data());
@@ -1084,40 +1083,40 @@ void VulkanCreate(WindowContext* ctx) {
auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>( auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>(
"vkEnumerateDeviceExtensionProperties", "vkEnumerateDeviceExtensionProperties",
[&](uint32_t* count, vk::ExtensionProperties* values) { [&](uint32_t* count, vk::ExtensionProperties* values) {
return ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties( return window.graphic_ctx.physical_device.enumerateDeviceExtensionProperties(
nullptr, count, values); nullptr, count, values);
}); });
if (HasExtension(available_extensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) { if (HasExtension(available_extensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) {
device_extensions.push_back(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)) { if (HasExtension(available_extensions, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) {
device_extensions.push_back(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)); memcpy(window.device_name, device_properties.deviceName, sizeof(window.device_name));
std::snprintf(ctx->processor_name, sizeof(ctx->processor_name), "%s", std::snprintf(window.processor_name, sizeof(window.processor_name), "%s",
Common::GetSystemInfo().ProcessorName.c_str()); 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, window.graphic_ctx.device = VulkanCreateDevice(window.graphic_ctx.physical_device,
queues, device_extensions, &ctx->graphic_ctx); window.surface, r, queues, device_extensions);
if (ctx->graphic_ctx.device == nullptr) { if (window.graphic_ctx.device == nullptr) {
EXIT("Could not create device"); 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"); EXIT("Could not create Vulkan memory allocator");
} }
VulkanCreateQueues(&ctx->graphic_ctx, queues); VulkanCreateQueues(queues);
ctx->swapchain = VulkanCreateSwapchain(&ctx->graphic_ctx, 2); window.swapchain = VulkanCreateSwapchain(2);
RenderDocSetActiveWindow(ctx->graphic_ctx.instance, ctx->window); RenderDocSetActiveWindow(window.graphic_ctx.instance, window.window);
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
+159 -193
View File
@@ -234,11 +234,11 @@ struct WindowGame {
}; };
struct WindowGamePrivate { struct WindowGamePrivate {
WindowGamePrivate() = default; explicit WindowGamePrivate(GraphicContext& graphics): graphics(graphics) {}
Common::Mutex mutex; Common::Mutex mutex;
int skip_frames = 0; int skip_frames = 0;
GraphicContext* ctx = nullptr; GraphicContext& graphics;
}; };
WindowContext* g_window_ctx = nullptr; WindowContext* g_window_ctx = nullptr;
@@ -248,58 +248,58 @@ constexpr uint32_t KYTY_SDL_WINDOW_FLAGS =
(static_cast<uint32_t>(SDL_WINDOW_HIDDEN) | static_cast<uint32_t>(SDL_WINDOW_VULKAN)); (static_cast<uint32_t>(SDL_WINDOW_HIDDEN) | static_cast<uint32_t>(SDL_WINDOW_VULKAN));
constexpr int KYTY_SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED; /*NOLINT(hicpp-signed-bitwise)*/ constexpr int KYTY_SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED; /*NOLINT(hicpp-signed-bitwise)*/
static void CalcFrameTime(WindowGame* game, double game_time_s) { static void CalcFrameTime(WindowGame& game, double game_time_s) {
game->m_previous_time_seconds = game->m_current_time_seconds; game.m_previous_time_seconds = game.m_current_time_seconds;
game->m_current_time_seconds = game_time_s; game.m_current_time_seconds = game_time_s;
game->m_frame_num++; game.m_frame_num++;
game->m_fps_frames_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) { if (fps_time > FPS_UPDATE_TIME) {
game->m_current_fps = static_cast<double>(game->m_fps_frames_num) / fps_time; game.m_current_fps = static_cast<double>(game.m_fps_frames_num) / fps_time;
game->m_fps_frames_num = 0; game.m_fps_frames_num = 0;
game->m_fps_start_time = game->m_current_time_seconds; game.m_fps_start_time = game.m_current_time_seconds;
} }
} }
static bool Init(WindowGame* /*game*/) { static bool Init(WindowGame& /*game*/) {
return true; return true;
} }
static bool Update(WindowGame* /*game*/) { static bool Update(WindowGame& /*game*/) {
return true; return true;
} }
static bool Render(WindowGame* /*game*/) { static bool Render(WindowGame& /*game*/) {
return true; return true;
} }
static bool Close(WindowGame* /*game*/) { static bool Close(WindowGame& /*game*/) {
return true; return true;
} }
static void SetPause(WindowGame* game, bool flag) { static void SetPause(WindowGame& game, bool flag) {
LOGF("Pause: %s\n", flag ? "true" : "false"); 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; 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; int num = 0;
bool ok = true; bool ok = true;
while (lag >= game->m_update_fixed_time) { while (lag >= game.m_update_fixed_time) {
if (num < game->m_max_updates_per_frame) { if (num < game.m_max_updates_per_frame) {
ok = ok && Update(game); ok = ok && Update(game);
game->m_update_num++; game.m_update_num++;
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); ok = ok && Render(game);
@@ -307,44 +307,36 @@ static bool RenderAndUpdate(WindowGame* game) {
return ok; return ok;
} }
bool GameInit(WindowGame* game, const Common::Timer& timer, void* data) { bool GameInit(WindowGame& game, const Common::Timer& timer) {
EXIT_IF(game == nullptr); EXIT_IF(game.private_data || game.event);
EXIT_IF(data == nullptr); auto& graphics = WindowGetGraphicContext();
EXIT_IF(game->private_data || game->event);
auto* ctx = static_cast<GraphicContext*>(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; game.private_data = pdata;
pdata->ctx = ctx; game.event = new SDL_Event;
game->private_data = pdata; game.m_screen_width = graphics.screen_width;
game->event = new SDL_Event; game.m_screen_height = graphics.screen_height;
game->m_screen_width = ctx->screen_width;
game->m_screen_height = ctx->screen_height;
CalcFrameTime(game, timer.GetTimeS()); CalcFrameTime(game, timer.GetTimeS());
return Init(game); return Init(game);
} }
bool GameClose(WindowGame* game) { bool GameClose(WindowGame& game) {
EXIT_IF(!game); EXIT_IF(!game.private_data || !game.event);
EXIT_IF(!game->private_data || !game->event); delete (static_cast<WindowGamePrivate*>(game.private_data));
delete (static_cast<SDL_Event*>(game.event));
delete (static_cast<WindowGamePrivate*>(game->private_data));
delete (static_cast<SDL_Event*>(game->event));
return Close(game); return Close(game);
} }
void GameShowWindow(WindowGame* game, const Common::Timer& timer) { void GameShowWindow(WindowGame& game, const Common::Timer& timer) {
EXIT_IF(!game); auto* p = static_cast<WindowGamePrivate*>(game.private_data);
auto* p = static_cast<WindowGamePrivate*>(game->private_data);
EXIT_IF(!p); EXIT_IF(!p);
@@ -364,33 +356,33 @@ void GameShowWindow(WindowGame* game, const Common::Timer& timer) {
p->mutex.Unlock(); p->mutex.Unlock();
} }
void GameEventQuit(WindowGame* game) { void GameEventQuit(WindowGame& game) {
LOGF("Event: quit\n"); 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"); 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 #ifdef KYTY_DBG_INPUT
LOGF("Key: time = %.04f, %s%s, %s%s, %s, scan = %d, key = %d, mod = %04" PRIx16 "\n", 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.timestamp_seconds, (key.down ? "down" : ""), (key.up ? "up" : ""),
(key->pressed ? "pressed" : ""), (key->released ? "released" : ""), (key.pressed ? "pressed" : ""), (key.released ? "released" : ""),
(key->repeat ? "repeat" : ""), key->scan_code, key->key_code, key->mod); (key.repeat ? "repeat" : ""), key.scan_code, key.key_code, key.mod);
#endif #endif
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX
if (key->down) { if (key.down) {
switch (key->key_code) { switch (key.key_code) {
case SDLK_ESCAPE: game->m_game_need_exit = true; break; case SDLK_ESCAPE: game.m_game_need_exit = true; break;
case SDLK_SPACE: SetPause(game, !game->m_game_is_paused); break; case SDLK_SPACE: SetPause(game, !game.m_game_is_paused); break;
case SDLK_F1: case SDLK_F1:
if (!key->repeat) { if (!key.repeat) {
RenderDocRequestCapture(); RenderDocRequestCapture();
} }
break; break;
@@ -398,159 +390,153 @@ void GameEventKeyboard(WindowGame* game, const EventKeyboard* key) {
} }
} }
const auto button = KeyboardKeyToPadButton(key->key_code); const auto button = KeyboardKeyToPadButton(key.key_code);
if (button != 0 && (key->down || key->up) && !key->repeat) { if (button != 0 && (key.down || key.up) && !key.repeat) {
static bool keyboard_connected = false; static bool keyboard_connected = false;
if (!keyboard_connected) { if (!keyboard_connected) {
Controller::ControllerConnect(KEYBOARD_CONTROLLER_ID); Controller::ControllerConnect(KEYBOARD_CONTROLLER_ID);
keyboard_connected = true; keyboard_connected = true;
} }
Controller::ControllerButton(KEYBOARD_CONTROLLER_ID, button, key->down); Controller::ControllerButton(KEYBOARD_CONTROLLER_ID, button, key.down);
} }
#endif #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 #ifdef KYTY_DBG_INPUT
if (mb->wheel) { if (mb.wheel) {
LOGF("Mouse wheel: time = %.04f, %s[%d, %d]\n", mb->timestamp_seconds, LOGF("Mouse wheel: time = %.04f, %s[%d, %d]\n", mb.timestamp_seconds,
(mb->touch ? "touch, " : ""), mb->x, mb->y); (mb.touch ? "touch, " : ""), mb.x, mb.y);
} else if (mb->motion) { } else if (mb.motion) {
LOGF("Mouse motion: time = %.04f, %s%s%s%s%s%s, [%d, %d], (%d, %d)\n", LOGF("Mouse motion: time = %.04f, %s%s%s%s%s%s, [%d, %d], (%d, %d)\n", mb.timestamp_seconds,
mb->timestamp_seconds, (mb->left ? "left" : ""), (mb->middle ? "middle" : ""), (mb.left ? "left" : ""), (mb.middle ? "middle" : ""), (mb.right ? "right" : ""),
(mb->right ? "right" : ""), (mb->x1 ? "x1" : ""), (mb->x2 ? "x2" : ""), (mb.x1 ? "x1" : ""), (mb.x2 ? "x2" : ""), (mb.touch ? "_touch" : ""), mb.x, mb.y,
(mb->touch ? "_touch" : ""), mb->x, mb->y, mb->motion_x, mb->motion_y); mb.motion_x, mb.motion_y);
} else { } else {
LOGF("Mouse click: time = %.04f, %d, %s%s%s%s%s%s, %s%s, %s%s, [%d, %d]\n", 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.timestamp_seconds, mb.num_of_clicks, (mb.left ? "left" : ""),
(mb->middle ? "middle" : ""), (mb->right ? "right" : ""), (mb->x1 ? "x1" : ""), (mb.middle ? "middle" : ""), (mb.right ? "right" : ""), (mb.x1 ? "x1" : ""),
(mb->x2 ? "x2" : ""), (mb->touch ? "_touch" : ""), (mb->down ? "down" : ""), (mb.x2 ? "x2" : ""), (mb.touch ? "_touch" : ""), (mb.down ? "down" : ""),
(mb->up ? "up" : ""), (mb->pressed ? "pressed" : ""), (mb->released ? "released" : ""), (mb.up ? "up" : ""), (mb.pressed ? "pressed" : ""), (mb.released ? "released" : ""),
mb->x, mb->y); mb.x, mb.y);
} }
#endif #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 #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 " LOGF("Finger motion: time = %.04f, %d, %d, (x,y) = [%f, %f], (dx,dy) = [%f, %f], pressure "
"= %f\n", "= %f\n",
f->timestamp_seconds, f->touch_id, f->finger_id, f->x, f->y, f->dx, f->dy, f.timestamp_seconds, f.touch_id, f.finger_id, f.x, f.y, f.dx, f.dy, f.pressure);
f->pressure);
} else { } else {
LOGF("Finger press: time = %.04f, %d, %d, %s%s, (x,y) = [%f, %f], (dx,dy) = [%f, %f], " LOGF("Finger press: time = %.04f, %d, %d, %s%s, (x,y) = [%f, %f], (dx,dy) = [%f, %f], "
"pressure = %f\n", "pressure = %f\n",
f->timestamp_seconds, f->touch_id, f->finger_id, (f->down ? "down" : ""), 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.up ? "up" : ""), f.x, f.y, f.dx, f.dy, f.pressure);
} }
#endif #endif
} }
void GameEventController([[maybe_unused]] WindowGame* game, void GameEventController([[maybe_unused]] WindowGame& game,
[[maybe_unused]] const EventController* f) { [[maybe_unused]] const EventController& f) {
EXIT_NOT_IMPLEMENTED(f->remapped); EXIT_NOT_IMPLEMENTED(f.remapped);
#ifdef KYTY_DBG_INPUT #ifdef KYTY_DBG_INPUT
if (f->added || f->removed) { if (f.added || f.removed) {
LOGF("Controller %s: %d, time = %.04f\n", (f->added ? "added" : "removed"), f->id, LOGF("Controller %s: %d, time = %.04f\n", (f.added ? "added" : "removed"), f.id,
f->timestamp_seconds); f.timestamp_seconds);
} else if (f->axis) { } else if (f.axis) {
LOGF("Controller axis: %d, axis = %d, value = %d, time = %.04f\n", f->id, f->axis_id, LOGF("Controller axis: %d, axis = %d, value = %d, time = %.04f\n", f.id, f.axis_id,
f->axis_value, f->timestamp_seconds); f.axis_value, f.timestamp_seconds);
} else { } else {
LOGF("Controller button: " LOGF("Controller button: "
"%d, %s%s, %s%s, button = %d, time = %.04f\n", "%d, %s%s, %s%s, button = %d, time = %.04f\n",
f->id, (f->down ? "down" : ""), (f->up ? "up" : ""), (f->pressed ? "pressed" : ""), f.id, (f.down ? "down" : ""), (f.up ? "up" : ""), (f.pressed ? "pressed" : ""),
(f->released ? "released" : ""), f->button, f->timestamp_seconds); (f.released ? "released" : ""), f.button, f.timestamp_seconds);
} }
#endif #endif
if (f->added) { if (f.added) {
auto* pad = SDL_GameControllerOpen(f->id); auto* pad = SDL_GameControllerOpen(f.id);
EXIT_NOT_IMPLEMENTED(pad == nullptr); EXIT_NOT_IMPLEMENTED(pad == nullptr);
int id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(pad)); int id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(pad));
Controller::ControllerConnect(id); Controller::ControllerConnect(id);
} }
if (f->removed) { if (f.removed) {
Controller::ControllerDisconnect(f->id); Controller::ControllerDisconnect(f.id);
SDL_GameControllerClose(SDL_GameControllerFromInstanceID(f->id)); SDL_GameControllerClose(SDL_GameControllerFromInstanceID(f.id));
} }
if (f->down || f->up) { if (f.down || f.up) {
const auto button = ControllerButtonToPadButton(f->button); const auto button = ControllerButtonToPadButton(f.button);
if (button != 0) { if (button != 0) {
Controller::ControllerButton(f->id, button, f->down); Controller::ControllerButton(f.id, button, f.down);
} }
} }
if (f->axis) { if (f.axis) {
const auto axis = ControllerAxisFromSdl(f->axis_id); const auto axis = ControllerAxisFromSdl(f.axis_id);
if (axis != Controller::Axis::AxisMax) { if (axis != Controller::Axis::AxisMax) {
Controller::ControllerAxis(f->id, axis, Controller::ControllerAxis(f.id, axis,
ControllerAxisValueFromSdl(f->axis_id, f->axis_value)); ControllerAxisValueFromSdl(f.axis_id, f.axis_value));
} }
} }
} }
void GameEventDisplay([[maybe_unused]] WindowGame* game, [[maybe_unused]] const EventDisplay* d) { void GameEventDisplay([[maybe_unused]] WindowGame& game) {
auto* p = static_cast<WindowGamePrivate*>(game->private_data); auto* p = static_cast<WindowGamePrivate*>(game.private_data);
auto* ctx = static_cast<GraphicContext*>(p->ctx);
p->mutex.Lock(); p->mutex.Lock();
game->m_screen_width = ctx->screen_width; game.m_screen_width = p->graphics.screen_width;
game->m_screen_height = ctx->screen_height; game.m_screen_height = p->graphics.screen_height;
p->mutex.Unlock(); p->mutex.Unlock();
} }
void GameEventLowMemory(WindowGame* /*game*/) { void GameEventLowMemory(WindowGame& /*game*/) {
LOGF("Event: low_memory\n"); LOGF("Event: low_memory\n");
} }
void GameEventWillEnterBackground(WindowGame* game) { void GameEventWillEnterBackground(WindowGame& game) {
LOGF("Event: will_enter_background\n"); LOGF("Event: will_enter_background\n");
SetPause(game, true); SetPause(game, true);
} }
void GameEventDidEnterBackground(WindowGame* /*game*/) { void GameEventDidEnterBackground(WindowGame& /*game*/) {
LOGF("Event: did_enter_background\n"); LOGF("Event: did_enter_background\n");
} }
void GameEventWillEnterForeground(WindowGame* /*game*/) { void GameEventWillEnterForeground(WindowGame& /*game*/) {
LOGF("Event: will_enter_foreground\n"); LOGF("Event: will_enter_foreground\n");
} }
void GameEventDidEnterForeground(WindowGame* game) { void GameEventDidEnterForeground(WindowGame& game) {
LOGF("Event: did_enter_foreground\n"); LOGF("Event: did_enter_foreground\n");
SetPause(game, false); 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(new_width == 0 || new_height == 0);
EXIT_IF(!game);
auto* p = static_cast<WindowGamePrivate*>(game->private_data); auto* p = static_cast<WindowGamePrivate*>(game.private_data);
EXIT_IF(p == nullptr); EXIT_IF(p == nullptr);
auto* ctx = static_cast<GraphicContext*>(p->ctx);
EXIT_IF(ctx == nullptr);
p->mutex.Lock(); p->mutex.Lock();
{ {
p->skip_frames++; p->skip_frames++;
ctx->screen_width = new_width; p->graphics.screen_width = new_width;
ctx->screen_height = new_height; p->graphics.screen_height = new_height;
game->m_screen_width = ctx->screen_width; game.m_screen_width = p->graphics.screen_width;
game->m_screen_height = ctx->screen_height; game.m_screen_height = p->graphics.screen_height;
} }
p->mutex.Unlock(); p->mutex.Unlock();
} }
static void ProcessWindowEvent(WindowGame* game, SDL_WindowEvent window) { static void ProcessWindowEvent(WindowGame& game, SDL_WindowEvent window) {
switch (window.event) { switch (window.event) {
case SDL_WINDOWEVENT_SHOWN: LOGF("Window %" PRIu32 " shown\n", window.windowID); break; 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; bool sdl = false;
switch (display.event) { 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, LOGF("Display %" PRIu32 "[%s] changed orientation to %d - ", display.display,
sdl ? "SDL" : "Kyty", static_cast<int>(display.data1)); sdl ? "SDL" : "Kyty", static_cast<int>(display.data1));
EventDisplay d {};
d.orientation = DisplayOrientation::Unknown;
switch (display.data1) { switch (display.data1) {
case SDL_ORIENTATION_UNKNOWN: LOGF("UNKNOWN\n"); break; case SDL_ORIENTATION_UNKNOWN: LOGF("UNKNOWN\n"); break;
case SDL_ORIENTATION_LANDSCAPE: case SDL_ORIENTATION_LANDSCAPE: LOGF("LANDSCAPE\n"); break;
LOGF("LANDSCAPE\n"); case SDL_ORIENTATION_LANDSCAPE_FLIPPED: LOGF("LANDSCAPE_FLIPPED\n"); break;
d.orientation = DisplayOrientation::Landscape; case SDL_ORIENTATION_PORTRAIT: LOGF("PORTRAIT\n"); break;
break; case SDL_ORIENTATION_PORTRAIT_FLIPPED: LOGF("PORTRAIT_FLIPPED\n"); 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;
default: LOGF("???\n"); default: LOGF("???\n");
} }
if (!sdl) { if (!sdl) {
GameEventDisplay(game, &d); GameEventDisplay(game);
} }
break; break;
@@ -654,30 +625,24 @@ static void ProcessDisplayEvent(WindowGame* game, SDL_DisplayEvent display) {
} }
} }
int GamePollEvent(WindowGame* game) { int GamePollEvent(WindowGame& game) {
EXIT_IF(!game); auto* event = static_cast<SDL_Event*>(game.event);
auto* event = static_cast<SDL_Event*>(game->event);
EXIT_IF(!event); EXIT_IF(!event);
return SDL_PollEvent(event); return SDL_PollEvent(event);
} }
int GameWaitEvent(WindowGame* game) { int GameWaitEvent(WindowGame& game) {
EXIT_IF(!game); auto* event = static_cast<SDL_Event*>(game.event);
auto* event = static_cast<SDL_Event*>(game->event);
EXIT_IF(!event); EXIT_IF(!event);
return SDL_WaitEvent(event); return SDL_WaitEvent(event);
} }
void GameProcessEvent(WindowGame* game, double time_s) { void GameProcessEvent(WindowGame& game, double time_s) {
EXIT_IF(!game); auto* event = static_cast<SDL_Event*>(game.event);
auto* event = static_cast<SDL_Event*>(game->event);
EXIT_IF(!event); EXIT_IF(!event);
@@ -712,7 +677,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
key.mod = event->key.keysym.mod; key.mod = event->key.keysym.mod;
key.timestamp_seconds = time_s; key.timestamp_seconds = time_s;
GameEventKeyboard(game, &key); GameEventKeyboard(game, key);
break; break;
} }
@@ -744,7 +709,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
mb.motion_y = 0; mb.motion_y = 0;
mb.timestamp_seconds = time_s; mb.timestamp_seconds = time_s;
GameEventMouse(game, &mb); GameEventMouse(game, mb);
break; break;
} }
@@ -771,7 +736,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
mb.motion_y = 0; mb.motion_y = 0;
mb.timestamp_seconds = time_s; mb.timestamp_seconds = time_s;
GameEventMouse(game, &mb); GameEventMouse(game, mb);
break; break;
} }
@@ -798,7 +763,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
mb.motion_y = event->motion.yrel; mb.motion_y = event->motion.yrel;
mb.timestamp_seconds = time_s; mb.timestamp_seconds = time_s;
GameEventMouse(game, &mb); GameEventMouse(game, mb);
break; break;
} }
@@ -820,7 +785,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
f.pressure = event->tfinger.pressure; f.pressure = event->tfinger.pressure;
f.timestamp_seconds = time_s; f.timestamp_seconds = time_s;
GameEventFinger(game, &f); GameEventFinger(game, f);
break; break;
} }
@@ -842,7 +807,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
c.released = false; c.released = false;
c.timestamp_seconds = time_s; c.timestamp_seconds = time_s;
GameEventController(game, &c); GameEventController(game, c);
break; break;
} }
@@ -865,7 +830,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
c.released = (event->cbutton.state == SDL_RELEASED); c.released = (event->cbutton.state == SDL_RELEASED);
c.timestamp_seconds = time_s; c.timestamp_seconds = time_s;
GameEventController(game, &c); GameEventController(game, c);
break; break;
} }
@@ -889,20 +854,20 @@ void GameProcessEvent(WindowGame* game, double time_s) {
c.released = false; c.released = false;
c.timestamp_seconds = time_s; c.timestamp_seconds = time_s;
GameEventController(game, &c); GameEventController(game, c);
break; break;
} }
} }
} }
void GameMainLoop(WindowGame* game, void* data) { void GameMainLoop(WindowGame& game) {
bool need_exit = false; bool need_exit = false;
Common::Timer timer; Common::Timer timer;
timer.Start(); timer.Start();
if (!GameInit(game, timer, data)) { if (!GameInit(game, timer)) {
need_exit = true; need_exit = true;
} }
@@ -916,7 +881,7 @@ void GameMainLoop(WindowGame* game, void* data) {
continue; continue;
} }
if (game->m_game_is_paused) { if (game.m_game_is_paused) {
if (!timer.IsPaused()) { if (!timer.IsPaused()) {
timer.Pause(); timer.Pause();
} }
@@ -924,13 +889,13 @@ void GameMainLoop(WindowGame* game, void* data) {
GameWaitEvent(game); GameWaitEvent(game);
GameProcessEvent(game, timer.GetTimeS()); GameProcessEvent(game, timer.GetTimeS());
need_exit = game->m_game_need_exit; need_exit = game.m_game_need_exit;
continue; 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()) { if (!timer.IsPaused()) {
timer.Pause(); timer.Pause();
} }
@@ -952,14 +917,13 @@ void GameMainLoop(WindowGame* game, void* data) {
GameClose(game); GameClose(game);
} }
static void WindowCreate(WindowContext* ctx) { static void WindowCreate(WindowContext& context) {
EXIT_IF(ctx == nullptr); EXIT_IF(context.window != nullptr);
EXIT_IF(ctx->window != nullptr); EXIT_IF(context.graphic_ctx.screen_width == 0);
EXIT_IF(ctx->graphic_ctx.screen_width == 0); EXIT_IF(context.graphic_ctx.screen_height == 0);
EXIT_IF(ctx->graphic_ctx.screen_height == 0);
int width = static_cast<int>(ctx->graphic_ctx.screen_width); int width = static_cast<int>(context.graphic_ctx.screen_width);
int height = static_cast<int>(ctx->graphic_ctx.screen_height); int height = static_cast<int>(context.graphic_ctx.screen_height);
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, "0"); 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); LOGF("WindowCreate(): width = %d, height = %d\n", width, height);
ctx->window = context.window =
SDL_CreateWindow(KYTY_SDL_WINDOW_CAPTION, KYTY_SDL_WINDOWPOS_CENTERED, SDL_CreateWindow(KYTY_SDL_WINDOW_CAPTION, KYTY_SDL_WINDOWPOS_CENTERED,
KYTY_SDL_WINDOWPOS_CENTERED, width, height, KYTY_SDL_WINDOW_FLAGS); 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()); 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) { void WindowInit(uint32_t width, uint32_t height) {
@@ -1015,19 +979,21 @@ void WindowRun() {
{ {
EXIT_IF(g_window_ctx->graphic_initialized); EXIT_IF(g_window_ctx->graphic_initialized);
WindowCreate(g_window_ctx); WindowCreate(*g_window_ctx);
VulkanCreate(g_window_ctx); VulkanCreate(*g_window_ctx);
g_window_ctx->game = &game; g_window_ctx->game = &game;
g_window_ctx->graphic_initialized = true;
g_window_ctx->graphic_initialized_condvar.Signal();
} }
g_window_ctx->mutex.Unlock(); g_window_ctx->mutex.Unlock();
GraphicsRenderCreateContext(); 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 // TODO: replace std::_Exit shutdown with full Vulkan teardown, then destroy
// the VMA allocator immediately before vkDestroyDevice. // the VMA allocator immediately before vkDestroyDevice.
@@ -1043,12 +1009,12 @@ vk::SurfaceCapabilitiesKHR* VulkanGetSurfaceCapabilities() {
return &g_window_ctx->surface_capabilities->capabilities; return &g_window_ctx->surface_capabilities->capabilities;
} }
GraphicContext* WindowGetGraphicContext() { GraphicContext& WindowGetGraphicContext() {
EXIT_IF(g_window_ctx == nullptr); EXIT_IF(g_window_ctx == nullptr);
Common::LockGuard lock(g_window_ctx->mutex); 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) { static int WindowIconRead(void* user, char* data, int size) {
@@ -41,9 +41,9 @@ struct WindowContext {
extern WindowContext* g_window_ctx; extern WindowContext* g_window_ctx;
void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface, void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface,
SurfaceCapabilities* capabilities); SurfaceCapabilities& capabilities);
VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count); VulkanSwapchain* VulkanCreateSwapchain(uint32_t image_count);
void VulkanCreate(WindowContext* ctx); void VulkanCreate(WindowContext& window);
void WindowUpdateIcon(); void WindowUpdateIcon();
void WindowUpdateTitle(); void WindowUpdateTitle();
+12 -13
View File
@@ -6,7 +6,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
namespace Libs::Graphics::Rt { namespace Libs::Graphics {
namespace { namespace {
bool ExtensionAvailable(const std::vector<vk::ExtensionProperties>& available, const char* name) { bool ExtensionAvailable(const std::vector<vk::ExtensionProperties>& available, const char* name) {
@@ -25,10 +25,9 @@ void AppendExtensionIfMissing(std::vector<const char*>& extensions, const char*
} // namespace } // namespace
void AppendHardwareRayTracingDeviceExtensions( void GraphicContext::AppendHardwareRayTracingDeviceExtensions(
const std::vector<vk::ExtensionProperties>& available_extensions, const std::vector<vk::ExtensionProperties>& available_extensions,
std::vector<const char*>* device_extensions, GraphicContext* ctx) { std::vector<const char*>& device_extensions) {
EXIT_IF(device_extensions == nullptr || ctx == nullptr);
const char* required[] = { const char* required[] = {
VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
@@ -40,27 +39,27 @@ void AppendHardwareRayTracingDeviceExtensions(
if (!ExtensionAvailable(available_extensions, extension)) { if (!ExtensionAvailable(available_extensions, extension)) {
LOGF("Vulkan RT: extension %s is unavailable; hardware ray tracing disabled\n", LOGF("Vulkan RT: extension %s is unavailable; hardware ray tracing disabled\n",
extension); extension);
ctx->rt_extensions_enabled = false; rt_extensions_enabled = false;
return; return;
} }
} }
for (const auto* extension: required) { for (const auto* extension: required) {
AppendExtensionIfMissing(*device_extensions, extension); AppendExtensionIfMissing(device_extensions, extension);
} }
if (ExtensionAvailable(available_extensions, VK_KHR_SPIRV_1_4_EXTENSION_NAME)) { 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)) { 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"); LOGF("Vulkan RT: enabling hardware ray query extensions\n");
} }
void LoadHardwareRayTracingFunctions(GraphicContext* ctx) { void GraphicContext::LoadHardwareRayTracingFunctions() const {
EXIT_IF(ctx == nullptr || ctx->device == nullptr); EXIT_IF(device == nullptr);
if (!ctx->rt_extensions_enabled) { if (!rt_extensions_enabled) {
return; return;
} }
@@ -75,4 +74,4 @@ void LoadHardwareRayTracingFunctions(GraphicContext* ctx) {
} }
} }
} // namespace Libs::Graphics::Rt } // namespace Libs::Graphics
+1 -13
View File
@@ -5,18 +5,6 @@
#include <vector> #include <vector>
namespace Libs::Graphics { namespace Libs::Graphics {} // namespace Libs::Graphics
namespace Rt {
void AppendHardwareRayTracingDeviceExtensions(
const std::vector<vk::ExtensionProperties>& available_extensions,
std::vector<const char*>* device_extensions, GraphicContext* ctx);
void LoadHardwareRayTracingFunctions(GraphicContext* ctx);
} // namespace Rt
} // namespace Libs::Graphics
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_RT_HARDWARE_H_ */ #endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_RT_HARDWARE_H_ */
@@ -58,21 +58,21 @@ bool ImageBinding(const ImageResource& image, DescriptorBindingKind& result) {
} }
} }
bool CollectValue(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>* visited, bool CollectValue(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>& visited,
std::set<uint32_t>* registers) { std::set<uint32_t>& registers) {
if (id <= ScalarProvenance::Unknown) { if (id <= ScalarProvenance::Unknown) {
return true; return true;
} }
if (id >= provenance.values.size()) { if (id >= provenance.values.size()) {
return false; return false;
} }
if ((*visited)[id] != 0) { if (visited[id] != 0) {
return true; return true;
} }
(*visited)[id] = 1; visited[id] = 1;
const auto& value = provenance.values[id]; const auto& value = provenance.values[id];
if (value.op == ScalarValueOp::UserData) { if (value.op == ScalarValueOp::UserData) {
registers->insert(value.imm); registers.insert(value.imm);
return true; return true;
} }
if (value.op == ScalarValueOp::Phi) { if (value.op == ScalarValueOp::Phi) {
@@ -92,7 +92,7 @@ bool CollectValue(const ScalarProvenance& provenance, uint32_t id, std::vector<u
} }
bool CollectSource(const Program& program, uint32_t source, bool allow_unknown, bool CollectSource(const Program& program, uint32_t source, bool allow_unknown,
std::vector<uint8_t>* visited, std::set<uint32_t>* registers) { std::vector<uint8_t>& visited, std::set<uint32_t>& registers) {
if (allow_unknown && source == ScalarProvenance::Unknown) { if (allow_unknown && source == ScalarProvenance::Unknown) {
return true; return true;
} }
@@ -112,49 +112,49 @@ bool CollectUserData(const Program& program, std::vector<uint32_t>& result) {
std::set<uint32_t> registers; std::set<uint32_t> registers;
std::vector<uint8_t> visited(program.provenance.values.size()); std::vector<uint8_t> visited(program.provenance.values.size());
for (const auto& buffer: program.info.buffers) { for (const auto& buffer: program.info.buffers) {
if (!CollectSource(program, buffer.source, false, &visited, &registers)) { if (!CollectSource(program, buffer.source, false, visited, registers)) {
return false; return false;
} }
} }
for (const auto& image: program.info.images) { for (const auto& image: program.info.images) {
if (!CollectSource(program, image.source, false, &visited, &registers)) { if (!CollectSource(program, image.source, false, visited, registers)) {
return false; return false;
} }
} }
for (const auto& sampler: program.info.samplers) { for (const auto& sampler: program.info.samplers) {
if (!CollectSource(program, sampler.source, false, &visited, &registers)) { if (!CollectSource(program, sampler.source, false, visited, registers)) {
return false; return false;
} }
} }
for (const auto& address: program.info.addresses) { for (const auto& address: program.info.addresses) {
if (!CollectSource(program, address.source, true, &visited, &registers)) { if (!CollectSource(program, address.source, true, visited, registers)) {
return false; return false;
} }
} }
for (const auto& read: program.srt.reads) { for (const auto& read: program.srt.reads) {
if (!CollectValue(program.provenance, read.value, &visited, &registers)) { if (!CollectValue(program.provenance, read.value, visited, registers)) {
return false; return false;
} }
} }
for (const auto read: program.srt.dynamic_reads) { for (const auto read: program.srt.dynamic_reads) {
if (!CollectValue(program.provenance, read, &visited, &registers)) { if (!CollectValue(program.provenance, read, visited, registers)) {
return false; return false;
} }
} }
for (const auto source: program.srt.dynamic_sources) { for (const auto source: program.srt.dynamic_sources) {
if (!CollectSource(program, source, true, &visited, &registers)) { if (!CollectSource(program, source, true, visited, registers)) {
return false; return false;
} }
} }
for (const auto& block: program.blocks) { for (const auto& block: program.blocks) {
for (const auto& inst: block.instructions) { for (const auto& inst: block.instructions) {
if (inst.op == Opcode::SLoadDword && inst.memory.kind == ResourceKind::ScalarBuffer && if (inst.op == Opcode::SLoadDword && inst.memory.kind == ResourceKind::ScalarBuffer &&
!CollectValue(program.provenance, inst.scalar_value, &visited, &registers)) { !CollectValue(program.provenance, inst.scalar_value, visited, registers)) {
return false; return false;
} }
for (uint32_t i = 0; i < inst.src_count; i++) { for (uint32_t i = 0; i < inst.src_count; i++) {
if (!CollectValue(program.provenance, inst.scalar_sources[i], &visited, if (!CollectValue(program.provenance, inst.scalar_sources[i], visited,
&registers)) { registers)) {
return false; return false;
} }
} }
@@ -164,10 +164,10 @@ bool CollectUserData(const Program& program, std::vector<uint32_t>& result) {
return true; return true;
} }
void AddBinding(BindingLayout* layout, DescriptorBindingKind kind, void AddBinding(BindingLayout& layout, DescriptorBindingKind kind,
std::vector<uint32_t> resources = {}) { std::vector<uint32_t> resources = {}) {
layout->descriptors.push_back( layout.descriptors.push_back(
{kind, static_cast<uint32_t>(layout->descriptors.size()), std::move(resources)}); {kind, static_cast<uint32_t>(layout.descriptors.size()), std::move(resources)});
} }
bool UsesGds(const Program& program) { bool UsesGds(const Program& program) {
@@ -183,11 +183,10 @@ bool UsesGds(const Program& program) {
} // namespace } // namespace
bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std::string* error) { bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std::string* error) {
if (program == nullptr || !program->shader_info_complete || program->binding_layout_complete) { if (!program.shader_info_complete || program.binding_layout_complete) {
if (error != nullptr) { if (error != nullptr) {
*error = program == nullptr ? "invalid binding-layout program" *error = !program.shader_info_complete ? "shader info is not ready"
: !program->shader_info_complete ? "shader info is not ready"
: "binding layout already allocated"; : "binding layout already allocated";
} }
return false; return false;
@@ -208,25 +207,25 @@ bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std
BindingLayout next; BindingLayout next;
next.descriptor_set = options.descriptor_set; next.descriptor_set = options.descriptor_set;
next.push_constant_offset = options.push_constant_offset; 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) { if (error != nullptr) {
*error = "shader plan contains an invalid scalar provenance reference"; *error = "shader plan contains an invalid scalar provenance reference";
} }
return false; return false;
} }
if (!program->info.buffers.empty()) { if (!program.info.buffers.empty()) {
std::vector<uint32_t> resources(program->info.buffers.size()); std::vector<uint32_t> resources(program.info.buffers.size());
for (uint32_t i = 0; i < resources.size(); i++) { for (uint32_t i = 0; i < resources.size(); i++) {
resources[i] = i; resources[i] = i;
} }
AddBinding(&next, DescriptorBindingKind::Buffers, std::move(resources)); AddBinding(next, DescriptorBindingKind::Buffers, std::move(resources));
} }
std::array<std::vector<uint32_t>, ImageBindingKinds.size()> image_groups; std::array<std::vector<uint32_t>, 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; DescriptorBindingKind kind;
if (!ImageBinding(program->info.images[i], kind)) { if (!ImageBinding(program.info.images[i], kind)) {
if (error != nullptr) { if (error != nullptr) {
*error = "shader info contains an invalid image binding class"; *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++) { for (uint32_t i = 0; i < image_groups.size(); i++) {
if (!image_groups[i].empty()) { 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()) { if (!program.info.samplers.empty()) {
std::vector<uint32_t> resources(program->info.samplers.size()); std::vector<uint32_t> resources(program.info.samplers.size());
for (uint32_t i = 0; i < resources.size(); i++) { for (uint32_t i = 0; i < resources.size(); i++) {
resources[i] = i; resources[i] = i;
} }
AddBinding(&next, DescriptorBindingKind::Samplers, std::move(resources)); AddBinding(next, DescriptorBindingKind::Samplers, std::move(resources));
} }
if (UsesGds(*program)) { if (UsesGds(program)) {
AddBinding(&next, DescriptorBindingKind::Gds); AddBinding(next, DescriptorBindingKind::Gds);
} }
if (!program->info.addresses.empty()) { if (!program.info.addresses.empty()) {
std::vector<uint32_t> resources(program->info.addresses.size()); std::vector<uint32_t> resources(program.info.addresses.size());
for (uint32_t i = 0; i < resources.size(); i++) { for (uint32_t i = 0; i < resources.size(); i++) {
resources[i] = i; resources[i] = i;
} }
AddBinding(&next, DescriptorBindingKind::AddressMemory, std::move(resources)); AddBinding(next, DescriptorBindingKind::AddressMemory, std::move(resources));
} }
if (!program->srt.reads.empty()) { if (!program.srt.reads.empty()) {
AddBinding(&next, DescriptorBindingKind::FlattenedSrt); AddBinding(next, DescriptorBindingKind::FlattenedSrt);
} }
const auto available_push_dwords = (MaxPushConstantBytes - options.push_constant_offset) / 4u; 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) { if (next.user_data_registers.size() <= push_limit) {
next.push_constant_size = static_cast<uint32_t>(next.user_data_registers.size() * 4u); next.push_constant_size = static_cast<uint32_t>(next.user_data_registers.size() * 4u);
} else { } else {
AddBinding(&next, DescriptorBindingKind::UserData); AddBinding(next, DescriptorBindingKind::UserData);
} }
program->bindings = std::move(next); program.bindings = std::move(next);
program->binding_layout_complete = true; program.binding_layout_complete = true;
return true; return true;
} }
@@ -11,7 +11,7 @@ struct BindingLayoutOptions {
uint32_t max_push_dwords = 32; 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); const DescriptorBinding* FindBinding(const BindingLayout& layout, DescriptorBindingKind kind);
+20 -20
View File
@@ -4,7 +4,7 @@
namespace Libs::Graphics::ShaderRecompiler::Decoder { namespace Libs::Graphics::ShaderRecompiler::Decoder {
bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
if (word_index + 1u >= code.size()) { if (word_index + 1u >= code.size()) {
if (error != nullptr) { if (error != nullptr) {
@@ -18,33 +18,33 @@ bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
const uint32_t target = (word0 >> 4u) & 0x3fu; const uint32_t target = (word0 >> 4u) & 0x3fu;
const uint32_t en = word0 & 0xfu; const uint32_t en = word0 & 0xfu;
inst->pc = pc; inst.pc = pc;
inst->word = word0; inst.word = word0;
inst->word_count = 2; inst.word_count = 2;
inst->family = Family::EXP; inst.family = Family::EXP;
inst->opcode_id = target; inst.opcode_id = target;
inst->opcode = Opcode::Exp; inst.opcode = Opcode::Exp;
inst->exp.target = target; inst.exp.target = target;
inst->exp.en = en; inst.exp.en = en;
inst->exp.compr = ((word0 >> 10u) & 1u) != 0; inst.exp.compr = ((word0 >> 10u) & 1u) != 0;
inst->exp.done = ((word0 >> 11u) & 1u) != 0; inst.exp.done = ((word0 >> 11u) & 1u) != 0;
inst->exp.vm = ((word0 >> 12u) & 1u) != 0; inst.exp.vm = ((word0 >> 12u) & 1u) != 0;
SetRawWords(inst, code, word_index, 2); SetRawWords(inst, code, word_index, 2);
if (!DecodeVectorGpr(word1 & 0xffu, &inst->src0, error) || if (!DecodeVectorGpr(word1 & 0xffu, inst.src0, error) ||
!DecodeVectorGpr((word1 >> 8u) & 0xffu, &inst->src1, error) || !DecodeVectorGpr((word1 >> 8u) & 0xffu, inst.src1, error) ||
!DecodeVectorGpr((word1 >> 16u) & 0xffu, &inst->src2, error) || !DecodeVectorGpr((word1 >> 16u) & 0xffu, inst.src2, error) ||
!DecodeVectorGpr((word1 >> 24u) & 0xffu, &inst->src3, error)) { !DecodeVectorGpr((word1 >> 24u) & 0xffu, inst.src3, error)) {
return false; return false;
} }
if (target == 0x14u && inst->exp.done && en == 0x1u) { if (target == 0x14u && inst.exp.done && en == 0x1u) {
inst->src_count = 1u; inst.src_count = 1u;
} else { } else {
inst->src_count = inst->exp.compr ? 2u : 4u; inst.src_count = inst.exp.compr ? 2u : 4u;
} }
if (en == 0u) { if (en == 0u) {
inst->src_count = 0; inst.src_count = 0;
} }
return true; return true;
+1 -1
View File
@@ -5,7 +5,7 @@
namespace Libs::Graphics::ShaderRecompiler::Decoder { namespace Libs::Graphics::ShaderRecompiler::Decoder {
bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
} // namespace Libs::Graphics::ShaderRecompiler::Decoder } // namespace Libs::Graphics::ShaderRecompiler::Decoder
+23 -23
View File
@@ -226,7 +226,7 @@ bool IsSingleDmaskBit(uint32_t dmask) {
} // namespace } // namespace
bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
if (word_index + 1u >= code.size()) { if (word_index + 1u >= code.size()) {
if (error != nullptr) { if (error != nullptr) {
@@ -257,12 +257,12 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
const auto* gather = LookupGather(opcode); const auto* gather = LookupGather(opcode);
const auto* atomic = LookupAtomic(opcode); const auto* atomic = LookupAtomic(opcode);
inst->pc = pc; inst.pc = pc;
inst->word = word0; inst.word = word0;
inst->word_count = word_count; inst.word_count = word_count;
inst->family = Family::MIMG; inst.family = Family::MIMG;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->opcode = (sample != nullptr ? Opcode::ImageSample inst.opcode = (sample != nullptr ? Opcode::ImageSample
: gather != nullptr ? gather->decoded : gather != nullptr ? gather->decoded
: atomic != nullptr ? atomic->decoded : atomic != nullptr ? atomic->decoded
: opcode == 0x00u ? Opcode::ImageLoad : opcode == 0x00u ? Opcode::ImageLoad
@@ -272,20 +272,20 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
: opcode == 0x0eu ? Opcode::ImageGetResinfo : opcode == 0x0eu ? Opcode::ImageGetResinfo
: opcode == 0x60u ? Opcode::ImageGetLod : opcode == 0x60u ? Opcode::ImageGetLod
: Opcode::Unsupported); : Opcode::Unsupported);
inst->dmask = (word0 >> 8u) & 0xfu; inst.dmask = (word0 >> 8u) & 0xfu;
inst->data_dwords = gather != nullptr ? 4u : CountDmaskComponents(inst->dmask); inst.data_dwords = gather != nullptr ? 4u : CountDmaskComponents(inst.dmask);
inst->glc = ((word0 >> 13u) & 1u) != 0; inst.glc = ((word0 >> 13u) & 1u) != 0;
inst->slc = ((word0 >> 25u) & 1u) != 0; inst.slc = ((word0 >> 25u) & 1u) != 0;
inst->image_sample_flags = (sample != nullptr ? sample->flags inst.image_sample_flags = (sample != nullptr ? sample->flags
: gather != nullptr ? gather->flags : gather != nullptr ? gather->flags
: 0u) | : 0u) |
(a16 ? ImageSampleFlagA16 : 0u); (a16 ? ImageSampleFlagA16 : 0u);
inst->image_dimension = dimension; inst.image_dimension = dimension;
inst->image_nsa_dwords = nsa_dwords; inst.image_nsa_dwords = nsa_dwords;
for (uint32_t i = 0; i < nsa_dwords * 4u && i < MaxImageNsaAddressComponents; i++) { 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) sample != nullptr ? ImageSampleAddressComponents(sample->flags, dimension)
: gather != nullptr ? ImageSampleAddressComponents(gather->flags, dimension) : gather != nullptr ? ImageSampleAddressComponents(gather->flags, dimension)
: atomic != nullptr ? 3u : atomic != nullptr ? 3u
@@ -297,19 +297,19 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
: 0u); : 0u);
SetRawWords(inst, code, word_index, word_count); 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"); 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, SetUnsupported(inst, Family::MIMG, opcode,
"MIMG image gather requires exactly one dmask bit"); "MIMG image gather requires exactly one dmask bit");
} }
DecodeVectorGpr(vdata, &inst->dst, nullptr); DecodeVectorGpr(vdata, inst.dst, nullptr);
DecodeVectorGpr(vaddr, &inst->src0, nullptr); DecodeVectorGpr(vaddr, inst.src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr); DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
DecodeScalarSource(ssamp * 4u, pc, &inst->src2, nullptr); DecodeScalarSource(ssamp * 4u, pc, inst.src2, nullptr);
inst->src_count = 3; inst.src_count = 3;
return true; return true;
} }
+1 -1
View File
@@ -5,7 +5,7 @@
namespace Libs::Graphics::ShaderRecompiler::Decoder { namespace Libs::Graphics::ShaderRecompiler::Decoder {
bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
const char* MimgSampleOpcodeName(uint32_t opcode); const char* MimgSampleOpcodeName(uint32_t opcode);
+114 -114
View File
@@ -125,24 +125,24 @@ uint32_t SignExtendU32(uint32_t value, uint32_t bits) {
return (value ^ sign) - sign; return (value ^ sign) - sign;
} }
void MarkMemoryUnsupported(Instruction* inst, Family family, uint32_t opcode, const char* reason) { void MarkMemoryUnsupported(Instruction& inst, Family family, uint32_t opcode, const char* reason) {
inst->family = family; inst.family = family;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->opcode = Opcode::Unsupported; inst.opcode = Opcode::Unsupported;
SetUnsupported(inst, family, opcode, reason); SetUnsupported(inst, family, opcode, reason);
} }
void ApplyMemoryInfo(Instruction* inst, const MemoryOpcodeInfo* info) { void ApplyMemoryInfo(Instruction& inst, const MemoryOpcodeInfo* info) {
if (info == nullptr) { if (info == nullptr) {
inst->opcode = Opcode::Unsupported; inst.opcode = Opcode::Unsupported;
return; return;
} }
inst->opcode = info->decoded; inst.opcode = info->decoded;
inst->data_dwords = info->data_dwords; inst.data_dwords = info->data_dwords;
inst->data_bits = info->data_bits; inst.data_bits = info->data_bits;
inst->data_signed = info->data_signed; inst.data_signed = info->data_signed;
inst->typed = info->typed; inst.typed = info->typed;
inst->formatted = info->formatted; inst.formatted = info->formatted;
} }
bool IsDsWriteOpcode(Opcode opcode) { bool IsDsWriteOpcode(Opcode opcode) {
@@ -215,7 +215,7 @@ bool IsFlatStoreOpcode(Opcode opcode) {
} // namespace } // namespace
bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
if (word_index + 1u >= code.size()) { if (word_index + 1u >= code.size()) {
if (error != nullptr) { if (error != nullptr) {
@@ -231,32 +231,32 @@ bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
const uint32_t sbase = word0 & 0x3fu; const uint32_t sbase = word0 & 0x3fu;
const uint32_t soffset = (word1 >> 25u) & 0x7fu; const uint32_t soffset = (word1 >> 25u) & 0x7fu;
inst->pc = pc; inst.pc = pc;
inst->word = word0; inst.word = word0;
inst->word_count = 2; inst.word_count = 2;
inst->offset = SignExtendU32(word1 & 0x1fffffu, 21u); inst.offset = SignExtendU32(word1 & 0x1fffffu, 21u);
inst->glc = ((word0 >> 16u) & 1u) != 0; inst.glc = ((word0 >> 16u) & 1u) != 0;
inst->family = Family::SMEM; inst.family = Family::SMEM;
inst->opcode_id = opcode; inst.opcode_id = opcode;
const auto* info = const auto* info =
LookupMemoryOpcode(SMEM_OPS, static_cast<uint32_t>(std::size(SMEM_OPS)), opcode); LookupMemoryOpcode(SMEM_OPS, static_cast<uint32_t>(std::size(SMEM_OPS)), opcode);
ApplyMemoryInfo(inst, info); ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2); 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"); 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 // SMEM encodes SBASE in SGPR pairs. Scalar-buffer loads still use the same
// pair index; their descriptor operand consumes four SGPRs from that base. // pair index; their descriptor operand consumes four SGPRs from that base.
DecodeScalarSource(sbase * 2u, pc, &inst->src0, nullptr); DecodeScalarSource(sbase * 2u, pc, inst.src0, nullptr);
DecodeScalarSource(soffset, pc, &inst->src1, nullptr); DecodeScalarSource(soffset, pc, inst.src1, nullptr);
inst->src_count = 2; inst.src_count = 2;
return true; return true;
} }
bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
Instruction* inst, std::string* error) { Instruction& inst, std::string* error) {
if (word_index + 1u >= code.size()) { if (word_index + 1u >= code.size()) {
if (error != nullptr) { if (error != nullptr) {
*error = fmt::format("truncated MUBUF instruction at pc 0x{:08x}", pc); *error = fmt::format("truncated MUBUF instruction at pc 0x{:08x}", pc);
@@ -272,34 +272,34 @@ bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
const uint32_t srsrc = (word1 >> 16u) & 0x1fu; const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
const uint32_t soffset = (word1 >> 24u) & 0xffu; const uint32_t soffset = (word1 >> 24u) & 0xffu;
inst->pc = pc; inst.pc = pc;
inst->word = word0; inst.word = word0;
inst->word_count = 2; inst.word_count = 2;
inst->offset = word0 & 0xfffu; inst.offset = word0 & 0xfffu;
inst->idxen = ((word0 >> 13u) & 1u) != 0; inst.idxen = ((word0 >> 13u) & 1u) != 0;
inst->offen = ((word0 >> 12u) & 1u) != 0; inst.offen = ((word0 >> 12u) & 1u) != 0;
inst->glc = ((word0 >> 14u) & 1u) != 0; inst.glc = ((word0 >> 14u) & 1u) != 0;
inst->slc = ((word1 >> 22u) & 1u) != 0; inst.slc = ((word1 >> 22u) & 1u) != 0;
inst->family = Family::MUBUF; inst.family = Family::MUBUF;
inst->opcode_id = opcode; inst.opcode_id = opcode;
const auto* info = const auto* info =
LookupMemoryOpcode(MUBUF_OPS, static_cast<uint32_t>(std::size(MUBUF_OPS)), opcode); LookupMemoryOpcode(MUBUF_OPS, static_cast<uint32_t>(std::size(MUBUF_OPS)), opcode);
ApplyMemoryInfo(inst, info); ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2); 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"); MarkMemoryUnsupported(inst, Family::MUBUF, opcode, "MUBUF opcode is not implemented");
} }
DecodeVectorGpr(vdata, &inst->dst, nullptr); DecodeVectorGpr(vdata, inst.dst, nullptr);
DecodeVectorGpr(vaddr, &inst->src0, nullptr); DecodeVectorGpr(vaddr, inst.src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr); DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
DecodeScalarSource(soffset, pc, &inst->src2, nullptr); DecodeScalarSource(soffset, pc, inst.src2, nullptr);
inst->src_count = 3; inst.src_count = 3;
return true; return true;
} }
bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
Instruction* inst, std::string* error) { Instruction& inst, std::string* error) {
if (word_index + 1u >= code.size()) { if (word_index + 1u >= code.size()) {
if (error != nullptr) { if (error != nullptr) {
*error = fmt::format("truncated MTBUF instruction at pc 0x{:08x}", pc); *error = fmt::format("truncated MTBUF instruction at pc 0x{:08x}", pc);
@@ -317,35 +317,35 @@ bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
const uint32_t srsrc = (word1 >> 16u) & 0x1fu; const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
const uint32_t soffset = (word1 >> 24u) & 0xffu; const uint32_t soffset = (word1 >> 24u) & 0xffu;
inst->pc = pc; inst.pc = pc;
inst->word = word0; inst.word = word0;
inst->word_count = 2; inst.word_count = 2;
inst->offset = word0 & 0xfffu; inst.offset = word0 & 0xfffu;
inst->idxen = ((word0 >> 13u) & 1u) != 0; inst.idxen = ((word0 >> 13u) & 1u) != 0;
inst->offen = ((word0 >> 12u) & 1u) != 0; inst.offen = ((word0 >> 12u) & 1u) != 0;
inst->glc = ((word0 >> 14u) & 1u) != 0; inst.glc = ((word0 >> 14u) & 1u) != 0;
inst->slc = ((word1 >> 22u) & 1u) != 0; inst.slc = ((word1 >> 22u) & 1u) != 0;
inst->family = Family::MTBUF; inst.family = Family::MTBUF;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->data_format = dfmt; inst.data_format = dfmt;
inst->number_format = nfmt; inst.number_format = nfmt;
const auto* info = const auto* info =
LookupMemoryOpcode(MTBUF_OPS, static_cast<uint32_t>(std::size(MTBUF_OPS)), opcode); LookupMemoryOpcode(MTBUF_OPS, static_cast<uint32_t>(std::size(MTBUF_OPS)), opcode);
ApplyMemoryInfo(inst, info); ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2); 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"); MarkMemoryUnsupported(inst, Family::MTBUF, opcode, "MTBUF opcode is not implemented");
} }
DecodeVectorGpr(vdata, &inst->dst, nullptr); DecodeVectorGpr(vdata, inst.dst, nullptr);
DecodeVectorGpr(vaddr, &inst->src0, nullptr); DecodeVectorGpr(vaddr, inst.src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr); DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
DecodeScalarSource(soffset, pc, &inst->src2, nullptr); DecodeScalarSource(soffset, pc, inst.src2, nullptr);
inst->src_count = 3; inst.src_count = 3;
return true; return true;
} }
bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
if (word_index + 1u >= code.size()) { if (word_index + 1u >= code.size()) {
if (error != nullptr) { if (error != nullptr) {
@@ -366,43 +366,43 @@ bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
const uint32_t data = (word1 >> 8u) & 0xffu; const uint32_t data = (word1 >> 8u) & 0xffu;
const uint32_t addr = word1 & 0xffu; const uint32_t addr = word1 & 0xffu;
inst->pc = pc; inst.pc = pc;
inst->word = word0; inst.word = word0;
inst->word_count = 2; inst.word_count = 2;
inst->offset = seg == 0u ? (offset & 0x7ffu) : SignExtendU32(offset, 12u); inst.offset = seg == 0u ? (offset & 0x7ffu) : SignExtendU32(offset, 12u);
inst->glc = ((word0 >> 16u) & 1u) != 0; inst.glc = ((word0 >> 16u) & 1u) != 0;
inst->slc = ((word0 >> 17u) & 1u) != 0; inst.slc = ((word0 >> 17u) & 1u) != 0;
inst->family = Family::FLAT; inst.family = Family::FLAT;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->memory_segment = seg; inst.memory_segment = seg;
const auto* info = const auto* info =
LookupMemoryOpcode(FLAT_OPS, static_cast<uint32_t>(std::size(FLAT_OPS)), opcode); LookupMemoryOpcode(FLAT_OPS, static_cast<uint32_t>(std::size(FLAT_OPS)), opcode);
ApplyMemoryInfo(inst, info); ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2); 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"); SetUnsupported(inst, Family::FLAT, opcode, "FLAT modifiers or segment are not implemented");
return true; return true;
} }
if (inst->opcode == Opcode::Unsupported) { if (inst.opcode == Opcode::Unsupported) {
MarkMemoryUnsupported(inst, Family::FLAT, opcode, "FLAT opcode is not implemented"); MarkMemoryUnsupported(inst, Family::FLAT, opcode, "FLAT opcode is not implemented");
return true; return true;
} }
DecodeVectorGpr(IsFlatStoreOpcode(inst->opcode) ? data : vdst, &inst->dst, nullptr); DecodeVectorGpr(IsFlatStoreOpcode(inst.opcode) ? data : vdst, inst.dst, nullptr);
DecodeVectorGpr(addr, &inst->src0, nullptr); DecodeVectorGpr(addr, inst.src0, nullptr);
inst->src_count = 1; inst.src_count = 1;
if (seg == 0u || saddr == 0x7du || saddr == 0x7fu) { if (seg == 0u || saddr == 0x7du || saddr == 0x7fu) {
DecodeVectorGpr(addr + 1u, &inst->src1, nullptr); DecodeVectorGpr(addr + 1u, inst.src1, nullptr);
inst->src_count = 2; inst.src_count = 2;
} else { } else {
DecodeScalarSource(saddr, pc, &inst->src1, nullptr); DecodeScalarSource(saddr, pc, inst.src1, nullptr);
inst->src_count = 2; inst.src_count = 2;
} }
return true; return true;
} }
bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
if (word_index + 1u >= code.size()) { if (word_index + 1u >= code.size()) {
if (error != nullptr) { if (error != nullptr) {
@@ -421,59 +421,59 @@ bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
const uint32_t data0 = (word1 >> 8u) & 0xffu; const uint32_t data0 = (word1 >> 8u) & 0xffu;
const uint32_t addr = word1 & 0xffu; const uint32_t addr = word1 & 0xffu;
inst->pc = pc; inst.pc = pc;
inst->word = word0; inst.word = word0;
inst->word_count = 2; inst.word_count = 2;
inst->offset = offset0 | (offset1 << 8u); inst.offset = offset0 | (offset1 << 8u);
inst->gds = ((word0 >> 17u) & 1u) != 0u; inst.gds = ((word0 >> 17u) & 1u) != 0u;
inst->family = Family::DS; inst.family = Family::DS;
inst->opcode_id = opcode; inst.opcode_id = opcode;
const auto* info = LookupMemoryOpcode(DS_OPS, static_cast<uint32_t>(std::size(DS_OPS)), opcode); const auto* info = LookupMemoryOpcode(DS_OPS, static_cast<uint32_t>(std::size(DS_OPS)), opcode);
ApplyMemoryInfo(inst, info); ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2); 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"); 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"); SetUnsupported(inst, Family::DS, opcode, "DS swizzle FFT mode is not implemented");
} }
if (inst->gds && if (inst.gds &&
(inst->opcode == Opcode::DsSwizzleB32 || inst->opcode == Opcode::DsWriteAddtidB32 || (inst.opcode == Opcode::DsSwizzleB32 || inst.opcode == Opcode::DsWriteAddtidB32 ||
inst->opcode == Opcode::DsReadAddtidB32)) { inst.opcode == Opcode::DsReadAddtidB32)) {
SetUnsupported(inst, Family::DS, opcode, "DS swizzle/addtid is available only for LDS"); SetUnsupported(inst, Family::DS, opcode, "DS swizzle/addtid is available only for LDS");
} }
if (inst->gds && (inst->opcode == Opcode::DsAppend || inst->opcode == Opcode::DsConsume) && if (inst.gds && (inst.opcode == Opcode::DsAppend || inst.opcode == Opcode::DsConsume) &&
inst->offset != 0u) { inst.offset != 0u) {
SetUnsupported(inst, Family::DS, opcode, SetUnsupported(inst, Family::DS, opcode,
"GDS append/consume requires a zero instruction offset"); "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, SetUnsupported(inst, Family::DS, opcode,
"DS write addtid data1 operand is not implemented"); "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, SetUnsupported(inst, Family::DS, opcode,
"DS read addtid data operands are not implemented"); "DS read addtid data operands are not implemented");
} }
if (inst->opcode == Opcode::DsWrite2B32 || opcode == 0x37u) { if (inst.opcode == Opcode::DsWrite2B32 || opcode == 0x37u) {
inst->offset = offset0 * 4u; inst.offset = offset0 * 4u;
inst->secondary_offset = offset1 * 4u; inst.secondary_offset = offset1 * 4u;
} else if (inst->opcode == Opcode::DsWrite2St64B32 || opcode == 0x38u) { } else if (inst.opcode == Opcode::DsWrite2St64B32 || opcode == 0x38u) {
inst->offset = offset0 * 256u; inst.offset = offset0 * 256u;
inst->secondary_offset = offset1 * 256u; inst.secondary_offset = offset1 * 256u;
} else if (inst->opcode == Opcode::DsWrite2B64 || inst->opcode == Opcode::DsRead2B64) { } else if (inst.opcode == Opcode::DsWrite2B64 || inst.opcode == Opcode::DsRead2B64) {
inst->offset = offset0 * 8u; inst.offset = offset0 * 8u;
inst->secondary_offset = offset1 * 8u; inst.secondary_offset = offset1 * 8u;
} else if (inst->opcode == Opcode::DsWrite2St64B64 || inst->opcode == Opcode::DsRead2St64B64) { } else if (inst.opcode == Opcode::DsWrite2St64B64 || inst.opcode == Opcode::DsRead2St64B64) {
inst->offset = offset0 * 512u; inst.offset = offset0 * 512u;
inst->secondary_offset = offset1 * 512u; inst.secondary_offset = offset1 * 512u;
} }
DecodeVectorGpr(vdst, &inst->dst, nullptr); DecodeVectorGpr(vdst, inst.dst, nullptr);
DecodeVectorGpr(addr, &inst->src0, nullptr); DecodeVectorGpr(addr, inst.src0, nullptr);
DecodeVectorGpr(data0, &inst->src1, nullptr); DecodeVectorGpr(data0, inst.src1, nullptr);
DecodeVectorGpr(data1, &inst->src2, nullptr); DecodeVectorGpr(data1, inst.src2, nullptr);
inst->src_count = DsSourceCount(inst->opcode); inst.src_count = DsSourceCount(inst.opcode);
return true; return true;
} }
+5 -5
View File
@@ -5,15 +5,15 @@
namespace Libs::Graphics::ShaderRecompiler::Decoder { namespace Libs::Graphics::ShaderRecompiler::Decoder {
bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
Instruction* inst, std::string* error); Instruction& inst, std::string* error);
bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
Instruction* inst, std::string* error); Instruction& inst, std::string* error);
bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
} // namespace Libs::Graphics::ShaderRecompiler::Decoder } // namespace Libs::Graphics::ShaderRecompiler::Decoder
@@ -5,6 +5,7 @@
#include <algorithm> #include <algorithm>
#include <fmt/format.h> #include <fmt/format.h>
#include <functional>
namespace Libs::Graphics::ShaderRecompiler::IR { namespace Libs::Graphics::ShaderRecompiler::IR {
namespace { namespace {
@@ -200,11 +201,10 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
} }
bool MaterializeResources(const Program& program, const SrtRuntime& runtime, bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
ResourceSnapshot* snapshot, std::string* error) { ResourceSnapshot& snapshot, std::string* error) {
if (snapshot == nullptr || !program.resource_tracking_complete) { if (!program.resource_tracking_complete) {
if (error != nullptr) { if (error != nullptr) {
*error = snapshot == nullptr ? "invalid resource snapshot" *error = "shader resources were not tracked";
: "shader resources were not tracked";
} }
return false; return false;
} }
@@ -229,7 +229,7 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
std::vector<DescriptorValue> values; std::vector<DescriptorValue> values;
std::vector<uint32_t> flattened_srt; std::vector<uint32_t> flattened_srt;
if (!EvaluateRuntimeSources(program, requests, runtime, &values, &flattened_srt, error)) { if (!EvaluateRuntimeSources(program, requests, runtime, values, flattened_srt, error)) {
return false; return false;
} }
@@ -280,25 +280,24 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
if (!ValidateResourceSnapshot(program, next, error)) { if (!ValidateResourceSnapshot(program, next, error)) {
return false; return false;
} }
*snapshot = std::move(next); snapshot = std::move(next);
return true; return true;
} }
bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std::string* error) { bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std::string* error) {
if (program == nullptr || !program->resource_tracking_complete || if (!program.resource_tracking_complete || program.shader_info_complete ||
program->shader_info_complete || program->binding_layout_complete) { program.binding_layout_complete) {
if (error != nullptr) { if (error != nullptr) {
*error = program == nullptr ? "invalid resource specialization program" *error = !program.resource_tracking_complete ? "shader resources were not tracked"
: !program->resource_tracking_complete ? "shader resources were not tracked"
: "resource specialization is too late"; : "resource specialization is too late";
} }
return false; return false;
} }
if (!ValidateResourceSnapshot(*program, snapshot, error)) { if (!ValidateResourceSnapshot(program, snapshot, error)) {
return false; return false;
} }
auto next = program->info; auto next = program.info;
for (uint32_t i = 0; i < next.buffers.size(); i++) { for (uint32_t i = 0; i < next.buffers.size(); i++) {
ShaderBufferResource descriptor; ShaderBufferResource descriptor;
if (!DecodeBufferDescriptor(snapshot.buffers[i], descriptor)) { if (!DecodeBufferDescriptor(snapshot.buffers[i], descriptor)) {
@@ -347,12 +346,12 @@ bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std
} }
} }
struct ImagePatch { struct ImagePatch {
Instruction* inst; std::reference_wrapper<Instruction> inst;
ResourceKind kind; ResourceKind kind;
Decoder::ImageDimension dimension; Decoder::ImageDimension dimension;
}; };
std::vector<ImagePatch> patches; std::vector<ImagePatch> patches;
for (auto& block: program->blocks) { for (auto& block: program.blocks) {
for (auto& inst: block.instructions) { for (auto& inst: block.instructions) {
if (inst.memory.kind != ResourceKind::Image && if (inst.memory.kind != ResourceKind::Image &&
inst.memory.kind != ResourceKind::ImageUint && inst.memory.kind != ResourceKind::ImageUint &&
@@ -368,13 +367,13 @@ bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std
return false; return false;
} }
const auto& image = next.images[inst.memory.resource]; 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) { for (const auto& patch: patches) {
patch.inst->memory.kind = patch.kind; patch.inst.get().memory.kind = patch.kind;
patch.inst->memory.image_dimension = patch.dimension; patch.inst.get().memory.image_dimension = patch.dimension;
} }
return true; return true;
} }
@@ -31,11 +31,11 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
// Resolves the immutable dense resource topology against one runtime user-data/SRT snapshot. // Resolves the immutable dense resource topology against one runtime user-data/SRT snapshot.
// On failure the destination is unchanged. // On failure the destination is unchanged.
bool MaterializeResources(const Program& program, const SrtRuntime& runtime, 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 // Applies runtime descriptor shape/format facts to a copied dense topology before layout and
// emission. On failure the program is unchanged. // 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 } // namespace Libs::Graphics::ShaderRecompiler::IR
@@ -4,6 +4,7 @@
#include <algorithm> #include <algorithm>
#include <fmt/format.h> #include <fmt/format.h>
#include <functional>
namespace Libs::Graphics::ShaderRecompiler::IR { namespace Libs::Graphics::ShaderRecompiler::IR {
namespace { namespace {
@@ -82,17 +83,17 @@ uint32_t ByteExtent(const Instruction& inst) {
return end > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(end); return end > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(end);
} }
bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>* visited, bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>& visited,
std::vector<uint32_t>* path) { std::vector<uint32_t>& path) {
path->push_back(id); path.push_back(id);
if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) { if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) {
return true; return true;
} }
if ((*visited)[id] != 0) { if (visited[id] != 0) {
path->pop_back(); path.pop_back();
return false; return false;
} }
(*visited)[id] = 1; visited[id] = 1;
const auto& value = provenance.values[id]; const auto& value = provenance.values[id];
if (value.op == ScalarValueOp::Phi) { if (value.op == ScalarValueOp::Phi) {
for (const auto arg: value.phi_args) { for (const auto arg: value.phi_args) {
@@ -100,7 +101,7 @@ bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vecto
return true; return true;
} }
} }
path->pop_back(); path.pop_back();
return false; return false;
} }
const auto args = ScalarValueArgCount(value.op); const auto args = ScalarValueArgCount(value.op);
@@ -109,19 +110,19 @@ bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vecto
return true; return true;
} }
} }
path->pop_back(); path.pop_back();
return false; return false;
} }
bool IsLoopInvariantValue(const ScalarProvenance& provenance, uint32_t id, bool IsLoopInvariantValue(const ScalarProvenance& provenance, uint32_t id,
std::vector<uint8_t>* visiting) { std::vector<uint8_t>& visiting) {
if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) { if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) {
return false; return false;
} }
if ((*visiting)[id] != 0) { if (visiting[id] != 0) {
return true; return true;
} }
(*visiting)[id] = 1; visiting[id] = 1;
const auto& value = provenance.values[id]; const auto& value = provenance.values[id];
if (value.op == ScalarValueOp::Phi) { if (value.op == ScalarValueOp::Phi) {
uint32_t invariant = ScalarProvenance::Undefined; uint32_t invariant = ScalarProvenance::Undefined;
@@ -150,7 +151,7 @@ bool IsLoopInvariantDescriptor(const ScalarProvenance& provenance,
const DescriptorValue& descriptor) { const DescriptorValue& descriptor) {
std::vector<uint8_t> visiting(provenance.values.size()); std::vector<uint8_t> visiting(provenance.values.size());
for (uint32_t i = 0; i < descriptor.dword_count; i++) { 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; return false;
} }
} }
@@ -173,7 +174,7 @@ public:
} }
for (auto& block: m_program.blocks) { for (auto& block: m_program.blocks) {
for (auto& inst: block.instructions) { for (auto& inst: block.instructions) {
if (!Collect(&inst, error)) { if (!Collect(inst, error)) {
return false; return false;
} }
} }
@@ -181,10 +182,11 @@ public:
LinkImageAliases(); LinkImageAliases();
m_program.info = std::move(m_info); m_program.info = std::move(m_info);
for (const auto& patch: m_patches) { for (const auto& patch: m_patches) {
patch.inst->memory.resource = patch.resource; auto& inst = patch.inst.get();
patch.inst->memory.sampler = patch.sampler; inst.memory.resource = patch.resource;
patch.inst->memory.resource_source = ScalarProvenance::Undefined; inst.memory.sampler = patch.sampler;
patch.inst->memory.sampler_source = ScalarProvenance::Undefined; inst.memory.resource_source = ScalarProvenance::Undefined;
inst.memory.sampler_source = ScalarProvenance::Undefined;
} }
m_program.resource_tracking_complete = true; m_program.resource_tracking_complete = true;
return true; return true;
@@ -192,7 +194,7 @@ public:
private: private:
struct Patch { struct Patch {
Instruction* inst = nullptr; std::reference_wrapper<Instruction> inst;
uint32_t resource = 0; uint32_t resource = 0;
uint32_t sampler = 0; uint32_t sampler = 0;
}; };
@@ -214,7 +216,7 @@ private:
std::vector<uint8_t> visited(m_program.provenance.values.size()); std::vector<uint8_t> visited(m_program.provenance.values.size());
for (uint32_t i = 0; i < descriptor->dword_count; i++) { for (uint32_t i = 0; i < descriptor->dword_count; i++) {
std::vector<uint32_t> path; std::vector<uint32_t> 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]; const auto value = descriptor->dwords[i];
std::string chain; std::string chain;
for (const auto id: path) { for (const auto id: path) {
@@ -400,50 +402,49 @@ private:
return true; return true;
} }
bool Collect(Instruction* inst, std::string* error) { bool Collect(Instruction& inst, std::string* error) {
if (IsAddress(*inst)) { if (IsAddress(inst)) {
const bool unbased = inst->memory.resource_source == ScalarProvenance::Unknown; const bool unbased = inst.memory.resource_source == ScalarProvenance::Unknown;
if ((!unbased && !ValidateSource(inst->memory.resource_source, 2, inst->pc, error)) || if ((!unbased && !ValidateSource(inst.memory.resource_source, 2, inst.pc, error)) ||
(unbased && inst->memory.kind != ResourceKind::Flat && (unbased && inst.memory.kind != ResourceKind::Flat &&
inst->memory.kind != ResourceKind::Global && inst.memory.kind != ResourceKind::Global &&
inst->memory.kind != ResourceKind::Scratch)) { inst.memory.kind != ResourceKind::Scratch)) {
return unbased ? Fail(inst->pc, error, "scalar memory base is unresolved") : false; 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) { 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; return true;
} }
if (!IsBuffer(*inst) && !IsImage(*inst)) { if (!IsBuffer(inst) && !IsImage(inst)) {
return true; 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)) { error)) {
return false; return false;
} }
Patch patch; const auto resource = IsBuffer(inst) ? AddBuffer(inst) : AddImage(inst);
patch.inst = inst; if (resource == UINT32_MAX) {
patch.resource = IsBuffer(*inst) ? AddBuffer(*inst) : AddImage(*inst); return Fail(inst.pc, error,
if (patch.resource == UINT32_MAX) { IsBuffer(inst) ? "buffer resource limit exceeded"
return Fail(inst->pc, error,
IsBuffer(*inst) ? "buffer resource limit exceeded"
: "image resource limit exceeded"); : "image resource limit exceeded");
} }
if (NeedsSampler(inst->op)) { uint32_t sampler = 0;
if (!ValidateSource(inst->memory.sampler_source, 4, inst->pc, error)) { if (NeedsSampler(inst.op)) {
if (!ValidateSource(inst.memory.sampler_source, 4, inst.pc, error)) {
return false; return false;
} }
patch.sampler = AddSampler(*inst); sampler = AddSampler(inst);
if (patch.sampler == UINT32_MAX) { if (sampler == UINT32_MAX) {
return Fail(inst->pc, error, "sampler resource limit exceeded"); 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; return false;
} }
} }
m_patches.push_back(patch); m_patches.push_back({std::ref(inst), resource, sampler});
return true; return true;
} }
@@ -454,15 +455,8 @@ private:
} // namespace } // namespace
bool TrackResources(Program* program, std::string* error) { bool TrackResources(Program& program, std::string* error) {
if (program == nullptr) { return Tracker(program).Run(error);
if (error != nullptr) {
*error = "shader resource tracking: hash=0x0000000000000000 stage=unknown "
"pc=0x00000000 invalid program";
}
return false;
}
return Tracker(*program).Run(error);
} }
} // namespace Libs::Graphics::ShaderRecompiler::IR } // namespace Libs::Graphics::ShaderRecompiler::IR
@@ -7,7 +7,7 @@ namespace Libs::Graphics::ShaderRecompiler::IR {
// Collects immutable resource topology, then replaces descriptor operands with dense indices. // Collects immutable resource topology, then replaces descriptor operands with dense indices.
// On failure the program is left unpatched. // 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 } // namespace Libs::Graphics::ShaderRecompiler::IR
+81 -81
View File
@@ -89,59 +89,59 @@ Opcode Lookup(const OpcodeMap* ops, uint32_t count, uint32_t opcode) {
} }
bool DecodeBinarySources(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, bool DecodeBinarySources(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
Instruction* inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) { Instruction& inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) {
if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error) || if (!DecodeScalarSource(ssrc0, pc, inst.src0, error) ||
!DecodeScalarSource(ssrc1, pc, &inst->src1, error)) { !DecodeScalarSource(ssrc1, pc, inst.src1, error)) {
return false; return false;
} }
inst->src_count = 2; inst.src_count = 2;
return ReadLiteralOperands(code, word_index, inst, error); return ReadLiteralOperands(code, word_index, inst, error);
} }
} // namespace } // namespace
bool DecodeSop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
const uint32_t word = code[word_index]; const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 8u) & 0xffu; const uint32_t opcode = (word >> 8u) & 0xffu;
const uint32_t ssrc0 = word & 0xffu; const uint32_t ssrc0 = word & 0xffu;
const uint32_t sdst = (word >> 16u) & 0x7fu; const uint32_t sdst = (word >> 16u) & 0x7fu;
inst->pc = pc; inst.pc = pc;
inst->word = word; inst.word = word;
inst->family = Family::SOP1; inst.family = Family::SOP1;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->opcode = Lookup(SOP1_OPS, static_cast<uint32_t>(std::size(SOP1_OPS)), opcode); inst.opcode = Lookup(SOP1_OPS, static_cast<uint32_t>(std::size(SOP1_OPS)), opcode);
SetRawWords(inst, code, word_index, 1); 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"); SetUnsupported(inst, Family::SOP1, opcode, "SOP1 opcode is not implemented");
return true; return true;
} }
switch (inst->opcode) { switch (inst.opcode) {
case Opcode::SGetpcB64: case Opcode::SGetpcB64:
inst->src_count = 0; inst.src_count = 0;
return DecodeScalarDestination(sdst, pc, &inst->dst, error); return DecodeScalarDestination(sdst, pc, inst.dst, error);
case Opcode::SSetpcB64: case Opcode::SSetpcB64:
inst->src_count = 1; inst.src_count = 1;
inst->dst.kind = OperandKind::Null; inst.dst.kind = OperandKind::Null;
if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error)) { if (!DecodeScalarSource(ssrc0, pc, inst.src0, error)) {
return false; return false;
} }
return ReadLiteralOperands(code, word_index, inst, error); return ReadLiteralOperands(code, word_index, inst, error);
default: break; default: break;
} }
if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error) || if (!DecodeScalarSource(ssrc0, pc, inst.src0, error) ||
!DecodeScalarDestination(sdst, pc, &inst->dst, error)) { !DecodeScalarDestination(sdst, pc, inst.dst, error)) {
return false; return false;
} }
inst->src_count = 1; inst.src_count = 1;
return ReadLiteralOperands(code, word_index, inst, error); return ReadLiteralOperands(code, word_index, inst, error);
} }
bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
const uint32_t word = code[word_index]; const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 23u) & 0x7fu; const uint32_t opcode = (word >> 23u) & 0x7fu;
@@ -149,25 +149,25 @@ bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
const uint32_t ssrc0 = word & 0xffu; const uint32_t ssrc0 = word & 0xffu;
const uint32_t sdst = (word >> 16u) & 0x7fu; const uint32_t sdst = (word >> 16u) & 0x7fu;
inst->pc = pc; inst.pc = pc;
inst->word = word; inst.word = word;
inst->family = Family::SOP2; inst.family = Family::SOP2;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->opcode = Lookup(SOP2_OPS, static_cast<uint32_t>(std::size(SOP2_OPS)), opcode); inst.opcode = Lookup(SOP2_OPS, static_cast<uint32_t>(std::size(SOP2_OPS)), opcode);
SetRawWords(inst, code, word_index, 1); 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"); SetUnsupported(inst, Family::SOP2, opcode, "SOP2 opcode is not implemented");
return true; return true;
} }
if (!DecodeScalarDestination(sdst, pc, &inst->dst, error)) { if (!DecodeScalarDestination(sdst, pc, inst.dst, error)) {
return false; return false;
} }
return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error); return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error);
} }
bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
const uint32_t word = code[word_index]; const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 23u) & 0x1fu; const uint32_t opcode = (word >> 23u) & 0x1fu;
@@ -176,72 +176,72 @@ bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
(void)error; (void)error;
inst->pc = pc; inst.pc = pc;
inst->word = word; inst.word = word;
inst->family = Family::SOPK; inst.family = Family::SOPK;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->opcode = Lookup(SOPK_OPS, static_cast<uint32_t>(std::size(SOPK_OPS)), opcode); inst.opcode = Lookup(SOPK_OPS, static_cast<uint32_t>(std::size(SOPK_OPS)), opcode);
inst->src0.kind = OperandKind::IntegerInlineConstant; inst.src0.kind = OperandKind::IntegerInlineConstant;
inst->src0.signed_val = imm; inst.src0.signed_val = imm;
inst->src0.value = static_cast<uint32_t>(imm); inst.src0.value = static_cast<uint32_t>(imm);
inst->src_count = 1; inst.src_count = 1;
SetRawWords(inst, code, word_index, 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"); SetUnsupported(inst, Family::SOPK, opcode, "SOPK opcode is not implemented");
return true; return true;
} }
switch (inst->opcode) { switch (inst.opcode) {
case Opcode::SMovkI32: return DecodeScalarDestination(sdst, pc, &inst->dst, error); case Opcode::SMovkI32: return DecodeScalarDestination(sdst, pc, inst.dst, error);
case Opcode::SWaitcnt: { case Opcode::SWaitcnt: {
const uint32_t waitcnt = word & 0xffffu; const uint32_t waitcnt = word & 0xffffu;
inst->dst.kind = OperandKind::Null; inst.dst.kind = OperandKind::Null;
inst->src0.signed_val = static_cast<int32_t>(waitcnt); inst.src0.signed_val = static_cast<int32_t>(waitcnt);
inst->src0.value = waitcnt; inst.src0.value = waitcnt;
inst->src_count = 1; inst.src_count = 1;
return true; return true;
} }
case Opcode::SSetregB32: case Opcode::SSetregB32:
inst->dst.kind = OperandKind::Null; inst.dst.kind = OperandKind::Null;
inst->src1.kind = OperandKind::LiteralConstant; inst.src1.kind = OperandKind::LiteralConstant;
inst->src1.value = word & 0xffffu; inst.src1.value = word & 0xffffu;
inst->src1.signed_val = static_cast<int32_t>(imm); inst.src1.signed_val = static_cast<int32_t>(imm);
inst->src_count = 2; inst.src_count = 2;
return DecodeScalarSource(sdst, pc, &inst->src0, error); return DecodeScalarSource(sdst, pc, inst.src0, error);
default: break; default: break;
} }
inst->src1 = inst->src0; inst.src1 = inst.src0;
if (!DecodeScalarSource(sdst, pc, &inst->src0, error)) { if (!DecodeScalarSource(sdst, pc, inst.src0, error)) {
return false; return false;
} }
if (inst->opcode == Opcode::SAddI32 || inst->opcode == Opcode::SMulkI32) { if (inst.opcode == Opcode::SAddI32 || inst.opcode == Opcode::SMulkI32) {
inst->src_count = 2; inst.src_count = 2;
return DecodeScalarDestination(sdst, pc, &inst->dst, error); return DecodeScalarDestination(sdst, pc, inst.dst, error);
} }
inst->dst.kind = OperandKind::Scc; inst.dst.kind = OperandKind::Scc;
inst->src_count = 2; inst.src_count = 2;
return true; return true;
} }
bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
const uint32_t word = code[word_index]; const uint32_t word = code[word_index];
const uint32_t ssrc1 = (word >> 8u) & 0xffu; const uint32_t ssrc1 = (word >> 8u) & 0xffu;
const uint32_t ssrc0 = word & 0xffu; const uint32_t ssrc0 = word & 0xffu;
const uint32_t opcode = (word >> 16u) & 0x7fu; const uint32_t opcode = (word >> 16u) & 0x7fu;
inst->pc = pc; inst.pc = pc;
inst->word = word; inst.word = word;
inst->family = Family::SOPC; inst.family = Family::SOPC;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->opcode = Lookup(SOPC_OPS, static_cast<uint32_t>(std::size(SOPC_OPS)), opcode); inst.opcode = Lookup(SOPC_OPS, static_cast<uint32_t>(std::size(SOPC_OPS)), opcode);
inst->dst.kind = OperandKind::Scc; inst.dst.kind = OperandKind::Scc;
SetRawWords(inst, code, word_index, 1); 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"); SetUnsupported(inst, Family::SOPC, opcode, "SOPC opcode is not implemented");
return true; return true;
} }
@@ -249,7 +249,7 @@ bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error); return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error);
} }
bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
const uint32_t word = code[word_index]; const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 16u) & 0x7fu; const uint32_t opcode = (word >> 16u) & 0x7fu;
@@ -257,24 +257,24 @@ bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
(void)error; (void)error;
inst->pc = pc; inst.pc = pc;
inst->word = word; inst.word = word;
inst->family = Family::SOPP; inst.family = Family::SOPP;
inst->opcode_id = opcode; inst.opcode_id = opcode;
inst->opcode = Lookup(SOPP_OPS, static_cast<uint32_t>(std::size(SOPP_OPS)), opcode); inst.opcode = Lookup(SOPP_OPS, static_cast<uint32_t>(std::size(SOPP_OPS)), opcode);
inst->src0.kind = OperandKind::LiteralConstant; inst.src0.kind = OperandKind::LiteralConstant;
inst->src0.value = simm; inst.src0.value = simm;
inst->src0.signed_val = static_cast<int16_t>(simm); inst.src0.signed_val = static_cast<int16_t>(simm);
inst->src_count = (inst->opcode == Opcode::SNop || inst->opcode == Opcode::SWaitcnt || inst.src_count = (inst.opcode == Opcode::SNop || inst.opcode == Opcode::SWaitcnt ||
inst->opcode == Opcode::SSleep || inst->opcode == Opcode::SSendmsg || inst.opcode == Opcode::SSleep || inst.opcode == Opcode::SSendmsg ||
inst->opcode == Opcode::STtraceData || inst->opcode == Opcode::SInstPrefetch) inst.opcode == Opcode::STtraceData || inst.opcode == Opcode::SInstPrefetch)
? 1 ? 1
: 0; : 0;
inst->branch_offset = static_cast<int32_t>(static_cast<int16_t>(simm)) * 4; inst.branch_offset = static_cast<int32_t>(static_cast<int16_t>(simm)) * 4;
inst->branch_target = pc + 4u + static_cast<uint32_t>(inst->branch_offset); inst.branch_target = pc + 4u + static_cast<uint32_t>(inst.branch_offset);
SetRawWords(inst, code, word_index, 1); 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"); SetUnsupported(inst, Family::SOPP, opcode, "SOPP control-flow opcode is not implemented");
} }
return true; return true;
@@ -5,15 +5,15 @@
namespace Libs::Graphics::ShaderRecompiler::Decoder { namespace Libs::Graphics::ShaderRecompiler::Decoder {
bool DecodeSop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
} // namespace Libs::Graphics::ShaderRecompiler::Decoder } // namespace Libs::Graphics::ShaderRecompiler::Decoder
@@ -140,20 +140,20 @@ bool ScalarMemoryLoad(Opcode op) {
return op == Opcode::SLoadDword || op == Opcode::SBufferLoadDword; return op == Opcode::SLoadDword || op == Opcode::SBufferLoadDword;
} }
bool ValueResolved(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>* visited) { bool ValueResolved(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>& visited) {
if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) { if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) {
return false; return false;
} }
if ((*visited)[id] == 1) { if (visited[id] == 1) {
return false; return false;
} }
if ((*visited)[id] == 2) { if (visited[id] == 2) {
return true; return true;
} }
if ((*visited)[id] == 3) { if (visited[id] == 3) {
return false; return false;
} }
(*visited)[id] = 1; visited[id] = 1;
const auto& value = provenance.values[id]; const auto& value = provenance.values[id];
bool resolved = true; bool resolved = true;
if (value.op == ScalarValueOp::Phi) { 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); resolved = ValueResolved(provenance, value.args[i], visited);
} }
} }
(*visited)[id] = resolved ? 2 : 3; visited[id] = resolved ? 2 : 3;
return resolved; return resolved;
} }
class Builder { class Builder {
public: 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) { bool Run(std::string* error) {
m_graph = {}; m_graph = {};
@@ -181,7 +181,7 @@ public:
m_graph.values[ScalarProvenance::Undefined].op = ScalarValueOp::Undefined; m_graph.values[ScalarProvenance::Undefined].op = ScalarValueOp::Undefined;
m_graph.values[ScalarProvenance::Unknown].op = ScalarValueOp::Unknown; 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_entry.resize(block_count);
m_exit.resize(block_count); m_exit.resize(block_count);
m_phi.resize(block_count); m_phi.resize(block_count);
@@ -200,8 +200,8 @@ public:
m_user_data.Fill(ScalarProvenance::Undefined); m_user_data.Fill(ScalarProvenance::Undefined);
for (uint32_t reg = 0; reg < ScalarRegisters; reg++) { for (uint32_t reg = 0; reg < ScalarRegisters; reg++) {
m_user_data.regs[reg] = m_user_data.regs[reg] =
reg >= m_program->user_data_base && reg >= m_program.user_data_base &&
reg - m_program->user_data_base < m_program->user_data_count reg - m_program.user_data_base < m_program.user_data_count
? InternValue({ScalarValueOp::UserData, 0, reg}) ? InternValue({ScalarValueOp::UserData, 0, reg})
: ScalarProvenance::Unknown; : ScalarProvenance::Unknown;
} }
@@ -211,7 +211,7 @@ public:
if (block_count == 0) { if (block_count == 0) {
return true; return true;
} }
for (const auto& block: m_program->blocks) { for (const auto& block: m_program.blocks) {
for (const auto predecessor: block.predecessors) { for (const auto predecessor: block.predecessors) {
if (predecessor >= block_count) { if (predecessor >= block_count) {
return Fail(error, fmt::format("scalar provenance has invalid predecessor {}", 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]; const bool entry_changed = next_entry != m_entry[block_index];
m_entry[block_index] = next_entry; 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]; const bool was_ready = m_exit_ready[block_index];
if (was_ready && !entry_changed && next_exit == m_exit[block_index]) { if (was_ready && !entry_changed && next_exit == m_exit[block_index]) {
continue; continue;
} }
m_exit[block_index] = next_exit; m_exit[block_index] = next_exit;
m_exit_ready[block_index] = true; 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); Queue(successor);
} }
} }
for (size_t block = 0; block < block_count; block++) { 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; return true;
} }
@@ -366,40 +366,37 @@ private:
return InternValue(std::move(node)); return InternValue(std::move(node));
} }
bool ConstantOperand(const Operand& operand, const ScalarState& state, uint32_t* value) { bool ConstantOperand(const Operand& operand, const ScalarState& state, uint32_t& value) {
if (value == nullptr) {
return false;
}
const auto id = OperandValue(operand, state); const auto id = OperandValue(operand, state);
if (id >= m_graph.values.size() || m_graph.values[id].op != ScalarValueOp::Constant) { if (id >= m_graph.values.size() || m_graph.values[id].op != ScalarValueOp::Constant) {
return false; return false;
} }
*value = m_graph.values[id].imm; value = m_graph.values[id].imm;
return true; return true;
} }
uint32_t ReadVectorLane(const Instruction& inst, const ScalarState& state) { uint32_t ReadVectorLane(const Instruction& inst, const ScalarState& state) {
if (inst.src_count < 2 || inst.src[0].kind != OperandKind::Register || if (inst.src_count < 2 || inst.src[0].kind != OperandKind::Register ||
inst.src[0].reg.file != RegisterFile::Vector || 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; return ScalarProvenance::Unknown;
} }
uint32_t lane = 0; uint32_t lane = 0;
if (!ConstantOperand(inst.src[1], state, &lane)) { if (!ConstantOperand(inst.src[1], state, lane)) {
return ScalarProvenance::Unknown; return ScalarProvenance::Unknown;
} }
const auto found = state.vector_lanes.find( 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; return found != state.vector_lanes.end() ? found->second : ScalarProvenance::Unknown;
} }
void ClearVectorLanes(uint32_t reg, ScalarState* state) { void ClearVectorLanes(uint32_t reg, ScalarState& state) {
const auto first = state->vector_lanes.lower_bound(VectorLaneKey(reg, 0)); const auto first = state.vector_lanes.lower_bound(VectorLaneKey(reg, 0));
const auto last = state->vector_lanes.lower_bound((static_cast<uint64_t>(reg) + 1u) << 32u); const auto last = state.vector_lanes.lower_bound((static_cast<uint64_t>(reg) + 1u) << 32u);
state->vector_lanes.erase(first, last); 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) { if (inst.dst.kind != OperandKind::Register || inst.dst.reg.file != RegisterFile::Vector) {
return; return;
} }
@@ -410,8 +407,8 @@ private:
for (uint32_t i = 0; i < inst.src_count; i++) { for (uint32_t i = 0; i < inst.src_count; i++) {
uint32_t src_reg = 0; uint32_t src_reg = 0;
if (VectorRegister(inst.src[i], src_reg) && if (VectorRegister(inst.src[i], src_reg) &&
state->address_bases[src_reg] > ScalarProvenance::Unknown) { state.address_bases[src_reg] > ScalarProvenance::Unknown) {
address_base = state->address_bases[src_reg]; address_base = state.address_bases[src_reg];
break; break;
} }
} }
@@ -419,16 +416,16 @@ private:
for (uint32_t i = 0; i < inst.src_count; i++) { for (uint32_t i = 0; i < inst.src_count; i++) {
uint32_t src_reg = 0; uint32_t src_reg = 0;
if (ScalarRegister(inst.src[i], src_reg) && if (ScalarRegister(inst.src[i], src_reg) &&
state->regs[src_reg] > ScalarProvenance::Unknown) { state.regs[src_reg] > ScalarProvenance::Unknown) {
address_base = state->regs[src_reg]; address_base = state.regs[src_reg];
break; break;
} }
} }
} }
} }
state->address_bases[reg] = ScalarProvenance::Unknown; state.address_bases[reg] = ScalarProvenance::Unknown;
if (inst.op == Opcode::MoveRelDestU32) { if (inst.op == Opcode::MoveRelDestU32) {
state->vector_lanes.clear(); state.vector_lanes.clear();
return; return;
} }
if (inst.op != Opcode::WriteLaneU32) { if (inst.op != Opcode::WriteLaneU32) {
@@ -438,24 +435,24 @@ private:
} }
for (uint32_t i = 0; i < dwords && reg <= UINT32_MAX - i; i++) { for (uint32_t i = 0; i < dwords && reg <= UINT32_MAX - i; i++) {
ClearVectorLanes(reg + i, state); ClearVectorLanes(reg + i, state);
if (reg + i < state->address_bases.size()) { if (reg + i < state.address_bases.size()) {
state->address_bases[reg + i] = ScalarProvenance::Unknown; state.address_bases[reg + i] = ScalarProvenance::Unknown;
} }
} }
state->address_bases[reg] = address_base; state.address_bases[reg] = address_base;
return; 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); ClearVectorLanes(reg, state);
return; return;
} }
uint32_t lane = 0; uint32_t lane = 0;
if (!ConstantOperand(inst.src[1], *state, &lane)) { if (!ConstantOperand(inst.src[1], state, lane)) {
ClearVectorLanes(reg, state); ClearVectorLanes(reg, state);
return; return;
} }
state->vector_lanes[VectorLaneKey(reg, lane % m_program->wave_size)] = state.vector_lanes[VectorLaneKey(reg, lane % m_program.wave_size)] =
OperandValue(inst.src[0], *state); OperandValue(inst.src[0], state);
} }
uint32_t ReadConst(const Instruction& inst, const ScalarState& state, bool buffer) { 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) { switch (inst.op) {
case Opcode::ScalarAddCarryU32: case Opcode::ScalarAddCarryU32:
state->scc = Define(inst, ScalarValueOp::Carry, before); state.scc = Define(inst, ScalarValueOp::Carry, before);
break; break;
case Opcode::ScalarSubBorrowU32: case Opcode::ScalarSubBorrowU32:
case Opcode::ScalarSubBorrowCarryU32: state->scc = DefineBorrow(inst, before); break; case Opcode::ScalarSubBorrowCarryU32: state.scc = DefineBorrow(inst, before); break;
case Opcode::ScalarShiftLeftAddCarryU32: case Opcode::ScalarShiftLeftAddCarryU32:
state->scc = Define(inst, ScalarValueOp::ShiftLeftAddCarry, before); state.scc = Define(inst, ScalarValueOp::ShiftLeftAddCarry, before);
break; break;
default: 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) { if (inst.dst.kind == OperandKind::Register && inst.dst.reg.file == RegisterFile::Scc) {
state->scc = inst.op == Opcode::MoveU32 && inst.src_count != 0 state.scc = inst.op == Opcode::MoveU32 && inst.src_count != 0
? OperandValue(inst.src[0], *state) ? OperandValue(inst.src[0], state)
: ScalarProvenance::Unknown; : ScalarProvenance::Unknown;
return; return;
} }
if (inst.dst.kind == OperandKind::Register && inst.dst.reg.file == RegisterFile::M0) { 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); 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) ? OperandValue(inst.src[0], before)
: op != ScalarValueOp::Unknown ? Define(inst, op, before) : op != ScalarValueOp::Unknown ? Define(inst, op, before)
: ScalarProvenance::Unknown; : ScalarProvenance::Unknown;
@@ -551,10 +548,10 @@ private:
return; return;
} }
const auto before = *state; const auto before = state;
state->regs[dst] = ScalarProvenance::Unknown; state.regs[dst] = ScalarProvenance::Unknown;
if (PairDwordOpcode(inst.op) && dst + 1 < ScalarRegisters) { if (PairDwordOpcode(inst.op) && dst + 1 < ScalarRegisters) {
state->regs[dst + 1] = ScalarProvenance::Unknown; state.regs[dst + 1] = ScalarProvenance::Unknown;
} }
uint32_t value = ScalarProvenance::Unknown; uint32_t value = ScalarProvenance::Unknown;
@@ -582,10 +579,10 @@ private:
if (inst.src_count != 0 && dst + 1 < ScalarRegisters) { if (inst.src_count != 0 && dst + 1 < ScalarRegisters) {
if (ScalarRegister(inst.src[0], src) && src + 1 < ScalarRegisters) { if (ScalarRegister(inst.src[0], src) && src + 1 < ScalarRegisters) {
value = before.regs[src]; value = before.regs[src];
state->regs[dst + 1] = before.regs[src + 1]; state.regs[dst + 1] = before.regs[src + 1];
} else { } else {
value = OperandValue(inst.src[0], before); 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 inst.src[0].kind == OperandKind::ImmediateU32 && inst.src[0].sext_64
? UINT32_MAX ? UINT32_MAX
: 0u); : 0u);
@@ -596,7 +593,7 @@ private:
case Opcode::BitFieldMaskU64: case Opcode::BitFieldMaskU64:
value = Define(inst, ScalarValueOp::BitFieldMaskU64Low, before); value = Define(inst, ScalarValueOp::BitFieldMaskU64Low, before);
if (dst + 1 < ScalarRegisters) { if (dst + 1 < ScalarRegisters) {
state->regs[dst + 1] = Define(inst, ScalarValueOp::BitFieldMaskU64High, before); state.regs[dst + 1] = Define(inst, ScalarValueOp::BitFieldMaskU64High, before);
} }
break; break;
case Opcode::SLoadDword: value = ReadConst(inst, before, false); break; case Opcode::SLoadDword: value = ReadConst(inst, before, false); break;
@@ -610,12 +607,12 @@ private:
break; break;
} }
} }
state->regs[dst] = value; state.regs[dst] = value;
UpdateScc(inst, before, state); UpdateScc(inst, before, state);
uint32_t dst2 = 0; uint32_t dst2 = 0;
if (ScalarRegister(inst.dst2, dst2)) { if (ScalarRegister(inst.dst2, dst2)) {
state->regs[dst2] = state.regs[dst2] =
inst.src_count > 1 ? OperandValue(inst.src[1], before) : ScalarProvenance::Unknown; inst.src_count > 1 ? OperandValue(inst.src[1], before) : ScalarProvenance::Unknown;
} }
} }
@@ -663,57 +660,57 @@ private:
return AddDescriptor(descriptor); return AddDescriptor(descriptor);
} }
void AttachSources(Instruction* inst, const ScalarState& state) { void AttachSources(Instruction& inst, const ScalarState& state) {
inst->memory.resource_source = 0; inst.memory.resource_source = 0;
inst->memory.sampler_source = 0; inst.memory.sampler_source = 0;
if (inst->op == Opcode::SLoadDword) { if (inst.op == Opcode::SLoadDword) {
inst->memory.resource_source = AddDescriptor(state, inst->memory.resource, 2); inst.memory.resource_source = AddDescriptor(state, inst.memory.resource, 2);
return; return;
} }
if (inst->memory.kind == ResourceKind::Flat || inst->memory.kind == ResourceKind::Global || if (inst.memory.kind == ResourceKind::Flat || inst.memory.kind == ResourceKind::Global ||
inst->memory.kind == ResourceKind::Scratch) { inst.memory.kind == ResourceKind::Scratch) {
inst->memory.resource_source = ScalarProvenance::Unknown; inst.memory.resource_source = ScalarProvenance::Unknown;
if (inst->memory.kind == ResourceKind::Flat) { if (inst.memory.kind == ResourceKind::Flat) {
inst->memory.resource_source = AddFlatAddressDescriptor(*inst, state); inst.memory.resource_source = AddFlatAddressDescriptor(inst, state);
} }
for (uint32_t i = 0; i < inst->src_count; i++) { for (uint32_t i = 0; i < inst.src_count; i++) {
const auto& source = inst->src[i]; const auto& source = inst.src[i];
if (inst->memory.resource_source == ScalarProvenance::Unknown && if (inst.memory.resource_source == ScalarProvenance::Unknown &&
source.kind == OperandKind::Register && source.kind == OperandKind::Register &&
source.reg.file == RegisterFile::Scalar) { 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; break;
} }
} }
return; return;
} }
if (inst->memory.kind == ResourceKind::Buffer || if (inst.memory.kind == ResourceKind::Buffer ||
(inst->memory.kind == ResourceKind::ScalarBuffer && (inst.memory.kind == ResourceKind::ScalarBuffer &&
inst->op == Opcode::SBufferLoadDword)) { inst.op == Opcode::SBufferLoadDword)) {
const auto base = inst->memory.resource * 4u; const auto base = inst.memory.resource * 4u;
inst->memory.resource_source = AddDescriptor(state, base, 4); inst.memory.resource_source = AddDescriptor(state, base, 4);
return; return;
} }
if (inst->memory.kind == ResourceKind::Image || if (inst.memory.kind == ResourceKind::Image ||
inst->memory.kind == ResourceKind::ImageUint || inst.memory.kind == ResourceKind::ImageUint ||
inst->memory.kind == ResourceKind::StorageImage || inst.memory.kind == ResourceKind::StorageImage ||
inst->memory.kind == ResourceKind::StorageImageUint) { inst.memory.kind == ResourceKind::StorageImageUint) {
inst->memory.resource_source = AddDescriptor(state, inst->memory.resource * 4u, 8); inst.memory.resource_source = AddDescriptor(state, inst.memory.resource * 4u, 8);
if (inst->op == Opcode::ImageSample || inst->op == Opcode::ImageGather4 || if (inst.op == Opcode::ImageSample || inst.op == Opcode::ImageGather4 ||
inst->op == Opcode::ImageGetLod) { inst.op == Opcode::ImageGetLod) {
inst->memory.sampler_source = AddDescriptor(state, inst->memory.sampler * 4u, 4); inst.memory.sampler_source = AddDescriptor(state, inst.memory.sampler * 4u, 4);
} }
} }
} }
void AttachScalarSources(Instruction* inst, const ScalarState& state) { void AttachScalarSources(Instruction& inst, const ScalarState& state) {
std::fill(std::begin(inst->scalar_sources), std::end(inst->scalar_sources), std::fill(std::begin(inst.scalar_sources), std::end(inst.scalar_sources),
ScalarProvenance::Undefined); ScalarProvenance::Undefined);
for (uint32_t i = 0; i < inst->src_count; i++) { for (uint32_t i = 0; i < inst.src_count; i++) {
const auto& source = inst->src[i]; const auto& source = inst.src[i];
if (source.kind == OperandKind::Register && source.reg.file != RegisterFile::Vector && if (source.kind == OperandKind::Register && source.reg.file != RegisterFile::Vector &&
source.reg.file != RegisterFile::Exec) { 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]; auto& component_inst = block.instructions[index + component];
if (attach_sources) { if (attach_sources) {
component_inst.scalar_value = ScalarProvenance::Undefined; component_inst.scalar_value = ScalarProvenance::Undefined;
AttachScalarSources(&component_inst, before); AttachScalarSources(component_inst, before);
AttachSources(&component_inst, before); AttachSources(component_inst, before);
} }
auto component_state = before; auto component_state = before;
WriteDestination(component_inst, &component_state); WriteDestination(component_inst, component_state);
uint32_t dst = 0; uint32_t dst = 0;
ScalarRegister(component_inst.dst, dst); ScalarRegister(component_inst.dst, dst);
state.regs[dst] = component_state.regs[dst]; state.regs[dst] = component_state.regs[dst];
@@ -746,11 +743,11 @@ private:
} }
if (attach_sources) { if (attach_sources) {
inst.scalar_value = ScalarProvenance::Undefined; inst.scalar_value = ScalarProvenance::Undefined;
AttachScalarSources(&inst, state); AttachScalarSources(inst, state);
AttachSources(&inst, state); AttachSources(inst, state);
} }
WriteVectorDestination(inst, &state); WriteVectorDestination(inst, state);
WriteDestination(inst, &state); WriteDestination(inst, state);
if (attach_sources) { if (attach_sources) {
uint32_t dst = 0; uint32_t dst = 0;
if (ScalarRegister(inst.dst, dst)) { if (ScalarRegister(inst.dst, dst)) {
@@ -765,7 +762,7 @@ private:
ScalarState MergeEntry(size_t block_index) { ScalarState MergeEntry(size_t block_index) {
ScalarState result; ScalarState result;
result.Fill(ScalarProvenance::Undefined); 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) { const auto merge = [&](uint32_t initial, auto predecessor_value, uint32_t* phi) {
std::vector<uint32_t> incoming; std::vector<uint32_t> incoming;
if (initial != ScalarProvenance::Undefined) { if (initial != ScalarProvenance::Undefined) {
@@ -845,7 +842,7 @@ private:
} }
} }
Program* m_program; Program& m_program;
ScalarProvenance& m_graph; ScalarProvenance& m_graph;
ScalarState m_user_data; ScalarState m_user_data;
std::vector<ScalarState> m_entry; std::vector<ScalarState> m_entry;
@@ -860,40 +857,34 @@ private:
} // namespace } // namespace
bool BuildScalarProvenance(Program* program, std::string* error) { bool BuildScalarProvenance(Program& program, std::string* error) {
if (program == nullptr) { if (program.resource_tracking_complete) {
if (error != nullptr) {
*error = "invalid scalar provenance program";
}
return false;
}
if (program->resource_tracking_complete) {
if (error != nullptr) { if (error != nullptr) {
*error = "cannot rebuild scalar provenance after resource tracking"; *error = "cannot rebuild scalar provenance after resource tracking";
} }
return false; return false;
} }
if (program->user_data_count > 64) { if (program.user_data_count > 64) {
if (error != nullptr) { if (error != nullptr) {
*error = "scalar provenance user-data count exceeds 64 SGPRs"; *error = "scalar provenance user-data count exceeds 64 SGPRs";
} }
return false; return false;
} }
if (program->user_data_base > ScalarRegisters || if (program.user_data_base > ScalarRegisters ||
program->user_data_count > ScalarRegisters - program->user_data_base) { program.user_data_count > ScalarRegisters - program.user_data_base) {
if (error != nullptr) { if (error != nullptr) {
*error = "scalar provenance user-data window is out of range"; *error = "scalar provenance user-data window is out of range";
} }
return false; return false;
} }
if (program->srt_patching_complete) { if (program.srt_patching_complete) {
if (error != nullptr) { if (error != nullptr) {
*error = "cannot rebuild scalar provenance after SRT patching"; *error = "cannot rebuild scalar provenance after SRT patching";
} }
return false; return false;
} }
program->srt = {}; program.srt = {};
program->srt_plan_complete = false; program.srt_plan_complete = false;
return Builder(program).Run(error); return Builder(program).Run(error);
} }
@@ -911,7 +902,7 @@ bool DescriptorSourceResolved(const Program& program, uint32_t source) {
} }
std::vector<uint8_t> visited(program.provenance.values.size()); std::vector<uint8_t> visited(program.provenance.values.size());
for (uint32_t i = 0; i < descriptor->dword_count; i++) { 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; return false;
} }
} }
@@ -6,7 +6,7 @@
namespace Libs::Graphics::ShaderRecompiler::IR { namespace Libs::Graphics::ShaderRecompiler::IR {
// Builds scalar reaching definitions and attaches descriptor sources to individual memory uses. // 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); uint32_t ScalarValueArgCount(ScalarValueOp op);
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -105,8 +105,8 @@ struct Graph {
uint32_t FindNearestCommonPostDominator(uint32_t block_a, uint32_t block_b) const; uint32_t FindNearestCommonPostDominator(uint32_t block_a, uint32_t block_b) const;
}; };
bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* error); bool BuildGraph(const Decoder::Program& program, Graph& graph, std::string* error);
bool Structurize(Graph* graph, std::string* error); bool Structurize(Graph& graph, std::string* error);
std::string BranchConditionToString(BranchCondition condition); std::string BranchConditionToString(BranchCondition condition);
std::string FailureKindToString(FailureKind kind); std::string FailureKindToString(FailureKind kind);
std::string FormatBlockDiagnostic(const Graph& graph, uint32_t block_id, const char* stage, std::string FormatBlockDiagnostic(const Graph& graph, uint32_t block_id, const char* stage,
+87 -101
View File
@@ -44,10 +44,10 @@ bool IsControlFlowBranch(Opcode opcode) {
} }
} }
void ApplyLiteral(Operand* operand, uint32_t literal) { void ApplyLiteral(Operand& operand, uint32_t literal) {
if (operand->kind == OperandKind::LiteralConstant) { if (operand.kind == OperandKind::LiteralConstant) {
operand->value = literal; operand.value = literal;
operand->signed_val = static_cast<int32_t>(literal); operand.signed_val = static_cast<int32_t>(literal);
} }
} }
@@ -196,36 +196,31 @@ std::string FormatExp(const Instruction& inst) {
} // namespace } // namespace
bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::string* error) { bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error) {
if (operand == nullptr) { operand = {};
SetError(error, "internal decoder error: null source operand");
return false;
}
*operand = {};
if (code <= 105u) { if (code <= 105u) {
operand->kind = OperandKind::Sgpr; operand.kind = OperandKind::Sgpr;
operand->reg = code; operand.reg = code;
return true; return true;
} }
if (code >= 128u && code <= 192u) { if (code >= 128u && code <= 192u) {
operand->kind = OperandKind::IntegerInlineConstant; operand.kind = OperandKind::IntegerInlineConstant;
operand->signed_val = static_cast<int32_t>(code - 128u); operand.signed_val = static_cast<int32_t>(code - 128u);
operand->value = static_cast<uint32_t>(operand->signed_val); operand.value = static_cast<uint32_t>(operand.signed_val);
return true; return true;
} }
if (code >= 193u && code <= 208u) { if (code >= 193u && code <= 208u) {
operand->kind = OperandKind::IntegerInlineConstant; operand.kind = OperandKind::IntegerInlineConstant;
operand->signed_val = 192 - static_cast<int32_t>(code); operand.signed_val = 192 - static_cast<int32_t>(code);
operand->value = static_cast<uint32_t>(operand->signed_val); operand.value = static_cast<uint32_t>(operand.signed_val);
return true; return true;
} }
if (code >= 240u && code <= 247u) { if (code >= 240u && code <= 247u) {
constexpr float values[] = {0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f, 4.0f, -4.0f}; constexpr float values[] = {0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f, 4.0f, -4.0f};
operand->kind = OperandKind::FloatInlineConstant; operand.kind = OperandKind::FloatInlineConstant;
operand->float_val = values[code - 240u]; operand.float_val = values[code - 240u];
operand->value = FloatBits(operand->float_val); operand.value = FloatBits(operand.float_val);
return true; return true;
} }
if (code >= 256u && code <= 511u) { if (code >= 256u && code <= 511u) {
@@ -233,22 +228,22 @@ bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::strin
} }
switch (code) { switch (code) {
case 106u: operand->kind = OperandKind::VccLo; return true; case 106u: operand.kind = OperandKind::VccLo; return true;
case 107u: operand->kind = OperandKind::VccHi; return true; case 107u: operand.kind = OperandKind::VccHi; return true;
case 124u: operand->kind = OperandKind::M0; return true; case 124u: operand.kind = OperandKind::M0; return true;
case 125u: operand->kind = OperandKind::Null; return true; case 125u: operand.kind = OperandKind::Null; return true;
case 126u: operand->kind = OperandKind::ExecLo; return true; case 126u: operand.kind = OperandKind::ExecLo; return true;
case 127u: operand->kind = OperandKind::ExecHi; return true; case 127u: operand.kind = OperandKind::ExecHi; return true;
case 239u: operand->kind = OperandKind::PopsExitingWaveId; return true; case 239u: operand.kind = OperandKind::PopsExitingWaveId; return true;
case 248u: case 248u:
operand->kind = OperandKind::FloatInlineConstant; operand.kind = OperandKind::FloatInlineConstant;
operand->float_val = 0.15915494309189535f; operand.float_val = 0.15915494309189535f;
operand->value = FloatBits(operand->float_val); operand.value = FloatBits(operand.float_val);
return true; return true;
case 251u: operand->kind = OperandKind::VccZ; return true; case 251u: operand.kind = OperandKind::VccZ; return true;
case 252u: operand->kind = OperandKind::ExecZ; return true; case 252u: operand.kind = OperandKind::ExecZ; return true;
case 253u: operand->kind = OperandKind::Scc; return true; case 253u: operand.kind = OperandKind::Scc; return true;
case 255u: operand->kind = OperandKind::LiteralConstant; return true; case 255u: operand.kind = OperandKind::LiteralConstant; return true;
default: default:
if (error != nullptr) { if (error != nullptr) {
*error = fmt::format("unsupported scalar source operand 0x{:08x} at pc 0x{:08x}", *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) { bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error) {
if (operand == nullptr) { operand = {};
SetError(error, "internal decoder error: null destination operand");
return false;
}
*operand = {};
if (code <= 105u) { if (code <= 105u) {
operand->kind = OperandKind::Sgpr; operand.kind = OperandKind::Sgpr;
operand->reg = code; operand.reg = code;
return true; return true;
} }
switch (code) { switch (code) {
case 106u: operand->kind = OperandKind::VccLo; return true; case 106u: operand.kind = OperandKind::VccLo; return true;
case 107u: operand->kind = OperandKind::VccHi; return true; case 107u: operand.kind = OperandKind::VccHi; return true;
case 124u: operand->kind = OperandKind::M0; return true; case 124u: operand.kind = OperandKind::M0; return true;
case 125u: operand->kind = OperandKind::Null; return true; case 125u: operand.kind = OperandKind::Null; return true;
case 126u: operand->kind = OperandKind::ExecLo; return true; case 126u: operand.kind = OperandKind::ExecLo; return true;
case 127u: operand->kind = OperandKind::ExecHi; return true; case 127u: operand.kind = OperandKind::ExecHi; return true;
default: default:
if (error != nullptr) { if (error != nullptr) {
*error = fmt::format( *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) { bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error) {
if (operand == nullptr) {
SetError(error, "internal decoder error: null VGPR operand");
return false;
}
if (reg > 255u) { if (reg > 255u) {
SetError(error, "VGPR index is out of range"); SetError(error, "VGPR index is out of range");
return false; return false;
} }
*operand = {}; operand = {};
operand->kind = OperandKind::Vgpr; operand.kind = OperandKind::Vgpr;
operand->reg = reg; operand.reg = reg;
return true; return true;
} }
bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error) { std::string* error) {
if (!HasLiteral(*inst)) { if (!HasLiteral(inst)) {
return true; return true;
} }
if (word_index + inst->word_count >= code.size()) { if (word_index + inst.word_count >= code.size()) {
if (error != nullptr) { 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; return false;
} }
const auto literal = code[word_index + inst->word_count]; const auto literal = code[word_index + inst.word_count];
ApplyLiteral(&inst->src0, literal); ApplyLiteral(inst.src0, literal);
ApplyLiteral(&inst->src1, literal); ApplyLiteral(inst.src1, literal);
ApplyLiteral(&inst->src2, literal); ApplyLiteral(inst.src2, literal);
ApplyLiteral(&inst->src3, literal); ApplyLiteral(inst.src3, literal);
inst->word_count++; inst.word_count++;
SetRawWords(inst, code, word_index, inst->word_count); SetRawWords(inst, code, word_index, inst.word_count);
return true; return true;
} }
void SetRawWords(Instruction* inst, std::span<const uint32_t> code, uint32_t word_index, void SetRawWords(Instruction& inst, std::span<const uint32_t> code, uint32_t word_index,
uint32_t word_count) { uint32_t word_count) {
inst->word_count = word_count; inst.word_count = word_count;
inst->raw_count = std::min<uint32_t>(word_count, MaxInstructionRawWords); inst.raw_count = std::min<uint32_t>(word_count, MaxInstructionRawWords);
for (uint32_t i = 0; i < inst->raw_count; i++) { for (uint32_t i = 0; i < inst.raw_count; i++) {
inst->raw[i] = code[word_index + i]; inst.raw[i] = code[word_index + i];
} }
} }
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) {
inst->opcode = Opcode::Unsupported; inst.opcode = Opcode::Unsupported;
inst->family = family; inst.family = family;
inst->opcode_id = opcode_id; inst.opcode_id = opcode_id;
inst->unsupported_reason = reason; inst.unsupported_reason = reason;
} }
bool DecodeProgram(std::span<const uint32_t> code, Program* program, std::string* error) { bool DecodeProgram(std::span<const uint32_t> code, Program& program, std::string* error) {
if (code.empty() || code.size() > UINT32_MAX / sizeof(uint32_t) || program == nullptr) { if (code.empty() || code.size() > UINT32_MAX / sizeof(uint32_t)) {
SetError(error, "invalid shader decoder input"); SetError(error, "invalid shader decoder input");
return false; return false;
} }
program->instructions.clear(); program.instructions.clear();
program->code = code; program.code = code;
std::set<uint32_t> branch_targets; std::set<uint32_t> branch_targets;
for (uint32_t word_index = 0; word_index < code.size();) { for (uint32_t word_index = 0; word_index < code.size();) {
@@ -358,30 +344,30 @@ bool DecodeProgram(std::span<const uint32_t> code, Program* program, std::string
Instruction inst; Instruction inst;
bool ok = false; bool ok = false;
if ((word & 0x80000000u) == 0u) { 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) { } else if ((word & 0xc0000000u) == 0x80000000u) {
const auto opcode = (word >> 23u) & 0x7fu; const auto opcode = (word >> 23u) & 0x7fu;
switch (opcode) { switch (opcode) {
case 0x7du: ok = DecodeSop1(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 0x7eu: ok = DecodeSopc(pc, code, word_index, inst, error); break;
case 0x7fu: ok = DecodeSopp(pc, code, word_index, &inst, error); break; case 0x7fu: ok = DecodeSopp(pc, code, word_index, inst, error); break;
default: default:
ok = opcode >= 0x60u ? DecodeSopk(pc, code, word_index, &inst, error) ok = opcode >= 0x60u ? DecodeSopk(pc, code, word_index, inst, error)
: DecodeSop2(pc, code, word_index, &inst, error); : DecodeSop2(pc, code, word_index, inst, error);
break; break;
} }
} else { } else {
switch (word >> 26u) { switch (word >> 26u) {
case 0x32u: ok = DecodeVintrp(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 0x33u: ok = DecodeVop3p(pc, code, word_index, inst, error); break;
case 0x35u: ok = DecodeVop3(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 0x36u: ok = DecodeDs(pc, code, word_index, inst, error); break;
case 0x37u: ok = DecodeFlat(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 0x38u: ok = DecodeMubuf(pc, code, word_index, inst, error); break;
case 0x3au: ok = DecodeMtbuf(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 0x3cu: ok = DecodeMimg(pc, code, word_index, inst, error); break;
case 0x3du: ok = DecodeSmem(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 0x3eu: ok = DecodeExp(pc, code, word_index, inst, error); break;
default: default:
if (error != nullptr) { if (error != nullptr) {
*error = fmt::format( *error = fmt::format(
@@ -396,7 +382,7 @@ bool DecodeProgram(std::span<const uint32_t> code, Program* program, std::string
return false; return false;
} }
program->instructions.push_back(inst); program.instructions.push_back(inst);
word_index += inst.word_count; word_index += inst.word_count;
if (IsControlFlowBranch(inst.opcode)) { if (IsControlFlowBranch(inst.opcode)) {
@@ -656,16 +656,16 @@ struct Program {
std::vector<Instruction> instructions; std::vector<Instruction> instructions;
}; };
bool DecodeProgram(std::span<const uint32_t> code, Program* program, std::string* error); bool DecodeProgram(std::span<const uint32_t> code, Program& program, std::string* error);
bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, 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 DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error);
bool DecodeVectorGpr(uint32_t reg, Operand* operand, std::string* error); bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error);
bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction* inst, bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
std::string* error); std::string* error);
void SetRawWords(Instruction* inst, std::span<const uint32_t> code, uint32_t word_index, void SetRawWords(Instruction& inst, std::span<const uint32_t> code, uint32_t word_index,
uint32_t word_count); 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 FamilyToString(Family family);
std::string OpcodeToString(Opcode opcode); std::string OpcodeToString(Opcode opcode);
std::string OperandToString(const Operand& operand); std::string OperandToString(const Operand& operand);
+1 -1
View File
@@ -753,7 +753,7 @@ struct Program {
}; };
bool LowerProgram(const Decoder::Program& decoded, const CFG::Graph& cfg, ShaderType stage, 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 RegisterToString(Register reg);
std::string OperandToString(const Operand& operand); std::string OperandToString(const Operand& operand);
@@ -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) { std::string name) {
if (!HasInput(*info, kind, location)) { if (!HasInput(info, kind, location)) {
info->inputs.push_back({kind, location, components, std::move(name)}); 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) { std::string name) {
if (!HasOutput(*info, kind, index)) { if (!HasOutput(info, kind, index)) {
info->outputs.push_back({kind, index, location, std::move(name)}); 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, void CollectVertexInputs(const Program& program, const ShaderVertexInputInfo* vertex,
ShaderInfo* info) { ShaderInfo& info) {
AddInput(info, StageInputKind::VertexIndex, 0, 1, "gl_VertexIndex"); AddInput(info, StageInputKind::VertexIndex, 0, 1, "gl_VertexIndex");
AddInput(info, StageInputKind::InstanceIndex, 0, 1, "gl_InstanceIndex"); AddInput(info, StageInputKind::InstanceIndex, 0, 1, "gl_InstanceIndex");
if (vertex == nullptr) { 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) { if (pixel == nullptr) {
return; return;
} }
@@ -130,7 +130,7 @@ void CollectPixelInputs(const ShaderPixelInputInfo* pixel, ShaderInfo* info) {
} }
void CollectComputeInputs(const Program& program, const ShaderComputeInputInfo* compute, void CollectComputeInputs(const Program& program, const ShaderComputeInputInfo* compute,
ShaderInfo* info) { ShaderInfo& info) {
if (compute != nullptr) { if (compute != nullptr) {
if (compute->group_id[0] || compute->group_id[1] || compute->group_id[2]) { if (compute->group_id[0] || compute->group_id[1] || compute->group_id[2]) {
AddInput(info, StageInputKind::WorkgroupId, 0, 3, "gl_WorkGroupID"); 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& block: program.blocks) {
for (const auto& inst: block.instructions) { for (const auto& inst: block.instructions) {
if (inst.op != Opcode::Export) { if (inst.op != Opcode::Export) {
@@ -193,32 +193,30 @@ void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, S
} // namespace } // namespace
bool CollectShaderInfo(Program* program, const ShaderInfoOptions& options, std::string* error) { bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::string* error) {
if (program == nullptr || !program->resource_tracking_complete || if (!program.resource_tracking_complete || program.shader_info_complete) {
program->shader_info_complete) {
if (error != nullptr) { if (error != nullptr) {
*error = program == nullptr ? "invalid shader info program" *error = !program.resource_tracking_complete ? "shader resources were not tracked"
: !program->resource_tracking_complete ? "shader resources were not tracked"
: "shader info already collected"; : "shader info already collected";
} }
return false; return false;
} }
if (!ValidateOptions(*program, options, error)) { if (!ValidateOptions(program, options, error)) {
return false; return false;
} }
auto next = program->info; auto next = program.info;
next.inputs.clear(); next.inputs.clear();
next.outputs.clear(); next.outputs.clear();
switch (program->stage) { switch (program.stage) {
case ShaderType::Vertex: CollectVertexInputs(*program, options.vertex, &next); break; case ShaderType::Vertex: CollectVertexInputs(program, options.vertex, next); break;
case ShaderType::Pixel: CollectPixelInputs(options.pixel, &next); break; case ShaderType::Pixel: CollectPixelInputs(options.pixel, next); break;
case ShaderType::Compute: CollectComputeInputs(*program, options.compute, &next); break; case ShaderType::Compute: CollectComputeInputs(program, options.compute, next); break;
default: return false; default: return false;
} }
CollectOutputs(*program, options.pixel, &next); CollectOutputs(program, options.pixel, next);
program->info = std::move(next); program.info = std::move(next);
program->shader_info_complete = true; program.shader_info_complete = true;
return true; return true;
} }
@@ -13,7 +13,7 @@ struct ShaderInfoOptions {
// Completes the immutable shader interface after resource tracking. On failure Program::info and // Completes the immutable shader interface after resource tracking. On failure Program::info and
// all completion state remain unchanged. // 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 } // namespace Libs::Graphics::ShaderRecompiler::IR
@@ -289,12 +289,11 @@ int BufferTableAttribFromOffset(uint32_t raw_offset, int dword) {
return static_cast<int>((raw_offset + static_cast<uint32_t>(dword) * 4u) / 16u); return static_cast<int>((raw_offset + static_cast<uint32_t>(dword) * 4u) / 16u);
} }
void AppendUniquePcs(std::vector<uint32_t>* dst, const std::vector<uint32_t>& src) { void AppendUniquePcs(std::vector<uint32_t>& dst, const std::vector<uint32_t>& src) {
EXIT_IF(dst == nullptr); dst.reserve(dst.size() + src.size());
dst->reserve(dst->size() + src.size());
for (auto pc: src) { for (auto pc: src) {
if (std::find(dst->begin(), dst->end(), pc) == dst->end()) { if (std::find(dst.begin(), dst.end(), pc) == dst.end()) {
dst->push_back(pc); dst.push_back(pc);
} }
} }
} }
@@ -578,21 +577,21 @@ int ResolveEmbeddedFetchResource(const ShaderVertexInputInfo* input_info,
return -1; 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<EmbeddedFetchLoad>& loads) { const std::vector<EmbeddedFetchLoad>& loads) {
if (ir == nullptr || input_info == nullptr || loads.empty()) { if (input_info == nullptr || loads.empty()) {
return 0; return 0;
} }
std::vector<uint32_t> prolog_pcs; std::vector<uint32_t> prolog_pcs;
prolog_pcs.reserve(loads.size()); prolog_pcs.reserve(loads.size());
for (const auto& load: loads) { for (const auto& load: loads) {
AppendUniquePcs(&prolog_pcs, load.prolog_loads); AppendUniquePcs(prolog_pcs, load.prolog_loads);
} }
auto* mutable_input_info = const_cast<ShaderVertexInputInfo*>(input_info); auto* mutable_input_info = const_cast<ShaderVertexInputInfo*>(input_info);
uint32_t rewritten = 0; uint32_t rewritten = 0;
for (auto& block: ir->blocks) { for (auto& block: ir.blocks) {
for (auto& inst: block.instructions) { for (auto& inst: block.instructions) {
if (IsIrFetchPrologLoad(inst) && EmbeddedFetchPcInList(prolog_pcs, inst.pc)) { if (IsIrFetchPrologLoad(inst) && EmbeddedFetchPcInList(prolog_pcs, inst.pc)) {
auto pc = inst.pc; auto pc = inst.pc;
@@ -637,8 +636,8 @@ uint32_t RewriteEmbeddedVertexFetches(IR::Program* ir, const ShaderVertexInputIn
} // namespace } // namespace
bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options, bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
CompileResult* result, std::string* error) { CompileResult& result, std::string* error) {
if (code.empty() || result == nullptr) { if (code.empty()) {
if (error != nullptr) { if (error != nullptr) {
*error = "invalid shader recompiler input"; *error = "invalid shader recompiler input";
} }
@@ -664,7 +663,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
static_cast<uint64_t>(code.size())); static_cast<uint64_t>(code.size()));
Decoder::Program decoded; Decoder::Program decoded;
if (!Decoder::DecodeProgram(code, &decoded, error)) { if (!Decoder::DecodeProgram(code, decoded, error)) {
return false; return false;
} }
LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " decode instructions=%" PRIu64 LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " decode instructions=%" PRIu64
@@ -683,7 +682,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
CFG::Graph cfg; CFG::Graph cfg;
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG BuildGraph\n", GetDumpLabel(options), LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG BuildGraph\n", GetDumpLabel(options),
StageName(options.stage), options.shader_hash); StageName(options.stage), options.shader_hash);
if (!CFG::BuildGraph(decoded, &cfg, error)) { if (!CFG::BuildGraph(decoded, cfg, error)) {
return false; return false;
} }
LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " CFG BuildGraph blocks=%" PRIu64 LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " CFG BuildGraph blocks=%" PRIu64
@@ -703,7 +702,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
const auto unstructured_cfg = cfg; const auto unstructured_cfg = cfg;
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG Structurize\n", LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG Structurize\n",
GetDumpLabel(options), StageName(options.stage), options.shader_hash); 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); const auto diagnostic = FormatCfgFailure(cfg, options, structure_error);
LOGF("%s structured CFG bug/failure: %s\n", GetDumpLabel(options), diagnostic.c_str()); LOGF("%s structured CFG bug/failure: %s\n", GetDumpLabel(options), diagnostic.c_str());
dispatcher_fallback = true; dispatcher_fallback = true;
@@ -729,7 +728,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
IR::Program ir; IR::Program ir;
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " IR LowerProgram\n", GetDumpLabel(options), LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " IR LowerProgram\n", GetDumpLabel(options),
StageName(options.stage), options.shader_hash); 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; return false;
} }
ir.lane_mask_mode = options.lane_mask_mode; ir.lane_mask_mode = options.lane_mask_mode;
@@ -747,18 +746,18 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
DetectEmbeddedVertexFetch(decoded, options.vertex_input_info, ir.user_data_base, DetectEmbeddedVertexFetch(decoded, options.vertex_input_info, ir.user_data_base,
ir.user_data_count, options.wave_size); ir.user_data_count, options.wave_size);
auto rewritten = 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()) { if (rewritten > 0 || !embedded_fetch.loads.empty()) {
LOGF("%s embedded vertex fetch rewrite: detected=%" PRIu64 " rewritten=%" PRIu32 "\n", LOGF("%s embedded vertex fetch rewrite: detected=%" PRIu64 " rewritten=%" PRIu32 "\n",
GetDumpLabel(options), static_cast<uint64_t>(embedded_fetch.loads.size()), GetDumpLabel(options), static_cast<uint64_t>(embedded_fetch.loads.size()),
rewritten); rewritten);
} }
} }
if (!IR::BuildScalarProvenance(&ir, error)) { if (!IR::BuildScalarProvenance(ir, error)) {
return false; return false;
} }
std::string srt_error; 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()); LOGF("%s SRT planning failed: %s\n", GetDumpLabel(options), srt_error.c_str());
if (error != nullptr) { if (error != nullptr) {
*error = std::move(srt_error); *error = std::move(srt_error);
@@ -770,7 +769,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
ir.fallback_reason = dispatcher_reason; 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; return false;
} }
if (options.stage == ShaderType::Vertex) { if (options.stage == ShaderType::Vertex) {
@@ -810,11 +809,11 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
: nullptr; : nullptr;
runtime.userdata = options.read_memory_data; runtime.userdata = options.read_memory_data;
runtime.flat_memory_base = options.flat_memory_base; runtime.flat_memory_base = options.flat_memory_base;
if (!IR::MaterializeResources(ir, runtime, &resources, error)) { if (!IR::MaterializeResources(ir, runtime, resources, error)) {
return false; return false;
} }
} }
if (!IR::SpecializeResources(&ir, resources, error)) { if (!IR::SpecializeResources(ir, resources, error)) {
return false; return false;
} }
@@ -828,13 +827,13 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
options.pixel_input_info != nullptr ? options.pixel_input_info : &default_pixel; options.pixel_input_info != nullptr ? options.pixel_input_info : &default_pixel;
info_options.compute = info_options.compute =
options.compute_input_info != nullptr ? options.compute_input_info : &default_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; return false;
} }
IR::BindingLayoutOptions layout_options; IR::BindingLayoutOptions layout_options;
layout_options.descriptor_set = options.descriptor_set; layout_options.descriptor_set = options.descriptor_set;
layout_options.push_constant_offset = options.push_constant_offset; 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; return false;
} }
std::string ir_dump; std::string ir_dump;
@@ -850,7 +849,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " SPIR-V EmitProgram\n", LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " SPIR-V EmitProgram\n",
GetDumpLabel(options), StageName(options.stage), options.shader_hash); GetDumpLabel(options), StageName(options.stage), options.shader_hash);
if (!Spirv::EmitProgram(ir, resources, options.vertex_input_info, options.pixel_input_info, 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) { if (dispatcher_fallback && error != nullptr) {
*error = fmt::format("dispatcher fallback failed after {}: {}", *error = fmt::format("dispatcher fallback failed after {}: {}",
dispatcher_reason.c_str(), emit_error.c_str()); dispatcher_reason.c_str(), emit_error.c_str());
@@ -868,15 +867,15 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
LOGF("%s dispatcher fallback used: %s\n", GetDumpLabel(options), dispatcher_reason.c_str()); LOGF("%s dispatcher fallback used: %s\n", GetDumpLabel(options), dispatcher_reason.c_str());
} }
result->spirv = std::move(spirv); result.spirv = std::move(spirv);
result->program = std::move(ir); result.program = std::move(ir);
result->resources = std::move(resources); result.resources = std::move(resources);
if (options.dump_ir) { if (options.dump_ir) {
result->decoded_dump = std::move(decoded_dump); result.decoded_dump = std::move(decoded_dump);
result->ir_dump = std::move(ir_dump); result.ir_dump = std::move(ir_dump);
} else { } else {
result->decoded_dump.clear(); result.decoded_dump.clear();
result->ir_dump.clear(); result.ir_dump.clear();
} }
return true; return true;
} }
@@ -44,7 +44,7 @@ struct CompileResult {
}; };
bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options, bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
CompileResult* result, std::string* error); CompileResult& result, std::string* error);
} // namespace Libs::Graphics::ShaderRecompiler } // namespace Libs::Graphics::ShaderRecompiler
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff. Show more