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:
static constexpr int BuffersNum = 8;
CommandScheduler(HW::Context& registers, HW::UserConfig& user_config, HW::Shader& shaders)
: m_registers(registers), m_user_config(user_config), m_shaders(shaders) {}
void SetQueue(int queue) { m_queue = queue; }
int Queue() const { return m_queue; }
bool Active() const { return m_current >= 0 && m_current < BuffersNum; }
void CheckActive() const { EXIT_IF(!Active()); }
CommandBuffer* Current() const {
RenderCommandBuffer& Current() const {
CheckActive();
EXIT_IF(m_buffers[m_current] == nullptr);
return m_buffers[m_current];
return *m_buffers[m_current];
}
void Init() {
@@ -37,10 +40,10 @@ public:
}
for (auto& buf: m_buffers) {
EXIT_IF(buf != nullptr);
buf = new CommandBuffer(m_queue);
buf = new RenderCommandBuffer(m_queue, m_registers, m_user_config, m_shaders);
}
m_current = 0;
Current()->Begin();
Current().Begin();
}
void Flush() {
@@ -48,18 +51,17 @@ public:
BeginNext();
}
CommandBuffer* FlushAndGetSubmitted() {
auto* submitted = SubmitCurrent();
CommandBuffer& FlushAndGetSubmitted() {
auto& submitted = SubmitCurrent();
BeginNext();
return submitted;
}
void CopyBuffers(std::array<CommandBuffer*, BuffersNum>* out) const {
EXIT_IF(out == nullptr);
void CopyBuffers(std::array<CommandBuffer*, BuffersNum>& out) const {
for (int i = 0; i < BuffersNum; i++) {
auto* buf = m_buffers[i];
EXIT_IF(buf == nullptr);
(*out)[i] = buf;
out[i] = buf;
}
}
@@ -81,27 +83,30 @@ public:
if (!Active()) {
return;
}
Current()->WaitForFenceAndReset();
Current()->Begin();
Current().WaitForFenceAndReset();
Current().Begin();
}
private:
CommandBuffer* SubmitCurrent() {
auto* submitted = Current();
submitted->End();
submitted->Execute();
CommandBuffer& SubmitCurrent() {
auto& submitted = Current();
submitted.End();
submitted.Execute();
return submitted;
}
void BeginNext() {
m_current = (m_current + 1) % BuffersNum;
Current()->WaitForFenceAndReset();
Current()->Begin();
Current().WaitForFenceAndReset();
Current().Begin();
}
CommandBuffer* m_buffers[BuffersNum] = {};
RenderCommandBuffer* m_buffers[BuffersNum] = {};
int m_current = -1;
int m_queue = -1;
HW::Context& m_registers;
HW::UserConfig& m_user_config;
HW::Shader& m_shaders;
};
class CommandProcessor {
@@ -113,7 +118,7 @@ public:
int64_t flip_arg = 0;
};
CommandProcessor() = default;
CommandProcessor(): m_scheduler(m_ctx, m_ucfg, m_sh_ctx) {}
~CommandProcessor() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(CommandProcessor);
@@ -145,9 +150,9 @@ public:
void RunLock() { m_run_mutex.Lock(); }
void RunUnlock() { m_run_mutex.Unlock(); }
HW::Context* GetCtx() { return &m_ctx; }
HW::UserConfig* GetUcfg() { return &m_ucfg; }
HW::Shader* GetShCtx() { return &m_sh_ctx; }
HW::Context& GetCtx() { return m_ctx; }
HW::UserConfig& GetUcfg() { return m_ucfg; }
HW::Shader& GetShCtx() { return m_sh_ctx; }
void SetIndexType(uint32_t index_type_and_size);
void SetIndexBaseAddress(uint64_t index_base_addr);
@@ -244,12 +249,9 @@ private:
uint32_t interrupt_context_id);
void FinishCommandProcessors();
CommandBuffer* CurrentBuffer() { return m_scheduler.Current(); }
RenderCommandBuffer& CurrentBuffer() { return m_scheduler.Current(); }
void CheckBuffer() const { m_scheduler.CheckActive(); }
GpuResourceManager* GetGpuResources() const {
EXIT_IF(g_render_ctx == nullptr);
return g_render_ctx->GetGpuResources();
}
GpuResourceManager& GetGpuResources() const { return GetRenderContext().GetGpuResources(); }
HW::Context m_ctx;
HW::UserConfig m_ucfg;
@@ -10,17 +10,17 @@ namespace Libs::Graphics {
class CommandProcessor;
using hw_ctx_parser_func_t = uint32_t (*)(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
using hw_ctx_parser_func_t = uint32_t (*)(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
using hw_uc_parser_func_t = uint32_t (*)(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
using hw_uc_parser_func_t = uint32_t (*)(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
using hw_sh_parser_func_t = uint32_t (*)(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
using hw_sh_parser_func_t = uint32_t (*)(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
using cp_op_parser_func_t = uint32_t (*)(CommandProcessor*, uint32_t, const uint32_t*, uint32_t,
using cp_op_parser_func_t = uint32_t (*)(CommandProcessor&, uint32_t, const uint32_t*, uint32_t,
uint32_t);
using hw_ctx_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t);
using hw_uc_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t);
using hw_sh_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t);
using hw_ctx_indirect_func_t = void (*)(CommandProcessor&, uint32_t, uint32_t);
using hw_uc_indirect_func_t = void (*)(CommandProcessor&, uint32_t, uint32_t);
using hw_sh_indirect_func_t = void (*)(CommandProcessor&, uint32_t, uint32_t);
extern const std::array<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];
@@ -36,136 +36,136 @@ void GraphicsInitJmpTablesCxIndirect();
void GraphicsInitJmpTablesShIndirect();
void GraphicsInitJmpTablesUcIndirect();
uint32_t HwCtxSetRenderControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthMetadataRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetRenderControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthMetadataRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetBorderColorTableAddr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetBorderColorTableAddr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetStencilClear(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthClear(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetScreenScissor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthRenderTarget(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetStencilClear(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthClear(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetScreenScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthRenderTarget(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetStencilInfo(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthHtileSurface(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetStencilInfo(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthHtileSurface(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetHardwareScreenOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetHardwareScreenOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetWindowOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetWindowScissor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetClipRect(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetRenderTargetMask(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetGenericScissor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetBlendColor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetCbDccControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetStencilControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetStencilMask(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPsInput(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetSpiTmpringSize(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetEqaaControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetColorControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthBounds(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPointState(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetClipControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetModeControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPolyOffsetRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetWindowOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetWindowScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetClipRect(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetRenderTargetMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetGenericScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetBlendColor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetCbDccControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetStencilControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetStencilMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPsInput(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetSpiTmpringSize(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetEqaaControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetColorControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDepthBounds(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPointState(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetClipControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetModeControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPolyOffsetRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetViewportTransformControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetViewportTransformControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetLineControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetFovWindow(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetScanModeControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetScanModeControl1(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetAaConfig(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetAaSampleControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetCentroidPriority(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetAaMask(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetVtxControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPaScExtendedControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetLineControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetFovWindow(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetScanModeControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetScanModeControl1(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetAaConfig(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetAaSampleControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetCentroidPriority(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetAaMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetVtxControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetPaScExtendedControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetAlphaToMask(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDrawPayloadControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetAlphaToMask(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetDrawPayloadControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwCtxSetPrimitiveIdReset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetObjprimIdControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetShaderStages(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetGuardBands(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetRenderTarget(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetColorInfo(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetBlendControl(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetViewportScissor(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetViewportZ(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetViewportScaleOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwCtxSetPrimitiveIdReset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetObjprimIdControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetShaderStages(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetGuardBands(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetRenderTarget(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetColorInfo(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetBlendControl(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetViewportScissor(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetViewportZ(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwCtxSetViewportScaleOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwShSetPsUserSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetGsUserSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetHsUserSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetCsUserSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetPsUserAccumSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetGsUserAccumSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetHsUserAccumSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetCsUserAccumSgpr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetCsRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShIgnoreRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetPrimitiveType(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetIndexType(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetObjectId(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetTextureGradientFactors(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwShSetPsUserSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetGsUserSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetHsUserSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetCsUserSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetPsUserAccumSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetGsUserAccumSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetHsUserAccumSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetCsUserAccumSgpr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShSetCsRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwShIgnoreRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetPrimitiveType(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetIndexType(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetObjectId(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetTextureGradientFactors(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwUcSetIaMultiVgtParam(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetMultiPrimIbReset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetBorderColorTableAddr(CommandProcessor*, uint32_t, uint32_t, const uint32_t*,
uint32_t HwUcSetIaMultiVgtParam(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetMultiPrimIbReset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetBorderColorTableAddr(CommandProcessor&, uint32_t, uint32_t, const uint32_t*,
uint32_t);
uint32_t HwUcSetGeIndexOffset(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetGdsOaRegisters(CommandProcessor*, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetGeIndexOffset(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t HwUcSetGdsOaRegisters(CommandProcessor&, uint32_t, uint32_t, const uint32_t*, uint32_t);
uint32_t CpOpNop(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetBase(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpClearState(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndexBase(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndexBufferSize(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDispatchDirect(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDispatchIndirect(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndirect(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndirectMulti(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndex(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndexOffset(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpPfpSyncMe(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndexType(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpNumInstances(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndexAuto(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpCondExec(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetPredication(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWriteData(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndirectBuffer(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpCopyData(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpEventWrite(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpEventWriteEop(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpEventWriteEos(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDmaData(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpAcquireMem(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetContextReg(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetShaderReg(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetUconfigReg(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndirectCxRegs(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndirectShRegs(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndirectUcRegs(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWriteConstRam(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDumpConstRam(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIncrementCeCounter(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIncrementDeCounter(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitOnCeCounter(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitOnDeCounterDiff(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpGetLodStats(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDispatchReset(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitRegMem32(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitFlipDone(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpPushMarker(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpPopMarker(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitRegMem64(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpFlip(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpReleaseMem(CommandProcessor*, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpNop(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetBase(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpClearState(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndexBase(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndexBufferSize(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDispatchDirect(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDispatchIndirect(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndirect(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndirectMulti(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndex(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndexOffset(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpPfpSyncMe(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndexType(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpNumInstances(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDrawIndexAuto(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpCondExec(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetPredication(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWriteData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndirectBuffer(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpCopyData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpEventWrite(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpEventWriteEop(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpEventWriteEos(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDmaData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpAcquireMem(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetContextReg(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetShaderReg(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpSetUconfigReg(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndirectCxRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndirectShRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIndirectUcRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWriteConstRam(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDumpConstRam(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIncrementCeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpIncrementDeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitOnCeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitOnDeCounterDiff(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpGetLodStats(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpDispatchReset(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitRegMem32(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitFlipDone(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpPushMarker(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpPopMarker(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpWaitRegMem64(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpFlip(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
uint32_t CpOpReleaseMem(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
} // namespace Libs::Graphics
File diff suppressed because it is too large. Load diff
+30 -33
View File
@@ -122,8 +122,8 @@ public:
void WaitForIdle();
bool IsIdle();
void SetCp(CommandProcessor* cp) {
m_cp = cp;
void SetCp(CommandProcessor& cp) {
m_cp = &cp;
Start();
}
@@ -171,8 +171,8 @@ public:
void WaitForIdle();
bool IsIdle();
void SetCp(CommandProcessor* cp) {
m_cp = cp;
void SetCp(CommandProcessor& cp) {
m_cp = &cp;
Start();
}
@@ -382,7 +382,7 @@ void Gpu::Init() {
m_gfx_cp = new CommandProcessor;
m_gfx_ring = new GraphicsRing;
m_gfx_cp->SetQueue(GraphicContext::QUEUE_GFX);
m_gfx_ring->SetCp(m_gfx_cp);
m_gfx_ring->SetCp(*m_gfx_cp);
EXIT_IF(GraphicContext::QUEUE_COMPUTE_NUM < 8);
}
@@ -400,7 +400,7 @@ ComputeRing* Gpu::GetRing(uint32_t ring_id) {
if (m_compute_ring[v] == nullptr) {
m_compute_ring[v] = new ComputeRing;
m_compute_ring[v]->SetQueueId(queue_id);
m_compute_ring[v]->SetCp(m_compute_cp[pipe_id]);
m_compute_ring[v]->SetCp(*m_compute_cp[pipe_id]);
}
return m_compute_ring[v];
@@ -475,14 +475,12 @@ void CommandProcessor::BufferFlush() {
}
void CommandProcessor::BufferFlushAndWait() {
CommandBuffer* submitted = nullptr;
{
auto& submitted = [&]() -> CommandBuffer& {
Common::LockGuard lock(m_mutex);
submitted = m_scheduler.FlushAndGetSubmitted();
}
return m_scheduler.FlushAndGetSubmitted();
}();
submitted->WaitForFence();
submitted.WaitForFence();
}
void CommandProcessor::BufferWait() {
@@ -493,7 +491,7 @@ void CommandProcessor::BufferWait() {
std::array<CommandBuffer*, CommandScheduler::BuffersNum> buffers {};
{
Common::LockGuard lock(m_mutex);
m_scheduler.CopyBuffers(&buffers);
m_scheduler.CopyBuffers(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);
}
if (src_sel == 2) {
GetGpuResources()->FillBuffer(
GetGpuResources().FillBuffer(
CurrentBuffer(), dst_address_or_offset, num_bytes,
static_cast<uint32_t>(src_address_or_offset_or_immediate & 0xffffffffu));
return;
}
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);
return;
}
@@ -960,11 +958,11 @@ void CommandProcessor::Run(uint32_t* data, uint32_t num_dw) {
KYTY_PROFILER_BLOCK("CommandProcessor::Run");
struct RunScope {
explicit RunScope(CommandProcessor* cp): prev(g_current_run_cp) { g_current_run_cp = cp; }
explicit RunScope(CommandProcessor& cp): prev(g_current_run_cp) { g_current_run_cp = &cp; }
~RunScope() { g_current_run_cp = prev; }
CommandProcessor* prev;
} run_scope(this);
} run_scope(*this);
auto* cmd = data;
auto dw = num_dw;
@@ -1033,7 +1031,7 @@ void CommandProcessor::Run(uint32_t* data, uint32_t num_dw) {
EXIT("unknown op\n\t%05" PRIx32 ":\n\tcmd_id = %08" PRIx32 "\n", num_dw - dw, cmd_id);
}
auto s = pfunc(this, cmd_id & ~1u, cmd, dw, num_dw);
auto s = pfunc(*this, cmd_id & ~1u, cmd, dw, num_dw);
// LOGF("\t %05" PRIx32 ": %u\n", num_dw - dw, s);
@@ -1142,9 +1140,9 @@ void CommandProcessor::DrawIndex(uint32_t index_count, const void* index_addr, u
"\n",
vertex_offset_add, first_instance);
}
RenderDrawIndex(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, m_index_type_and_size,
index_count, index_addr, flags, type, instance_count,
render_target_slice_offset, vertex_offset_add, first_instance);
RenderDrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr,
flags, type, instance_count, render_target_slice_offset, vertex_offset_add,
first_instance);
}
void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_count,
@@ -1164,8 +1162,8 @@ void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_cou
auto* index_addr = reinterpret_cast<const void*>(
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,
index_count, index_addr, flags, 1, m_num_instances);
RenderDrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr,
flags, 1, m_num_instances);
}
void CommandProcessor::DrawIndirect(uint32_t data_offset, uint32_t draw_initiator, bool indexed) {
@@ -1393,8 +1391,8 @@ void CommandProcessor::DispatchDirect(uint32_t thread_group_x, uint32_t thread_g
}
}
RenderDispatchDirect(m_submit_id, CurrentBuffer(), &m_ctx, &m_sh_ctx, thread_group_x,
thread_group_y, thread_group_z, mode);
RenderDispatchDirect(m_submit_id, CurrentBuffer(), thread_group_x, thread_group_y,
thread_group_z, mode);
}
constexpr uint32_t DispatchInitiatorUseThreadDimensions = 1u << 5u;
@@ -1442,9 +1440,8 @@ void CommandProcessor::DrawIndexAuto(uint32_t index_count, uint32_t flags,
CheckBuffer();
RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, index_count,
flags, render_target_slice_offset, instance_count, first_vertex,
first_instance);
RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), index_count, flags,
render_target_slice_offset, instance_count, first_vertex, first_instance);
}
void CommandProcessor::WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index) {
@@ -1778,7 +1775,7 @@ void CommandProcessor::Flip() {
LOGF("CommandProcessor::Flip()\n");
}
auto* command = CurrentBuffer();
auto& command = CurrentBuffer();
auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg);
Sync::WriteAtEndOfPipeOnlyFlip(m_submit_id, command, m_flip.handle, m_flip.index,
@@ -1799,7 +1796,7 @@ void CommandProcessor::Flip(void* dst_gpu_addr, uint32_t value) {
}
std::memcpy(dst_gpu_addr, &value, sizeof(value));
auto* command = CurrentBuffer();
auto& command = CurrentBuffer();
auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg);
Sync::WriteAtEndOfPipeWithFlip32(m_submit_id, command, static_cast<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");
}
std::memcpy(dst_gpu_addr, &value, sizeof(value));
auto* command = CurrentBuffer();
auto& command = CurrentBuffer();
auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg);
Sync::WriteAtEndOfPipeWithInterruptWriteBackFlip32(
@@ -1843,10 +1840,10 @@ void CommandProcessor::PrepareCpuFlip() {
EXIT("invalid graphics-thread CPU flip preparation\n");
}
struct RunScope {
explicit RunScope(CommandProcessor* cp) { g_current_run_cp = cp; }
explicit RunScope(CommandProcessor& cp) { g_current_run_cp = &cp; }
~RunScope() { g_current_run_cp = nullptr; }
};
RunScope run_scope(this);
RunScope run_scope(*this);
auto prepared_id = Presentation::DisplayBufferPrepareNextFlipOnGpu(CurrentBuffer());
m_scheduler.Flush();
+93 -95
View File
@@ -404,33 +404,33 @@ struct TextureBlockLayout {
uint32_t block_size;
};
static bool GetTextureBlockLayout(uint32_t format, uint32_t tile, TextureBlockLayout* out) {
static bool GetTextureBlockLayout(uint32_t format, uint32_t tile, TextureBlockLayout& out) {
uint32_t width_log2 = 0, height_log2 = 0;
if (tile == 1 && Gen5Standard256BLayout(format, &out->bytes, &out->texel_width,
&out->texel_height, &width_log2, &height_log2)) {
out->block_size = 256;
} else if (tile == 5 && Gen5Standard4KBLayout(format, &out->bytes, &out->texel_width,
&out->texel_height, &width_log2, &height_log2)) {
out->block_size = 4096;
if (tile == 1 && Gen5Standard256BLayout(format, &out.bytes, &out.texel_width,
&out.texel_height, &width_log2, &height_log2)) {
out.block_size = 256;
} else if (tile == 5 && Gen5Standard4KBLayout(format, &out.bytes, &out.texel_width,
&out.texel_height, &width_log2, &height_log2)) {
out.block_size = 4096;
} else if ((tile == 9 || tile == 17) &&
Gen5Standard64KBLayout(format, &out->bytes, &out->texel_width, &out->texel_height,
Gen5Standard64KBLayout(format, &out.bytes, &out.texel_width, &out.texel_height,
&width_log2, &height_log2)) {
out->block_size = 65536;
out.block_size = 65536;
} else if (tile == 24 || tile == 27) {
out->bytes = Prospero::NumBytesPerElement(format);
out->texel_width = out->texel_height = 1;
if (out->bytes == 0 || (tile == 24 && out->bytes > 8) ||
!Gen5Thin64KBBlockSizeFromElementBytes(out->bytes, &out->block_width,
&out->block_height)) {
out.bytes = Prospero::NumBytesPerElement(format);
out.texel_width = out.texel_height = 1;
if (out.bytes == 0 || (tile == 24 && out.bytes > 8) ||
!Gen5Thin64KBBlockSizeFromElementBytes(out.bytes, &out.block_width,
&out.block_height)) {
return false;
}
out->block_size = 65536;
out.block_size = 65536;
return true;
} else {
return false;
}
out->block_width = 1u << width_log2;
out->block_height = 1u << height_log2;
out.block_width = 1u << width_log2;
out.block_height = 1u << height_log2;
return true;
}
@@ -524,12 +524,12 @@ static void SetMacroMipLayout(const TextureBlockLayout& block, uint32_t tile, ui
}
bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height, uint32_t depth,
uint32_t levels, uint32_t tile, TileVolumeLayout* out) {
if (out == nullptr || width == 0 || height == 0 || depth == 0 || levels == 0 || levels > 16) {
uint32_t levels, uint32_t tile, TileVolumeLayout& out) {
if (width == 0 || height == 0 || depth == 0 || levels == 0 || levels > 16) {
return false;
}
TextureBlockLayout element {};
if (!GetTextureBlockLayout(format, tile, &element)) return false;
if (!GetTextureBlockLayout(format, tile, element)) return false;
TileBlockFamily family = TileBlockFamily::Count;
switch (tile) {
@@ -541,15 +541,15 @@ bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height
default: return false;
}
TileBlockLayout block {};
if (!TileGetBlockLayout(family, element.bytes, &block)) return false;
if (!TileGetBlockLayout(family, element.bytes, block)) return false;
*out = {};
out->family = family;
out->bytes_per_element = element.bytes;
out->texel_width = element.texel_width;
out->texel_height = element.texel_height;
out->block_depth = block.block_depth;
out->first_tail_level = levels;
out = {};
out.family = family;
out.bytes_per_element = element.bytes;
out.texel_width = element.texel_width;
out.texel_height = element.texel_height;
out.block_depth = block.block_depth;
out.first_tail_level = levels;
const uint32_t width0 = (width + element.texel_width - 1u) / element.texel_width;
const uint32_t height0 = (height + element.texel_height - 1u) / element.texel_height;
const bool thick4 = family == TileBlockFamily::Standard4KB3D;
@@ -568,37 +568,37 @@ bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height
const uint32_t mip_height = std::max(ShiftCeil(height0, level), 1u);
if (levels > 1 && mip_width <= tail_width && mip_height <= tail_height &&
levels - level <= max_tail) {
out->first_tail_level = level;
out->block_slice_size += block.block_size;
out.first_tail_level = level;
out.block_slice_size += block.block_size;
break;
}
out->level_widths[level] = AlignUp(mip_width, block.block_width);
out->level_heights[level] = AlignUp(mip_height, block.block_height);
out->level_sizes[level] = static_cast<uint64_t>(block.block_depth) *
out->level_widths[level] * out->level_heights[level] *
out.level_widths[level] = AlignUp(mip_width, block.block_width);
out.level_heights[level] = AlignUp(mip_height, block.block_height);
out.level_sizes[level] = static_cast<uint64_t>(block.block_depth) *
out.level_widths[level] * out.level_heights[level] *
element.bytes;
out->block_slice_size += out->level_sizes[level];
out.block_slice_size += out.level_sizes[level];
}
const auto bytes_log2 = std::countr_zero(element.bytes);
for (uint32_t level = out->first_tail_level; level < levels; ++level) {
const auto index = level - out->first_tail_level;
for (uint32_t level = out.first_tail_level; level < levels; ++level) {
const auto index = level - out.first_tail_level;
const auto tail = thick4 ? GEN5_MIP_TAIL_LOCATIONS_THICK_4KB[bytes_log2][index]
: (thick64 ? GEN5_MIP_TAIL_LOCATIONS_THICK_64KB[bytes_log2][index]
: GEN5_MIP_TAIL_LOCATIONS_THIN_64KB[bytes_log2][index]);
out->level_sizes[level] = block.block_size;
out->level_widths[level] = block.block_width;
out->level_heights[level] = block.block_height;
out->tail_x[level] = tail.x;
out->tail_y[level] = tail.y;
out.level_sizes[level] = block.block_size;
out.level_widths[level] = block.block_width;
out.level_heights[level] = block.block_height;
out.tail_x[level] = tail.x;
out.tail_y[level] = tail.y;
}
uint64_t offset = out->first_tail_level < levels ? block.block_size : 0;
for (int32_t l = static_cast<int32_t>(out->first_tail_level) - 1; l >= 0; --l) {
out->level_offsets[l] = offset;
offset += out->level_sizes[l];
uint64_t offset = out.first_tail_level < levels ? block.block_size : 0;
for (int32_t l = static_cast<int32_t>(out.first_tail_level) - 1; l >= 0; --l) {
out.level_offsets[l] = offset;
offset += out.level_sizes[l];
}
out->total_size = out->block_slice_size * ShiftCeil(depth, std::countr_zero(block.block_depth));
return offset == out->block_slice_size;
out.total_size = out.block_slice_size * ShiftCeil(depth, std::countr_zero(block.block_depth));
return offset == out.block_slice_size;
}
static uint32_t Gen5Standard4KBOffsetInBlock(uint32_t x, uint32_t y, uint32_t bytes_per_element) {
@@ -1047,8 +1047,8 @@ static constexpr uint32_t Depth64KB64XOffsetBytes(uint32_t x);
static constexpr uint32_t Depth64KB64YOffsetBytes(uint32_t y);
bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element,
TileBlockLayout* layout) {
if (layout == nullptr || !std::has_single_bit(bytes_per_element) || bytes_per_element > 16) {
TileBlockLayout& layout) {
if (!std::has_single_bit(bytes_per_element) || bytes_per_element > 16) {
return false;
}
@@ -1121,15 +1121,14 @@ bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element,
result.block_size) {
return false;
}
*layout = result;
layout = result;
return true;
}
bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, uint32_t z,
uint32_t* byte_offset) {
uint32_t& byte_offset) {
TileBlockLayout expected {};
if (byte_offset == nullptr ||
!TileGetBlockLayout(layout.family, layout.bytes_per_element, &expected) ||
if (!TileGetBlockLayout(layout.family, layout.bytes_per_element, expected) ||
layout.block_size != expected.block_size || layout.block_width != expected.block_width ||
layout.block_height != expected.block_height ||
layout.block_depth != expected.block_depth || x >= layout.block_width ||
@@ -1222,20 +1221,19 @@ bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, u
if (offset >= layout.block_size || offset % layout.bytes_per_element != 0) {
return false;
}
*byte_offset = offset;
byte_offset = offset;
return true;
}
bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y,
uint32_t* byte_offset) {
uint32_t& byte_offset) {
return TileGetBlockXor(layout, block_x, block_y, 0, byte_offset);
}
bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y,
uint32_t block_z, uint32_t* byte_offset) {
uint32_t block_z, uint32_t& byte_offset) {
TileBlockLayout expected {};
if (byte_offset == nullptr ||
!TileGetBlockLayout(layout.family, layout.bytes_per_element, &expected) ||
if (!TileGetBlockLayout(layout.family, layout.bytes_per_element, expected) ||
layout.block_size != expected.block_size || layout.block_width != expected.block_width ||
layout.block_height != expected.block_height ||
layout.block_depth != expected.block_depth) {
@@ -1246,7 +1244,7 @@ bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t b
block_y > UINT32_MAX / layout.block_height) {
return false;
}
*byte_offset = Depth64KB64XOffsetBytes(block_x * layout.block_width) ^
byte_offset = Depth64KB64XOffsetBytes(block_x * layout.block_width) ^
Depth64KB64YOffsetBytes(block_y * layout.block_height);
} else if (layout.family == TileBlockFamily::RenderTarget64KB) {
if (block_x > UINT32_MAX / layout.block_width ||
@@ -1256,22 +1254,22 @@ bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t b
const auto x = block_x * layout.block_width;
const auto y = block_y * layout.block_height;
switch (layout.bytes_per_element) {
case 1: *byte_offset = Gen5RenderTargetOffsetInBlock<uint8_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 8: *byte_offset = Gen5RenderTargetOffsetInBlock<uint64_t>(x, y); break;
case 16: *byte_offset = Gen5RenderTargetOffsetInBlock<Uint128>(x, y); break;
case 1: byte_offset = Gen5RenderTargetOffsetInBlock<uint8_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 8: byte_offset = Gen5RenderTargetOffsetInBlock<uint64_t>(x, y); break;
case 16: byte_offset = Gen5RenderTargetOffsetInBlock<Uint128>(x, y); break;
default: return false;
}
} else {
*byte_offset = 0;
byte_offset = 0;
}
if (layout.family == TileBlockFamily::RenderTarget64KB ||
layout.family == TileBlockFamily::Depth64KB) {
*byte_offset ^= ((block_z & 8u) << 5u) ^ ((block_z & 4u) << 7u) ^ ((block_z & 2u) << 9u) ^
byte_offset ^= ((block_z & 8u) << 5u) ^ ((block_z & 4u) << 7u) ^ ((block_z & 2u) << 9u) ^
((block_z & 1u) << 11u);
}
return *byte_offset < layout.block_size && *byte_offset % layout.bytes_per_element == 0;
return byte_offset < layout.block_size && byte_offset % layout.bytes_per_element == 0;
}
static constexpr uint32_t Depth64KB8XOffsetBytes(uint32_t x) {
@@ -1362,8 +1360,8 @@ static_assert(Depth64KB32XOffsetBytes(2) == 0x0010u);
static_assert(Depth64KB32YOffsetBytes(1) == 0x0008u);
static_assert((Depth64KB32XOffsetBytes(3) ^ Depth64KB32YOffsetBytes(5)) == 0x009cu);
bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign* htile_size) {
*htile_size = {};
bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& htile_size) {
htile_size = {};
if (width == 0 || width > 16384 || height == 0 || height > 16384) {
return false;
}
@@ -1374,13 +1372,13 @@ bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign* htile_size
if (size == 0 || size > UINT32_MAX) {
return false;
}
*htile_size = {static_cast<uint32_t>(size), 32768};
htile_size = {static_cast<uint32_t>(size), 32768};
return true;
}
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format,
uint32_t stencil_format, bool htile, TileSizeAlign* stencil_size,
TileSizeAlign* htile_size, TileSizeAlign* depth_size,
uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size,
TileSizeAlign& htile_size, TileSizeAlign& depth_size,
uint32_t num_fragments_log2) {
EXIT_IF(pitch != 0);
// Prospero derives uncompressed depth/stencil as independent 64 KiB block surfaces.
@@ -1408,19 +1406,19 @@ bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t
AlignUp(height, stencil_block_height) * fragments
: 0;
TileSizeAlign calculated_htile {};
const bool htile_valid = !htile || TileGetHtileSize(width, height, &calculated_htile);
const bool htile_valid = !htile || TileGetHtileSize(width, height, calculated_htile);
if (depth_bytes_total <= UINT32_MAX && stencil_bytes_total <= UINT32_MAX && htile_valid) {
*depth_size = {static_cast<uint32_t>(depth_bytes_total), 65536};
*stencil_size = stencil_format == 1
depth_size = {static_cast<uint32_t>(depth_bytes_total), 65536};
stencil_size = stencil_format == 1
? TileSizeAlign {static_cast<uint32_t>(stencil_bytes_total), 65536}
: TileSizeAlign {};
*htile_size = calculated_htile;
htile_size = calculated_htile;
return true;
}
}
*depth_size = TileSizeAlign();
*htile_size = TileSizeAlign();
*stencil_size = TileSizeAlign();
depth_size = TileSizeAlign();
htile_size = TileSizeAlign();
stencil_size = TileSizeAlign();
return false;
}
@@ -1443,9 +1441,9 @@ uint32_t TileGetDepthPitch(uint32_t width, uint32_t bytes_per_element,
}
bool TileGetRenderTargetSize(uint32_t width, uint32_t height, uint32_t pitch,
uint32_t bytes_per_element, TileSizeAlign* total_size,
uint32_t bytes_per_element, TileSizeAlign& total_size,
uint32_t num_fragments_log2) {
*total_size = {};
total_size = {};
uint32_t block_width = 0;
uint32_t block_height = 0;
if (height == 0 || pitch == 0 ||
@@ -1461,16 +1459,16 @@ bool TileGetRenderTargetSize(uint32_t width, uint32_t height, uint32_t pitch,
if (size == 0 || size > UINT32_MAX) {
return false;
}
total_size->size = static_cast<uint32_t>(size);
total_size->align = 65536;
total_size.size = static_cast<uint32_t>(size);
total_size.align = 65536;
return true;
}
bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch,
uint32_t bytes_per_element, uint32_t levels,
TileSizeAlign* total_size, TileSizeOffset* level_sizes,
TileSizeAlign& total_size, TileSizeOffset* level_sizes,
TilePaddedSize* padded_size) {
*total_size = {};
total_size = {};
if (width == 0 || height == 0 || levels == 0 || levels > 16 ||
pitch != TileGetRenderTargetPitch(width, bytes_per_element)) {
return false;
@@ -1494,9 +1492,9 @@ bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitc
default: return false;
}
TileGetTextureSize(format, width, height, pitch, levels,
Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), total_size,
Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), &total_size,
level_sizes, padded_size);
return total_size->size != 0 && total_size->align == 65536;
return total_size.size != 0 && total_size.align == 65536;
}
void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch,
@@ -1529,7 +1527,7 @@ void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32
}
TextureBlockLayout block {};
if (GetTextureBlockLayout(format, tile, &block)) {
if (GetTextureBlockLayout(format, tile, block)) {
if (tile == 1) {
SetMicroMipLayout(block, width, height, levels, total_size, level_sizes, padded_size);
} else {
@@ -1580,24 +1578,24 @@ void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32
void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth,
uint32_t pitch, uint32_t levels, uint32_t tile, bool volume_texture,
TileSizeAlign* total_size) {
TileSizeAlign& total_size) {
EXIT_NOT_IMPLEMENTED(depth == 0);
if (volume_texture) {
TileVolumeLayout volume {};
if (TileGetTextureVolumeLayout(format, width, height, depth, levels, tile, &volume)) {
if (TileGetTextureVolumeLayout(format, width, height, depth, levels, tile, volume)) {
EXIT_NOT_IMPLEMENTED(volume.total_size > UINT32_MAX);
total_size->size = static_cast<uint32_t>(volume.total_size);
total_size->align = tile == 5 ? 4096u : 65536u;
total_size.size = static_cast<uint32_t>(volume.total_size);
total_size.align = tile == 5 ? 4096u : 65536u;
return;
}
}
TileSizeAlign slice_size {};
TileGetTextureSize(format, width, height, pitch, levels, tile, &slice_size, nullptr, nullptr);
*total_size = slice_size;
total_size = slice_size;
const uint64_t total = static_cast<uint64_t>(slice_size.size) * depth;
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) {
+11 -11
View File
@@ -65,41 +65,41 @@ struct TileVolumeLayout {
};
bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element,
TileBlockLayout* layout);
TileBlockLayout& layout);
bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, uint32_t z,
uint32_t* byte_offset);
uint32_t& byte_offset);
bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y,
uint32_t* byte_offset);
uint32_t& byte_offset);
bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y,
uint32_t block_z, uint32_t* byte_offset);
uint32_t block_z, uint32_t& byte_offset);
bool TileIsStandard256BTextureSupported(uint32_t format);
bool TileIsStandard4KBTextureSupported(uint32_t format);
bool TileIsStandard64KBTextureSupported(uint32_t format);
bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height, uint32_t depth,
uint32_t levels, uint32_t tile, TileVolumeLayout* layout);
uint32_t levels, uint32_t tile, TileVolumeLayout& layout);
bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign* htile_size);
bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& htile_size);
bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format,
uint32_t stencil_format, bool htile, TileSizeAlign* stencil_size,
TileSizeAlign* htile_size, TileSizeAlign* depth_size,
uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size,
TileSizeAlign& htile_size, TileSizeAlign& depth_size,
uint32_t num_fragments_log2 = 0);
uint32_t TileGetRenderTargetPitch(uint32_t width, uint32_t bytes_per_element,
uint32_t num_fragments_log2 = 0);
uint32_t TileGetDepthPitch(uint32_t width, uint32_t bytes_per_element,
uint32_t num_fragments_log2 = 0);
bool TileGetRenderTargetSize(uint32_t width, uint32_t height, uint32_t pitch,
uint32_t bytes_per_element, TileSizeAlign* total_size,
uint32_t bytes_per_element, TileSizeAlign& total_size,
uint32_t num_fragments_log2 = 0);
bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch,
uint32_t bytes_per_element, uint32_t levels,
TileSizeAlign* total_size, TileSizeOffset* level_sizes,
TileSizeAlign& total_size, TileSizeOffset* level_sizes,
TilePaddedSize* padded_size);
void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch,
uint32_t levels, uint32_t tile, TileSizeAlign* total_size,
TileSizeOffset* level_sizes, TilePaddedSize* padded_size);
void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth,
uint32_t pitch, uint32_t levels, uint32_t tile, bool volume_texture,
TileSizeAlign* total_size);
TileSizeAlign& total_size);
uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t levels, uint32_t tile);
} // namespace Libs::Graphics
+112 -107
View File
@@ -21,6 +21,7 @@
#include <array>
#include <bit>
#include <cstring>
#include <memory>
#include <vector>
namespace Libs::Graphics {
@@ -86,17 +87,17 @@ struct Resources {
void* mapped = nullptr;
};
bool CheckedAdd(uint64_t a, uint64_t b, uint64_t* result) {
return b <= UINT64_MAX - a && (*result = a + b, true);
bool CheckedAdd(uint64_t a, uint64_t b, uint64_t& result) {
return b <= UINT64_MAX - a && (result = a + b, true);
}
bool CheckedMultiply(uint64_t a, uint64_t b, uint64_t* result) {
return (a == 0 || b <= UINT64_MAX / a) && (*result = a * b, true);
bool CheckedMultiply(uint64_t a, uint64_t b, uint64_t& result) {
return (a == 0 || b <= UINT64_MAX / a) && (result = a * b, true);
}
bool CheckedAddProduct(uint64_t* value, uint64_t count, uint64_t stride) {
bool CheckedAddProduct(uint64_t& value, uint64_t count, uint64_t stride) {
uint64_t bytes = 0;
return CheckedMultiply(count, stride, &bytes) && CheckedAdd(*value, bytes, value);
return CheckedMultiply(count, stride, bytes) && CheckedAdd(value, bytes, value);
}
bool IsRangeValid(uint64_t offset, uint64_t size, uint64_t capacity) {
@@ -129,53 +130,51 @@ void Barrier(vk::CommandBuffer command, vk::Buffer buffer, vk::AccessFlags src_a
command.pipelineBarrier(src_stage, dst_stage, {}, 0, nullptr, 1, &barrier, 0, nullptr);
}
class Tiler final {
class TileCompute final {
public:
void Run(bool to_tiled, GraphicContext* context, const void* input, void* output,
uint64_t tiled_capacity, uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
explicit TileCompute(GraphicContext& graphics): graphics(graphics) {}
void Run(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
const GpuTileRecord& record);
void Release(GraphicContext* context);
void Release();
private:
void Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
std::vector<Dispatch>* dispatches) const;
void Init(GraphicContext* context);
void Prepare(bool to_tiled, uint64_t tiled_capacity, uint64_t linear_capacity,
std::span<const GpuTileInfo> infos, std::vector<Dispatch>& dispatches) const;
void Init();
void CreatePipelines(std::span<const Dispatch> dispatches);
void CreatePipeline(uint32_t pipeline_slot);
void Resize(uint64_t staging_size, uint64_t linear_size);
void CreateBuffer(uint64_t size, bool mapped, VulkanBuffer* buffer, void** data) const;
void CreateBuffer(uint64_t size, bool mapped, VulkanBuffer& buffer, void** data) const;
void Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const Dispatch> dispatches,
const GpuTileRecord& record);
void Destroy(Resources* target) const;
void Destroy(Resources& target) const;
Common::Mutex mutex;
GraphicContext* ctx = nullptr;
GraphicContext& graphics;
Resources resources;
};
Tiler g_tiler;
Common::Mutex g_tiler_mutex;
std::unique_ptr<TileCompute> g_tiler;
void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
std::vector<Dispatch>* dispatches) const {
EXIT_IF(context == nullptr || g_render_ctx == nullptr ||
g_render_ctx->GetGraphicCtx() != context || infos.empty() || tiled_capacity == 0 ||
linear_capacity == 0);
const auto& limits = context->GetPhysicalDeviceProperties().limits;
void TileCompute::Prepare(bool to_tiled, uint64_t tiled_capacity, uint64_t linear_capacity,
std::span<const GpuTileInfo> infos,
std::vector<Dispatch>& dispatches) const {
EXIT_IF(infos.empty() || tiled_capacity == 0 || linear_capacity == 0);
const auto& limits = graphics.GetPhysicalDeviceProperties().limits;
EXIT_NOT_IMPLEMENTED(tiled_capacity > UINT32_MAX || linear_capacity > UINT32_MAX ||
AlignToDword(tiled_capacity) > limits.maxStorageBufferRange ||
AlignToDword(linear_capacity) > limits.maxStorageBufferRange);
dispatches->clear();
dispatches->reserve(infos.size());
dispatches.clear();
dispatches.reserve(infos.size());
for (const auto& info: infos) {
TileBlockLayout block {};
const uint32_t tiled_width = info.tiled_width != 0 ? info.tiled_width : info.pitch;
const uint32_t tiled_height = info.tiled_height != 0 ? info.tiled_height : info.height;
EXIT_NOT_IMPLEMENTED(
!TileGetBlockLayout(info.family, info.bytes_per_element, &block) || info.width == 0 ||
!TileGetBlockLayout(info.family, info.bytes_per_element, block) || info.width == 0 ||
info.height == 0 || info.depth == 0 || info.pitch < info.width ||
(!info.tail && (tiled_width < info.width || tiled_height < info.height)) ||
!IsRangeValid(info.linear_offset, info.linear_size, linear_capacity) ||
@@ -183,19 +182,19 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac
(block.block_depth == 1 && info.depth != 1));
uint64_t elements = 0, pitch_bytes = 0;
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(info.width, info.height, &elements) ||
!CheckedMultiply(elements, info.depth, &elements) ||
!CheckedMultiply(info.pitch, info.bytes_per_element, &pitch_bytes) ||
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(info.width, info.height, elements) ||
!CheckedMultiply(elements, info.depth, elements) ||
!CheckedMultiply(info.pitch, info.bytes_per_element, pitch_bytes) ||
elements > UINT32_MAX || pitch_bytes > UINT32_MAX);
uint64_t slice_bytes = info.linear_slice_stride;
EXIT_NOT_IMPLEMENTED(slice_bytes == 0 &&
!CheckedMultiply(pitch_bytes, info.height, &slice_bytes));
!CheckedMultiply(pitch_bytes, info.height, slice_bytes));
uint64_t linear_used = 0, minimum_slice = 0;
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(pitch_bytes, info.height, &minimum_slice) ||
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(pitch_bytes, info.height, minimum_slice) ||
(info.depth > 1 && slice_bytes < minimum_slice) ||
!CheckedAddProduct(&linear_used, info.depth - 1u, slice_bytes) ||
!CheckedAddProduct(&linear_used, info.height - 1u, pitch_bytes) ||
!CheckedAddProduct(&linear_used, info.width, info.bytes_per_element) ||
!CheckedAddProduct(linear_used, info.depth - 1u, slice_bytes) ||
!CheckedAddProduct(linear_used, info.height - 1u, pitch_bytes) ||
!CheckedAddProduct(linear_used, info.width, info.bytes_per_element) ||
linear_used > info.linear_size || slice_bytes > UINT32_MAX);
const uint64_t columns =
@@ -203,7 +202,7 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac
const uint64_t rows =
(static_cast<uint64_t>(tiled_height) + block.block_height - 1u) / block.block_height;
uint64_t blocks_per_slice = 0;
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(columns, rows, &blocks_per_slice) ||
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(columns, rows, blocks_per_slice) ||
columns > UINT32_MAX || blocks_per_slice > UINT32_MAX ||
rows * block.block_height > UINT32_MAX);
if (info.tail) {
@@ -217,8 +216,8 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac
const uint64_t slices =
(static_cast<uint64_t>(info.depth) + block.block_depth - 1u) / block.block_depth;
uint64_t tiled_used = 0;
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(blocks_per_slice, slices, &tiled_used) ||
!CheckedMultiply(tiled_used, block.block_size, &tiled_used) ||
EXIT_NOT_IMPLEMENTED(!CheckedMultiply(blocks_per_slice, slices, tiled_used) ||
!CheckedMultiply(tiled_used, block.block_size, tiled_used) ||
tiled_used > info.tiled_size);
}
const uint32_t alignment = std::min(info.bytes_per_element, 4u);
@@ -243,47 +242,42 @@ void Tiler::Prepare(bool to_tiled, GraphicContext* context, uint64_t tiled_capac
dispatch.push.tail_x = info.tail_x;
dispatch.push.tail_y = info.tail_y;
dispatch.push.tail = info.tail;
dispatches->push_back(dispatch);
dispatches.push_back(dispatch);
}
}
void Tiler::Destroy(Resources* target) const {
if (ctx == nullptr) {
return;
void TileCompute::Destroy(Resources& target) const {
if (target.mapped != nullptr) {
graphics.UnmapMemory(target.staging.memory);
}
if (target->mapped != nullptr) {
VulkanUnmapMemory(ctx, &target->staging.memory);
if (target.staging.buffer != nullptr) {
graphics.DeleteBuffer(target.staging);
}
if (target->staging.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &target->staging);
if (target.linear.buffer != nullptr) {
graphics.DeleteBuffer(target.linear);
}
if (target->linear.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &target->linear);
}
for (auto pipeline: target->pipelines) {
for (auto pipeline: target.pipelines) {
if (pipeline != nullptr) {
ctx->device.destroyPipeline(pipeline, nullptr);
graphics.device.destroyPipeline(pipeline, nullptr);
}
}
if (target->descriptor_pool != nullptr) {
ctx->device.destroyDescriptorPool(target->descriptor_pool, nullptr);
if (target.descriptor_pool != nullptr) {
graphics.device.destroyDescriptorPool(target.descriptor_pool, nullptr);
}
if (target->pipeline_layout != nullptr) {
ctx->device.destroyPipelineLayout(target->pipeline_layout, nullptr);
if (target.pipeline_layout != nullptr) {
graphics.device.destroyPipelineLayout(target.pipeline_layout, nullptr);
}
if (target->descriptor_layout != nullptr) {
ctx->device.destroyDescriptorSetLayout(target->descriptor_layout, nullptr);
if (target.descriptor_layout != nullptr) {
graphics.device.destroyDescriptorSetLayout(target.descriptor_layout, nullptr);
}
*target = {};
target = {};
}
void Tiler::Init(GraphicContext* context) {
void TileCompute::Init() {
if (resources.pipeline_layout != nullptr) {
EXIT_IF(ctx != context);
return;
}
EXIT_IF(context == nullptr || context->device == nullptr || context->allocator == nullptr);
ctx = context;
EXIT_IF(graphics.device == nullptr || graphics.allocator == nullptr);
std::array<vk::DescriptorSetLayoutBinding, 2> bindings {};
for (uint32_t i = 0; i < bindings.size(); i++) {
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.bindingCount = static_cast<uint32_t>(bindings.size());
descriptor_info.pBindings = bindings.data();
RequireVulkanSuccess(ctx->device.createDescriptorSetLayout(&descriptor_info, nullptr,
RequireVulkanSuccess(graphics.device.createDescriptorSetLayout(&descriptor_info, nullptr,
&resources.descriptor_layout),
"create GPU tiler descriptor layout");
@@ -305,7 +299,7 @@ void Tiler::Init(GraphicContext* context) {
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = &push_range;
RequireVulkanSuccess(
ctx->device.createPipelineLayout(&layout_info, nullptr, &resources.pipeline_layout),
graphics.device.createPipelineLayout(&layout_info, nullptr, &resources.pipeline_layout),
"create GPU tiler pipeline layout");
vk::DescriptorPoolSize pool_size {vk::DescriptorType::eStorageBuffer, 2};
vk::DescriptorPoolCreateInfo pool_info {};
@@ -314,18 +308,19 @@ void Tiler::Init(GraphicContext* context) {
pool_info.poolSizeCount = 1;
pool_info.pPoolSizes = &pool_size;
RequireVulkanSuccess(
ctx->device.createDescriptorPool(&pool_info, nullptr, &resources.descriptor_pool),
graphics.device.createDescriptorPool(&pool_info, nullptr, &resources.descriptor_pool),
"create GPU tiler descriptor pool");
vk::DescriptorSetAllocateInfo set_info {};
set_info.sType = vk::StructureType::eDescriptorSetAllocateInfo;
set_info.descriptorPool = resources.descriptor_pool;
set_info.descriptorSetCount = 1;
set_info.pSetLayouts = &resources.descriptor_layout;
RequireVulkanSuccess(ctx->device.allocateDescriptorSets(&set_info, &resources.descriptor_set),
RequireVulkanSuccess(
graphics.device.allocateDescriptorSets(&set_info, &resources.descriptor_set),
"allocate GPU tiler descriptor set");
}
void Tiler::CreatePipeline(uint32_t pipeline_slot) {
void TileCompute::CreatePipeline(uint32_t pipeline_slot) {
const uint32_t element_size_index = pipeline_slot % BYTES_PER_ELEMENT_COUNT;
const uint32_t family_direction_index = pipeline_slot / BYTES_PER_ELEMENT_COUNT;
const uint32_t family_index = family_direction_index % FAMILY_COUNT;
@@ -339,7 +334,7 @@ void Tiler::CreatePipeline(uint32_t pipeline_slot) {
module_info.codeSize = SHADERS[family_index].words * sizeof(uint32_t);
module_info.pCode = SHADERS[family_index].code;
vk::ShaderModule module = nullptr;
RequireVulkanSuccess(ctx->device.createShaderModule(&module_info, nullptr, &module),
RequireVulkanSuccess(graphics.device.createShaderModule(&module_info, nullptr, &module),
"create GPU tiler shader module");
vk::PipelineShaderStageCreateInfo stage {};
stage.sType = vk::StructureType::ePipelineShaderStageCreateInfo;
@@ -352,13 +347,14 @@ void Tiler::CreatePipeline(uint32_t pipeline_slot) {
info.stage = stage;
info.layout = resources.pipeline_layout;
vk::Pipeline pipeline = nullptr;
const auto result = ctx->device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline);
ctx->device.destroyShaderModule(module, nullptr);
const auto result =
graphics.device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline);
graphics.device.destroyShaderModule(module, nullptr);
RequireVulkanSuccess(result, "create GPU tiler pipeline");
resources.pipelines[pipeline_slot] = pipeline;
}
void Tiler::CreatePipelines(std::span<const Dispatch> dispatches) {
void TileCompute::CreatePipelines(std::span<const Dispatch> dispatches) {
for (const auto& dispatch: dispatches) {
if (resources.pipelines[dispatch.pipeline_slot] == nullptr) {
CreatePipeline(dispatch.pipeline_slot);
@@ -366,18 +362,19 @@ void Tiler::CreatePipelines(std::span<const Dispatch> dispatches) {
}
}
void Tiler::CreateBuffer(uint64_t size, bool mapped, VulkanBuffer* buffer, void** data) const {
buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
buffer->memory.property =
void TileCompute::CreateBuffer(uint64_t size, bool mapped, VulkanBuffer& buffer,
void** data) const {
buffer.usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferSrc |
vk::BufferUsageFlagBits::eTransferDst;
buffer.memory.property =
mapped
? vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent
: vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eDeviceLocal);
VulkanCreateBuffer(ctx, size, buffer);
if (mapped) VulkanMapMemory(ctx, &buffer->memory, data);
graphics.CreateBuffer(size, buffer);
if (mapped) graphics.MapMemory(buffer.memory, *data);
}
void Tiler::Resize(uint64_t staging_size, uint64_t linear_size) {
void TileCompute::Resize(uint64_t staging_size, uint64_t linear_size) {
if (resources.staging.buffer_size >= staging_size &&
resources.linear.buffer_size >= linear_size) {
return;
@@ -386,17 +383,17 @@ void Tiler::Resize(uint64_t staging_size, uint64_t linear_size) {
linear_size = std::max(linear_size, resources.linear.buffer_size);
VulkanBuffer staging {}, linear {};
void* mapped = nullptr;
CreateBuffer(staging_size, true, &staging, &mapped);
CreateBuffer(linear_size, false, &linear, nullptr);
if (resources.mapped != nullptr) VulkanUnmapMemory(ctx, &resources.staging.memory);
if (resources.staging.buffer != nullptr) VulkanDeleteBuffer(ctx, &resources.staging);
if (resources.linear.buffer != nullptr) VulkanDeleteBuffer(ctx, &resources.linear);
CreateBuffer(staging_size, true, staging, &mapped);
CreateBuffer(linear_size, false, linear, nullptr);
if (resources.mapped != nullptr) graphics.UnmapMemory(resources.staging.memory);
if (resources.staging.buffer != nullptr) graphics.DeleteBuffer(resources.staging);
if (resources.linear.buffer != nullptr) graphics.DeleteBuffer(resources.linear);
resources.staging = staging;
resources.linear = linear;
resources.mapped = mapped;
}
void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
void TileCompute::Execute(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const Dispatch> dispatches,
const GpuTileRecord& record) {
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].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);
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);
}
if (to_tiled && record) {
record(&command, &resources.linear);
record(command, resources.linear);
Barrier(vk_command, resources.linear.buffer,
vk::AccessFlagBits::eTransferWrite | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eShaderRead, vk::PipelineStageFlagBits::eAllCommands,
@@ -463,7 +460,7 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til
&resources.descriptor_set, 0, nullptr);
const uint64_t limit =
static_cast<uint64_t>(
ctx->GetPhysicalDeviceProperties().limits.maxComputeWorkGroupCount[0]) *
graphics.GetPhysicalDeviceProperties().limits.maxComputeWorkGroupCount[0]) *
GROUP_SIZE;
for (const auto& dispatch: dispatches) {
vk_command.bindPipeline(vk::PipelineBindPoint::eCompute,
@@ -484,7 +481,7 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til
vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eHost);
if (!to_tiled && record) {
record(&command, &resources.linear);
record(command, resources.linear);
}
if (!to_tiled && output != nullptr) {
const vk::BufferCopy copy {0, 0, linear_size};
@@ -502,15 +499,14 @@ void Tiler::Execute(bool to_tiled, const void* input, void* output, uint64_t til
}
}
void Tiler::Run(bool to_tiled, GraphicContext* context, const void* input, void* output,
uint64_t tiled_capacity, uint64_t linear_capacity,
std::span<const GpuTileInfo> infos, const GpuTileRecord& record) {
Common::LockGuard lock(mutex);
void TileCompute::Run(bool to_tiled, const void* input, void* output, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
const GpuTileRecord& record) {
EXIT_IF((to_tiled && (output == nullptr || (input == nullptr && !record))) ||
(!to_tiled && (input == nullptr || (output == nullptr && !record))));
std::vector<Dispatch> dispatches;
Prepare(to_tiled, context, tiled_capacity, linear_capacity, infos, &dispatches);
Init(context);
Prepare(to_tiled, tiled_capacity, linear_capacity, infos, dispatches);
Init();
CreatePipelines(dispatches);
const uint64_t staging_size =
std::max(AlignToDword(tiled_capacity), AlignToDword(linear_capacity));
@@ -519,29 +515,38 @@ void Tiler::Run(bool to_tiled, GraphicContext* context, const void* input, void*
Execute(to_tiled, input, output, tiled_capacity, linear_capacity, dispatches, record);
}
void Tiler::Release(GraphicContext* context) {
Common::LockGuard lock(mutex);
EXIT_IF(ctx != nullptr && context != ctx);
Destroy(&resources);
ctx = nullptr;
void TileCompute::Release() {
Destroy(resources);
}
} // namespace
void GpuDetile(GraphicContext* ctx, const void* tiled, void* linear, uint64_t tiled_capacity,
void GpuDetile(const void* tiled, void* linear, uint64_t tiled_capacity,
uint64_t linear_capacity, std::span<const GpuTileInfo> infos,
const GpuTileRecord& after) {
g_tiler.Run(false, ctx, tiled, linear, tiled_capacity, linear_capacity, infos, after);
Common::LockGuard lock(g_tiler_mutex);
if (!g_tiler) {
g_tiler = std::make_unique<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,
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) {
g_tiler.Release(ctx);
void GpuTileRelease() {
Common::LockGuard lock(g_tiler_mutex);
if (g_tiler) {
g_tiler->Release();
g_tiler.reset();
}
}
} // namespace Libs::Graphics
+4 -4
View File
@@ -32,14 +32,14 @@ struct GpuTileInfo {
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,
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,
const GpuTileRecord& before = {});
void GpuTileRelease(GraphicContext* ctx);
void GpuTileRelease();
} // namespace Libs::Graphics
+17
View File
@@ -16,6 +16,9 @@
namespace Libs::Graphics {
class CommandBuffer;
struct VulkanBuffer;
struct VulkanImage;
struct VulkanMemory;
struct VulkanSwapchain {
~VulkanSwapchain();
@@ -43,6 +46,20 @@ struct VulkanCommandPool {
};
struct GraphicContext: public VulkanInstance {
[[nodiscard]] bool CreateAllocator();
void DestroyAllocator();
void LogMemoryBudget() const;
void CreateBuffer(uint64_t size, VulkanBuffer& buffer);
void DeleteBuffer(VulkanBuffer& buffer);
[[nodiscard]] bool CreateImage(const vk::ImageCreateInfo& info, VulkanImage& image);
void DeleteImage(VulkanImage& image);
void MapMemory(VulkanMemory& memory, void*& data);
void UnmapMemory(VulkanMemory& memory);
void AppendHardwareRayTracingDeviceExtensions(
const std::vector<vk::ExtensionProperties>& available_extensions,
std::vector<const char*>& device_extensions);
void LoadHardwareRayTracingFunctions() const;
uint32_t screen_width = 0;
uint32_t screen_height = 0;
std::array<Common::Mutex, QUEUES_NUM> queue_mutexes;
+6 -9
View File
@@ -30,11 +30,8 @@ bool IsAccessible(DWORD protect, HostMemoryAccess access) {
} // namespace
bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAccess access,
uint64_t* accessible_size) {
if (accessible_size == nullptr) {
return false;
}
*accessible_size = 0;
uint64_t& accessible_size) {
accessible_size = 0;
if (addr == 0 || requested_size == 0) {
return false;
}
@@ -87,11 +84,11 @@ bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAcce
(void)access;
#endif
*accessible_size = current - addr;
return *accessible_size != 0;
accessible_size = current - addr;
return accessible_size != 0;
}
bool HostMemoryQueryReadable(uint64_t addr, uint64_t requested_size, uint64_t* readable_size) {
bool HostMemoryQueryReadable(uint64_t addr, uint64_t requested_size, uint64_t& readable_size) {
return HostMemoryQueryRange(addr, requested_size, HostMemoryAccess::Read, readable_size);
}
@@ -104,7 +101,7 @@ bool HostMemoryRangeIsReadable(uint64_t addr, uint64_t size) {
return false;
}
uint64_t readable_size = 0;
return HostMemoryQueryReadable(addr, size, &readable_size) && readable_size >= size;
return HostMemoryQueryReadable(addr, size, readable_size) && readable_size >= size;
}
} // namespace Libs::Graphics
+2 -2
View File
@@ -8,8 +8,8 @@ namespace Libs::Graphics {
enum class HostMemoryAccess { Read, Mapped };
bool HostMemoryQueryRange(uint64_t addr, uint64_t requested_size, HostMemoryAccess access,
uint64_t* accessible_size);
bool HostMemoryQueryReadable(uint64_t addr, uint64_t requested_size, uint64_t* readable_size);
uint64_t& accessible_size);
bool HostMemoryQueryReadable(uint64_t addr, uint64_t requested_size, uint64_t& readable_size);
bool HostMemoryIsReadable(uint64_t addr);
bool HostMemoryRangeIsReadable(uint64_t addr, uint64_t size);
+42 -49
View File
@@ -4,6 +4,7 @@
#include "common/threads.h"
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <algorithm>
@@ -58,17 +59,16 @@ public:
~LabelManager() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(LabelManager);
Label* Create(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2,
const uint64_t* args);
void Delete(Label* label);
void Set(CommandBuffer* buffer, Label* label);
Label* Create(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args);
void Delete(Label& label);
void Set(CommandBuffer& buffer, Label& label);
void Drain();
private:
static void ThreadRun(void* data);
bool Remove(Label* label);
static void Destroy(Label* label);
bool Remove(Label& label);
static void Destroy(Label& label);
Common::Mutex m_mutex;
Common::CondVar m_cond_var;
@@ -146,7 +146,7 @@ void LabelManager::ThreadRun(void* data) {
manager->m_callbacks_in_flight += fired_labels.size();
for (auto& label: deleted_labels) {
bool removed = manager->Remove(label);
bool removed = manager->Remove(*label);
EXIT_NOT_IMPLEMENTED(!removed);
}
@@ -158,7 +158,7 @@ void LabelManager::ThreadRun(void* data) {
(void)finished_submissions;
for (auto& label: deleted_labels) {
Destroy(label);
Destroy(*label);
}
for (auto& label: fired_labels) {
@@ -186,16 +186,14 @@ void LabelManager::ThreadRun(void* data) {
}
}
Label* LabelManager::Create(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2,
Label* LabelManager::Create(LabelCallback callback_1, LabelCallback callback_2,
const uint64_t* args) {
EXIT_IF(ctx == nullptr);
Common::LockGuard lock(m_mutex);
auto* label = new Label;
label->status = LabelStatus::New;
label->device = ctx->device;
label->device = GetRenderContext().GetGraphics().device;
label->callbacks.callback_1 = callback_1;
label->callbacks.callback_2 = callback_2;
@@ -210,21 +208,20 @@ Label* LabelManager::Create(GraphicContext* ctx, LabelCallback callback_1, Label
return label;
}
bool LabelManager::Remove(Label* label) {
EXIT_IF(label == nullptr);
EXIT_IF(label->device == nullptr);
bool LabelManager::Remove(Label& label) {
EXIT_IF(label.device == nullptr);
Common::LockGuard lock(m_mutex);
const auto it = std::find(m_labels.begin(), m_labels.end(), label);
const auto it = std::find(m_labels.begin(), m_labels.end(), &label);
EXIT_NOT_IMPLEMENTED(it == m_labels.end());
EXIT_NOT_IMPLEMENTED(label->status != LabelStatus::NotActive &&
label->status != LabelStatus::Active &&
label->status != LabelStatus::ActiveDeleted);
EXIT_NOT_IMPLEMENTED(label.status != LabelStatus::NotActive &&
label.status != LabelStatus::Active &&
label.status != LabelStatus::ActiveDeleted);
if (!label->submissions.empty()) {
label->status = LabelStatus::ActiveDeleted;
if (!label.submissions.empty()) {
label.status = LabelStatus::ActiveDeleted;
return false;
}
@@ -234,44 +231,41 @@ bool LabelManager::Remove(Label* label) {
return true;
}
void LabelManager::Destroy(Label* label) {
EXIT_IF(label == nullptr);
EXIT_IF(label->device == nullptr);
void LabelManager::Destroy(Label& label) {
EXIT_IF(label.device == nullptr);
EXIT_NOT_IMPLEMENTED(!label->submissions.empty());
EXIT_NOT_IMPLEMENTED(!label.submissions.empty());
delete label;
delete &label;
}
void LabelManager::Delete(Label* label) {
void LabelManager::Delete(Label& label) {
if (Remove(label)) {
Destroy(label);
}
}
void LabelManager::Set(CommandBuffer* buffer, Label* label) {
EXIT_IF(label == nullptr);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
EXIT_IF(label->device == nullptr);
void LabelManager::Set(CommandBuffer& buffer, Label& label) {
EXIT_IF(buffer.IsInvalid());
EXIT_IF(label.device == nullptr);
Common::LockGuard lock(m_mutex);
const auto it = std::find(m_labels.begin(), m_labels.end(), label);
const auto it = std::find(m_labels.begin(), m_labels.end(), &label);
EXIT_NOT_IMPLEMENTED(it == m_labels.end());
EXIT_NOT_IMPLEMENTED(label->status != LabelStatus::New &&
label->status != LabelStatus::NotActive &&
label->status != LabelStatus::Active);
EXIT_NOT_IMPLEMENTED(label.status != LabelStatus::New &&
label.status != LabelStatus::NotActive &&
label.status != LabelStatus::Active);
label->status = LabelStatus::Active;
label.status = LabelStatus::Active;
LabelSubmission submission {};
submission.callbacks = label->callbacks;
submission.callbacks = label.callbacks;
submission.completion = std::make_shared<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);
@@ -281,24 +275,24 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) {
create_info.flags = {};
const auto create_result =
label->device.createEvent(&create_info, nullptr, &submission.completion->event);
label.device.createEvent(&create_info, nullptr, &submission.completion->event);
if (create_result != vk::Result::eSuccess || submission.completion->event == nullptr) {
EXIT("failed to create label event: %s (%d)\n", VulkanToString(create_result).c_str(),
static_cast<int>(create_result));
}
buffer->RetainResourceUntilFence(submission.completion);
buffer.RetainResourceUntilFence(submission.completion);
// Labels can be reused before an earlier end-of-pipe event has been
// observed by the polling thread. Capture a separate Vulkan event and
// callback snapshot for each set so older writes are not lost.
const auto reset_result = label->device.resetEvent(submission.completion->event);
const auto reset_result = label.device.resetEvent(submission.completion->event);
if (reset_result != vk::Result::eSuccess) {
EXIT("failed to reset label event: %s (%d)\n", VulkanToString(reset_result).c_str(),
static_cast<int>(reset_result));
}
vk_buffer.setEvent(submission.completion->event, vk::PipelineStageFlagBits::eBottomOfPipe);
label->submissions.push_back(submission);
label.submissions.push_back(submission);
m_cond_var.SignalAll();
}
@@ -324,20 +318,19 @@ void LabelInit() {
g_label_manager = new LabelManager;
}
Label* LabelCreate(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2,
const uint64_t* args) {
Label* LabelCreate(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args) {
EXIT_IF(g_label_manager == nullptr);
return g_label_manager->Create(ctx, callback_1, callback_2, args);
return g_label_manager->Create(callback_1, callback_2, args);
}
void LabelDelete(Label* label) {
void LabelDelete(Label& label) {
EXIT_IF(g_label_manager == nullptr);
g_label_manager->Delete(label);
}
void LabelSet(CommandBuffer* buffer, Label* label) {
void LabelSet(CommandBuffer& buffer, Label& label) {
EXIT_IF(g_label_manager == nullptr);
g_label_manager->Set(buffer, label);
+3 -4
View File
@@ -15,10 +15,9 @@ void LabelInit();
constexpr int LABEL_ARGS_MAX = 5;
using LabelCallback = bool (*)(const uint64_t* args);
Label* LabelCreate(GraphicContext* ctx, LabelCallback callback_1, LabelCallback callback_2,
const uint64_t* args);
void LabelDelete(Label* label);
void LabelSet(CommandBuffer* buffer, Label* label);
Label* LabelCreate(LabelCallback callback_1, LabelCallback callback_2, const uint64_t* args);
void LabelDelete(Label& label);
void LabelSet(CommandBuffer& buffer, Label& label);
void LabelDrain();
[[nodiscard]] bool LabelInCallback() noexcept;
+73 -76
View File
@@ -5,6 +5,7 @@
#include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/gpu_format.h"
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h"
@@ -240,25 +241,26 @@ vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle) {
return components;
}
bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info) {
bool TextureCheckFormat(vk::ImageCreateInfo& image_info) {
auto& graphics = GetRenderContext().GetGraphics();
vk::ImageFormatProperties props {};
if (ctx->GetImageFormatProperties(image_info->format, image_info->imageType, image_info->tiling,
image_info->usage, image_info->flags,
if (graphics.GetImageFormatProperties(image_info.format, image_info.imageType,
image_info.tiling, image_info.usage, image_info.flags,
&props) == vk::Result::eErrorFormatNotSupported) {
auto apply_fallback = [&](vk::Format replacement, const char* message) {
image_info->format = replacement;
const bool result = TextureCheckFormat(ctx, image_info);
image_info.format = replacement;
const bool result = TextureCheckFormat(image_info);
LOGF("%s [%s]\n", message, (!result ? "FAIL" : "SUCCESS"));
return result;
};
if (image_info->format == vk::Format::eR8G8B8A8Srgb) {
if (image_info.format == vk::Format::eR8G8B8A8Srgb) {
// TODO() convert SRGB -> LINEAR in shader
return apply_fallback(
vk::Format::eR8G8B8A8Unorm,
"replace vk::Format::eR8G8B8A8Srgb => vk::Format::eR8G8B8A8Unorm");
}
if (image_info->format == vk::Format::eB8G8R8A8Srgb) {
if (image_info.format == vk::Format::eB8G8R8A8Srgb) {
// TODO() convert SRGB -> LINEAR in shader
return apply_fallback(
vk::Format::eB8G8R8A8Unorm,
@@ -269,34 +271,31 @@ bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info) {
return true;
}
static bool TextureCheckFormatExact(GraphicContext* ctx, const vk::ImageCreateInfo& image_info) {
static bool TextureCheckFormatExact(const vk::ImageCreateInfo& image_info) {
auto& graphics = GetRenderContext().GetGraphics();
vk::ImageFormatProperties props {};
return ctx->GetImageFormatProperties(image_info.format, image_info.imageType, image_info.tiling,
image_info.usage, image_info.flags,
return graphics.GetImageFormatProperties(image_info.format, image_info.imageType,
image_info.tiling, image_info.usage, image_info.flags,
&props) != vk::Result::eErrorFormatNotSupported;
}
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components) {
if (image_info->usage & vk::ImageUsageFlagBits::eStorage) {
if (components->r == vk::ComponentSwizzle::eR &&
components->g == vk::ComponentSwizzle::eG &&
components->b == vk::ComponentSwizzle::eB &&
components->a == vk::ComponentSwizzle::eA) {
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo& image_info, vk::ComponentMapping& components) {
if (image_info.usage & vk::ImageUsageFlagBits::eStorage) {
if (components.r == vk::ComponentSwizzle::eR && components.g == vk::ComponentSwizzle::eG &&
components.b == vk::ComponentSwizzle::eB && components.a == vk::ComponentSwizzle::eA) {
return true;
}
if (components->r == vk::ComponentSwizzle::eB &&
components->g == vk::ComponentSwizzle::eG &&
components->b == vk::ComponentSwizzle::eR &&
components->a == vk::ComponentSwizzle::eA &&
image_info->format == vk::Format::eR8G8B8A8Srgb) {
if (components.r == vk::ComponentSwizzle::eB && components.g == vk::ComponentSwizzle::eG &&
components.b == vk::ComponentSwizzle::eR && components.a == vk::ComponentSwizzle::eA &&
image_info.format == vk::Format::eR8G8B8A8Srgb) {
LOGF("replace vk::Format::eR8G8B8A8Srgb => vk::Format::eB8G8R8A8Srgb\n");
components->r = vk::ComponentSwizzle::eR;
components->g = vk::ComponentSwizzle::eG;
components->b = vk::ComponentSwizzle::eB;
components->a = vk::ComponentSwizzle::eA;
image_info->format = vk::Format::eB8G8R8A8Srgb;
components.r = vk::ComponentSwizzle::eR;
components.g = vk::ComponentSwizzle::eG;
components.b = vk::ComponentSwizzle::eB;
components.a = vk::ComponentSwizzle::eA;
image_info.format = vk::Format::eB8G8R8A8Srgb;
return true;
}
@@ -413,10 +412,9 @@ bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer
layer_count % 6u == 0;
}
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj,
vk::ComponentMapping TextureCreateImage(VulkanImage& vk_obj,
const TextureImageCreateParams& params) {
EXIT_IF(ctx == nullptr);
EXIT_IF(vk_obj == nullptr);
auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(params.owner == nullptr);
const bool array_texture = TextureIsLayeredTexture(params.type);
@@ -474,7 +472,7 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj
image_info.samples = vk::SampleCountFlagBits::e1;
const bool storage_view = TextureHasFormatUsage(params.view_usage, TextureFormatUsage::Storage);
if (storage_view && !TextureCheckStorageSwizzle(&image_info, &components)) {
if (storage_view && !TextureCheckStorageSwizzle(image_info, components)) {
if (!params.storage_swizzle_fallback) {
EXIT("swizzle is not supported");
}
@@ -494,11 +492,11 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj
const auto requested_usage = params.format_usage;
const auto required_usage = params.required_format_usage;
const bool has_optional_usage = static_cast<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;
required_info.usage = TextureGetUsage(required_usage);
required_info.format = view_checked_format;
if (TextureCheckFormatExact(ctx, required_info)) {
if (TextureCheckFormatExact(required_info)) {
static std::atomic_uint log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF("\t %s usage 0x%08x is not supported for format %d, using required "
@@ -511,39 +509,38 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj
}
}
if (!TextureCheckFormat(ctx, &image_info)) {
if (!TextureCheckFormat(image_info)) {
if (has_optional_usage) {
image_info.format = view_checked_format;
image_info.usage = TextureGetUsage(required_usage);
}
if (!has_optional_usage || !TextureCheckFormat(ctx, &image_info)) {
if (!has_optional_usage || !TextureCheckFormat(image_info)) {
EXIT("format is not supported");
}
}
vk_obj->extent.width = image_info.extent.width;
vk_obj->extent.height = image_info.extent.height;
vk_obj->layers = image_info.arrayLayers;
vk_obj->mip_levels = image_info.mipLevels;
vk_obj->format = image_info.format;
vk_obj->image = nullptr;
vk_obj->layout = image_info.initialLayout;
vk_obj.extent.width = image_info.extent.width;
vk_obj.extent.height = image_info.extent.height;
vk_obj.layers = image_info.arrayLayers;
vk_obj.mip_levels = image_info.mipLevels;
vk_obj.format = image_info.format;
vk_obj.image = nullptr;
vk_obj.layout = image_info.initialLayout;
vk_obj->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
vk_obj.memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
bool created = VulkanCreateImage(ctx, image_info, vk_obj);
bool created = graphics.CreateImage(image_info, vk_obj);
EXIT_NOT_IMPLEMENTED(!created);
return components;
}
void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj,
void TextureCreateImageViews(VulkanImage& vk_obj,
vk::ComponentMapping components, uint64_t type, uint32_t base_array,
uint32_t base_level, uint32_t level_count, uint32_t depth,
bool allow_cube_view, TextureFormatUsage view_usage) {
EXIT_IF(ctx == nullptr);
EXIT_IF(vk_obj == nullptr);
EXIT_IF(level_count == 0 || base_level + level_count > vk_obj->mip_levels);
auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(level_count == 0 || base_level + level_count > vk_obj.mip_levels);
const bool layered_texture = TextureIsLayeredTexture(type);
const bool volume_texture = TextureIs3DTexture(type);
@@ -559,9 +556,9 @@ void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj,
create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = (usage_info.usage ? &usage_info : nullptr);
create_info.flags = {};
create_info.image = vk_obj->image;
create_info.image = vk_obj.image;
create_info.viewType = vk::ImageViewType::e2D;
create_info.format = vk_obj->format;
create_info.format = vk_obj.format;
create_info.components = components;
create_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
create_info.subresourceRange.baseArrayLayer = (layered_texture ? base_array : 0);
@@ -581,8 +578,8 @@ void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj,
auto create_view = [&](int index) {
const auto result =
ctx->device.createImageView(&create_info, nullptr, &vk_obj->image_view[index]);
if (result != vk::Result::eSuccess || vk_obj->image_view[index] == nullptr) {
graphics.device.createImageView(&create_info, nullptr, &vk_obj.image_view[index]);
if (result != vk::Result::eSuccess || vk_obj.image_view[index] == nullptr) {
EXIT("failed to create texture image view: result=%d format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(create_info.format), index);
}
@@ -854,7 +851,7 @@ static uint64_t FmaskRegionCopySize(const BufferImageCopy& region) {
sizeof(uint32_t);
}
static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj,
static void UploadFmaskIdentity(VulkanImage& vk_obj,
const std::vector<BufferImageCopy>& regions,
vk::ImageLayout dst_layout, const char* owner) {
constexpr uint32_t kIdentityFmaskPattern = 0x76543210u;
@@ -878,7 +875,8 @@ static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj,
words[i] = kIdentityFmaskPattern;
}
Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), upload_size, upload_regions, dst_layout);
Transfer::UploadImage(vk_obj, temp_buf.Data(), upload_size, upload_regions,
dst_layout);
}
struct GpuTileElementLayout {
@@ -887,31 +885,30 @@ struct GpuTileElementLayout {
uint32_t tall = 1;
};
static bool GetGpuTileElementLayout(uint32_t fmt, GpuTileElementLayout* out) {
EXIT_IF(out == nullptr);
static bool GetGpuTileElementLayout(uint32_t fmt, GpuTileElementLayout& out) {
if (const auto bytes = Prospero::NumBytesPerElement(fmt); bytes != 0) {
*out = {bytes, 1, 1};
out = {bytes, 1, 1};
return true;
}
if (const auto bytes = Prospero::BlockCompressedBytesPerBlock(fmt); bytes != 0) {
*out = {bytes, 4, 4};
out = {bytes, 4, 4};
return true;
}
return false;
}
static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity, uint64_t* size) {
if (size == nullptr || offset > capacity || length > capacity - offset) {
static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity, uint64_t& size) {
if (offset > capacity || length > capacity - offset) {
return false;
}
*size = length;
size = length;
return true;
}
bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth,
uint64_t levels, std::vector<GpuTileInfo>* out_infos) {
if (out_infos == nullptr || size == 0 || levels == 0 || levels > 16 || depth == 0 ||
uint64_t levels, std::vector<GpuTileInfo>& out_infos) {
if (size == 0 || levels == 0 || levels > 16 || depth == 0 ||
regions.size() != GetTextureRegionCount(depth, levels, layout.volume_texture) ||
Prospero::IsFmaskTextureFormat(fmt)) {
return false;
@@ -921,7 +918,7 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
if (layout.tile_family == TileBlockFamily::RenderTarget64KB ||
layout.tile_family == TileBlockFamily::Depth64KB) {
element.bytes = Prospero::RenderTargetBytesPerElement(fmt);
} else if (!GetGpuTileElementLayout(fmt, &element)) {
} else if (!GetGpuTileElementLayout(fmt, element)) {
return false;
}
if (element.bytes == 0) {
@@ -933,12 +930,12 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
if (layout.volume_texture) {
TileVolumeLayout volume {};
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;
}
element = {volume.bytes_per_element, volume.texel_width, volume.texel_height};
TileBlockLayout block {};
if (!TileGetBlockLayout(volume.family, element.bytes, &block)) return false;
if (!TileGetBlockLayout(volume.family, element.bytes, block)) return false;
size_t region_base = 0;
for (uint32_t level = 0; level < levels; ++level) {
@@ -958,9 +955,9 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
const uint64_t linear_span =
static_cast<uint64_t>(copy_depth - 1u) * linear_stride +
layout.level_sizes[level].size;
if (!SetGpuTileSize(info.linear_offset, linear_span, size, &info.linear_size) ||
if (!SetGpuTileSize(info.linear_offset, linear_span, size, info.linear_size) ||
!SetGpuTileSize(info.tiled_offset, volume.level_sizes[level], size,
&info.tiled_size)) {
info.tiled_size)) {
return false;
}
info.linear_slice_stride = linear_stride;
@@ -990,7 +987,7 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
const bool tail = level >= layout.first_tail_level;
const auto family = base_family;
TileBlockLayout block {};
if (!TileGetBlockLayout(family, element.bytes, &block)) {
if (!TileGetBlockLayout(family, element.bytes, block)) {
return false;
}
const auto level_depth = GetTextureLevelDepth(depth, level, layout.volume_texture);
@@ -1001,9 +998,9 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
info.bytes_per_element = block.bytes_per_element;
info.linear_offset = region.offset;
info.tiled_offset = TextureUploadSliceSourceOffset(layout, level, z);
if (!SetGpuTileSize(info.linear_offset, level_size.size, size, &info.linear_size) ||
if (!SetGpuTileSize(info.linear_offset, level_size.size, size, info.linear_size) ||
!SetGpuTileSize(info.tiled_offset, GetLevelSrcSize(level_size), size,
&info.tiled_size)) {
info.tiled_size)) {
return false;
}
info.width = std::max((region.width + element.wide - 1u) / element.wide, 1u);
@@ -1036,11 +1033,11 @@ bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>&
if (infos.empty()) {
return false;
}
*out_infos = std::move(infos);
out_infos = std::move(infos);
return true;
}
void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data,
void TextureUploadGuestImage(VulkanImage& vk_obj, const void* src_data,
uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint64_t width,
uint64_t height, uint32_t depth, uint64_t levels, const char* owner,
@@ -1051,21 +1048,21 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
owner, layout.tile, size, width, height, depth, layout.pitch, levels);
}
if (static_cast<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;
}
if (layout.tile_family == TileBlockFamily::Depth64KB && Prospero::IsFmaskTextureFormat(fmt)) {
UploadFmaskIdentity(ctx, vk_obj, regions, dst_layout, owner);
UploadFmaskIdentity(vk_obj, regions, dst_layout, owner);
return;
}
std::vector<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
"x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n",
owner, fmt, layout.tile, size, width, height, depth, layout.pitch, levels);
}
Transfer::UploadTiledImage(ctx, vk_obj, src_data, size, size, infos, regions, dst_layout);
Transfer::UploadTiledImage(vk_obj, src_data, size, size, infos, regions, dst_layout);
}
} // namespace Libs::Graphics
@@ -83,8 +83,8 @@ struct TextureImageCreateParams {
vk::ComponentSwizzle TextureGetComponentSwizzle(uint8_t s);
vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle);
bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo* image_info);
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components);
bool TextureCheckFormat(vk::ImageCreateInfo& image_info);
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo& image_info, vk::ComponentMapping& components);
vk::ImageUsageFlags TextureGetUsage(TextureFormatUsage usage);
vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage);
vk::Format TextureGetFormat(uint32_t fmt);
@@ -99,9 +99,9 @@ bool TextureIs3DTexture(uint64_t type);
bool TextureIsCubeTexture(uint64_t type);
bool TextureIsLayeredTexture(uint64_t type);
bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer_count);
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* image,
vk::ComponentMapping TextureCreateImage(VulkanImage& image,
const TextureImageCreateParams& params);
void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj,
void TextureCreateImageViews(VulkanImage& vk_obj,
vk::ComponentMapping components, uint64_t type, uint32_t base_array,
uint32_t base_level, uint32_t level_count, uint32_t depth,
bool allow_cube_view, TextureFormatUsage view_usage);
@@ -125,8 +125,8 @@ std::vector<ImageBufferCopy>
TextureBuildDownloadRegions(const std::vector<BufferImageCopy>& upload_regions);
bool TextureBuildGpuTileInfos(uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth,
uint64_t levels, std::vector<GpuTileInfo>* infos);
void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data,
uint64_t levels, std::vector<GpuTileInfo>& infos);
void TextureUploadGuestImage(VulkanImage& vk_obj, const void* src_data,
uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint64_t width,
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/objects/label.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/resourceMutex.h"
#include "graphics/host_gpu/renderer/textureCache.h"
#include "graphics/host_gpu/transfer.h"
@@ -38,22 +39,20 @@ constexpr uint64_t AlignReadbackCopySize(uint64_t size) noexcept {
}
struct SharedVulkanBufferOwner {
explicit SharedVulkanBufferOwner(GraphicContext* context): ctx(context) {
EXIT_IF(ctx == nullptr);
}
explicit SharedVulkanBufferOwner(GraphicContext& graphics): graphics(graphics) {}
~SharedVulkanBufferOwner() {
if (buffer.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &buffer);
graphics.DeleteBuffer(buffer);
}
}
GraphicContext* ctx = nullptr;
GraphicContext& graphics;
VulkanBuffer buffer;
};
std::shared_ptr<VulkanBuffer> MakeSharedVulkanBuffer(GraphicContext* ctx) {
auto owner = std::make_shared<SharedVulkanBufferOwner>(ctx);
std::shared_ptr<VulkanBuffer> MakeSharedVulkanBuffer() {
auto owner = std::make_shared<SharedVulkanBufferOwner>(GetRenderContext().GetGraphics());
return {owner, &owner->buffer};
}
@@ -149,21 +148,21 @@ bool PageOverlaps(uint64_t left, uint64_t left_size, uint64_t right, uint64_t ri
}
} // namespace
bool MergeOverlappingBufferCacheRange(BufferCacheRange* merged,
bool MergeOverlappingBufferCacheRange(BufferCacheRange& merged,
BufferCacheRange candidate) noexcept {
if (merged == nullptr || merged->address == 0 || merged->size == 0 || candidate.address == 0 ||
candidate.size == 0 || merged->size > UINT64_MAX - merged->address ||
if (merged.address == 0 || merged.size == 0 || candidate.address == 0 || candidate.size == 0 ||
merged.size > UINT64_MAX - merged.address ||
candidate.size > UINT64_MAX - candidate.address) {
EXIT("BufferCache: invalid overlap-merge range\n");
}
const auto merged_end = merged->address + merged->size;
const auto merged_end = merged.address + merged.size;
const auto candidate_end = candidate.address + candidate.size;
if (merged->address >= candidate_end || candidate.address >= merged_end) {
if (merged.address >= candidate_end || candidate.address >= merged_end) {
return false;
}
const auto address = std::min(merged->address, candidate.address);
const auto address = std::min(merged.address, candidate.address);
const auto end = std::max(merged_end, candidate_end);
*merged = {.address = address, .size = end - address};
merged = {.address = address, .size = end - address};
return true;
}
@@ -175,7 +174,6 @@ struct BufferCache::CachedBuffer {
uint64_t vaddr = 0;
uint64_t size = 0;
uint64_t queue_mask = 0;
GraphicContext* ctx = nullptr;
std::shared_ptr<VulkanBuffer> buffer;
};
@@ -220,10 +218,7 @@ struct BufferCache::ReadbackWorker {
}
}
void Prepare(GraphicContext* graphic_context) {
if (graphic_context == nullptr) {
EXIT("BufferCache: cannot prepare readback without a graphics context\n");
}
void Prepare() {
auto current = state.load(std::memory_order_acquire);
while (current == State::InitRequested ||
(current == State::Claimed &&
@@ -236,15 +231,11 @@ struct BufferCache::ReadbackWorker {
EXIT("BufferCache: cannot prepare a stopping readback worker, state=%u\n",
static_cast<uint32_t>(current));
}
if (ctx != graphic_context || command == nullptr || mapped == nullptr ||
readback.buffer == nullptr) {
if (command == nullptr || mapped == nullptr || readback.buffer == nullptr) {
EXIT("BufferCache: initialized readback worker has invalid resources, state=%u "
"ctx=%p requested=%p "
"command=%p mapped=%p buffer=%p\n",
static_cast<uint32_t>(current), static_cast<const void*>(ctx),
static_cast<const void*>(graphic_context),
static_cast<const void*>(command.get()), static_cast<const void*>(mapped),
static_cast<const void*>(readback.buffer));
static_cast<uint32_t>(current), static_cast<const void*>(command.get()),
static_cast<const void*>(mapped), static_cast<const void*>(readback.buffer));
}
return;
}
@@ -253,7 +244,6 @@ struct BufferCache::ReadbackWorker {
EXIT("BufferCache: readback prepare requires uninitialized state, state=%u\n",
static_cast<uint32_t>(expected));
}
ctx = graphic_context;
state.store(State::InitRequested, std::memory_order_release);
state.notify_all();
while ((current = state.load(std::memory_order_acquire)) != State::Idle) {
@@ -276,16 +266,15 @@ struct BufferCache::ReadbackWorker {
const bool submissions_prepaused_now = GraphicsRunSubmissionLockHeld() || command_thread;
const bool unsafe_gpu_lock = GraphicsRunGpuLockHeld() && !submissions_prepaused_now;
if (unsafe_gpu_lock || LabelInCallback() || g_cache_lock_owner != nullptr ||
ctx == nullptr || command == nullptr || mapped == nullptr ||
readback.buffer == nullptr) {
command == nullptr || mapped == nullptr || readback.buffer == nullptr) {
EXIT("BufferCache: unsafe readback request context, command_thread=%d "
"submission_lock=%d "
"gpu_lock=%d label_callback=%d cache_lock=%p ctx=%p command=%p mapped=%p "
"gpu_lock=%d label_callback=%d cache_lock=%p command=%p mapped=%p "
"buffer=%p\n",
command_thread, GraphicsRunSubmissionLockHeld(), GraphicsRunGpuLockHeld(),
LabelInCallback(), static_cast<const void*>(g_cache_lock_owner),
static_cast<const void*>(ctx), static_cast<const void*>(command.get()),
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));
}
State expected = State::Idle;
while (!state.compare_exchange_weak(expected, State::Claimed, std::memory_order_acq_rel)) {
@@ -386,48 +375,46 @@ struct BufferCache::ReadbackWorker {
if (current == State::Stopping) {
command.reset();
if (mapped != nullptr) {
VulkanUnmapMemory(ctx, &readback.memory);
cache.m_graphics.UnmapMemory(readback.memory);
mapped = nullptr;
}
if (readback.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &readback);
cache.m_graphics.DeleteBuffer(readback);
}
state.store(State::Stopped, std::memory_order_release);
state.notify_all();
return;
}
if (current == State::InitRequested) {
if (ctx == nullptr || command != nullptr || mapped != nullptr ||
readback.buffer != nullptr) {
EXIT("BufferCache: invalid resources before readback initialization, ctx=%p "
if (command != nullptr || mapped != nullptr || readback.buffer != nullptr) {
EXIT("BufferCache: invalid resources before readback initialization, "
"command=%p mapped=%p buffer=%p\n",
static_cast<const void*>(ctx), static_cast<const void*>(command.get()),
static_cast<const void*>(mapped),
static_cast<const void*>(command.get()), static_cast<const void*>(mapped),
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) ||
ctx->queues[GraphicContext::QUEUE_GFX].family != family) {
cache.m_graphics.queues[GraphicContext::QUEUE_GFX].family != family) {
EXIT("BufferCache: utility and graphics queues must share a valid family, "
"util=%u "
"gfx=%u\n",
family, ctx->queues[GraphicContext::QUEUE_GFX].family);
family, cache.m_graphics.queues[GraphicContext::QUEUE_GFX].family);
}
for (int i = GraphicContext::QUEUE_COMPUTE_START;
i < GraphicContext::QUEUE_COMPUTE_START + GraphicContext::QUEUE_COMPUTE_NUM;
i++) {
if (ctx->queues[i].family != family) {
if (cache.m_graphics.queues[i].family != family) {
EXIT("BufferCache: compute queue %d family mismatch, expected=%u "
"actual=%u\n",
i, family, ctx->queues[i].family);
i, family, cache.m_graphics.queues[i].family);
}
}
readback.usage = vk::BufferUsageFlagBits::eTransferDst;
readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, READBACK_CAPACITY, &readback);
VulkanMapMemory(ctx, &readback.memory, &mapped);
cache.m_graphics.CreateBuffer(READBACK_CAPACITY, readback);
cache.m_graphics.MapMemory(readback.memory, mapped);
command = std::make_unique<CommandBuffer>(GraphicContext::QUEUE_UTIL);
state.store(State::Idle, std::memory_order_release);
state.notify_all();
@@ -528,7 +515,6 @@ struct BufferCache::ReadbackWorker {
BufferCache& cache;
std::atomic<State> state {State::Uninitialized};
GraphicContext* ctx = nullptr;
VulkanBuffer readback {};
void* mapped = nullptr;
std::unique_ptr<CommandBuffer> command;
@@ -542,8 +528,9 @@ struct BufferCache::ReadbackWorker {
std::thread thread;
};
BufferCache::BufferCache(PageManager& page_manager, ResourceMutex& resource_mutex)
: m_memory_tracker(page_manager), m_page_manager(page_manager),
BufferCache::BufferCache(GraphicContext& graphics, PageManager& page_manager,
ResourceMutex& resource_mutex)
: m_graphics(graphics), m_memory_tracker(page_manager), m_page_manager(page_manager),
m_resource_mutex(resource_mutex) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
m_readback = std::make_unique<ReadbackWorker>(*this);
@@ -563,7 +550,7 @@ BufferCache::~BufferCache() {
}
}
if (!m_buffers.empty()) {
Transfer::WaitForGraphicsIdle(m_buffers.begin()->second->ctx);
Transfer::WaitForGraphicsIdle();
}
m_buffers.clear();
}
@@ -629,8 +616,8 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) {
const auto ranges = m_gpu_modified_ranges.Intersections(address, bytes);
for (const auto& range: ranges) {
std::vector<uint8_t> data(range.size);
Transfer::DownloadBuffer(cached->ctx, cached->buffer.get(),
range.address - begin, data.data(), range.size);
Transfer::DownloadBuffer(*cached->buffer, range.address - begin, data.data(),
range.size);
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
downloaded += range.size;
}
@@ -659,19 +646,15 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) {
}
}
std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* command,
GraphicContext* ctx, uint64_t vaddr,
uint64_t size, bool is_written,
bool is_read, bool is_formatted) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr ||
vaddr == 0 || size == 0 || size > UINT64_MAX - vaddr || command->GetQueue() < 0 ||
command->GetQueue() >= 64) {
EXIT("BufferCache: invalid buffer request, command=%p queue=%d ctx=%p addr=0x%016" PRIx64
BufferBinding BufferCache::ObtainBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
bool is_written, bool is_read, bool is_formatted) {
if (command.IsInvalid() || command.IsExecute() || vaddr == 0 || size == 0 ||
size > UINT64_MAX - vaddr || command.GetQueue() < 0 || command.GetQueue() >= 64) {
EXIT("BufferCache: invalid buffer request, queue=%d addr=0x%016" PRIx64
" size=0x%016" PRIx64 "\n",
static_cast<const void*>(command), command == nullptr ? -1 : command->GetQueue(),
static_cast<const void*>(ctx), vaddr, size);
command.GetQueue(), 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;
ValidateGpuAccess(vaddr, size, is_read, is_written);
const auto begin = AlignDown(vaddr);
@@ -691,10 +674,10 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
VulkanBuffer* stream_buffer = nullptr;
vk::DeviceSize stream_offset = 0;
vk::DeviceSize stream_range = 0;
const auto stream_alignment = std::max<uint64_t>(ctx->StorageMinAlignment(), 16);
if (UploadHostData(command, ctx, guest_data.data(), size, stream_alignment,
&stream_buffer, &stream_offset, &stream_range)) {
return {stream_buffer, stream_offset};
const auto stream_alignment = std::max<uint64_t>(m_graphics.StorageMinAlignment(), 16);
if (UploadHostData(command, guest_data.data(), size, stream_alignment, stream_buffer,
stream_offset, stream_range)) {
return {*stream_buffer, stream_offset};
}
}
}
@@ -728,7 +711,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
}
}
if (is_written) {
m_readback->Prepare(ctx);
m_readback->Prepare();
}
FaultSafeCacheLock lock(this, m_mutex);
@@ -749,7 +732,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
if (first != m_buffers.begin()) {
auto previous = std::prev(first);
if (MergeOverlappingBufferCacheRange(
&merged, {previous->second->vaddr, previous->second->size})) {
merged, {previous->second->vaddr, previous->second->size})) {
first = previous;
}
}
@@ -758,7 +741,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
break;
}
if (MergeOverlappingBufferCacheRange(
&merged, {candidate->second->vaddr, candidate->second->size})) {
merged, {candidate->second->vaddr, candidate->second->size})) {
overlaps.push_back(candidate);
}
}
@@ -766,11 +749,10 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
if (!overlaps.empty()) {
for (const auto& overlap: overlaps) {
auto& old = *overlap->second;
if (old.ctx != ctx || old.buffer == nullptr || old.buffer->buffer == nullptr) {
if (old.buffer == nullptr || old.buffer->buffer == nullptr) {
EXIT("BufferCache: invalid overlapping buffer owner, addr=0x%016" PRIx64
" size=0x%016" PRIx64 " owner_ctx=%p requested_ctx=%p buffer=%p\n",
old.vaddr, old.size, static_cast<const void*>(old.ctx),
static_cast<const void*>(ctx), static_cast<const void*>(old.buffer.get()));
" size=0x%016" PRIx64 " buffer=%p\n",
old.vaddr, old.size, static_cast<const void*>(old.buffer.get()));
}
if (!CanMergeBufferCacheQueueMask(old.queue_mask, queue)) {
EXIT("BufferCache: cross-queue overlap merge is unsupported, "
@@ -786,8 +768,8 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
},
[&]() noexcept {
for (const auto& [upload_vaddr, upload_size]: uploads) {
Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex,
old.buffer.get(), upload_vaddr - old.vaddr,
Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *old.buffer,
upload_vaddr - old.vaddr,
reinterpret_cast<const void*>(upload_vaddr),
upload_size);
}
@@ -797,16 +779,15 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
auto cached = std::make_unique<CachedBuffer>();
cached->vaddr = merged.address;
cached->size = merged.size;
cached->ctx = ctx;
cached->buffer = MakeSharedVulkanBuffer(ctx);
cached->buffer = MakeSharedVulkanBuffer();
cached->buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst |
vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer |
vk::BufferUsageFlagBits::eStorageBuffer;
cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
VulkanCreateBuffer(ctx, cached->size, cached->buffer.get());
m_graphics.CreateBuffer(cached->size, *cached->buffer);
if (!overlaps.empty()) {
auto vk_buffer = command->Handle();
auto vk_buffer = command.Handle();
std::vector<vk::BufferMemoryBarrier> before;
before.reserve(overlaps.size() + 1);
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::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr);
for (const auto& overlap: overlaps) {
command->RetainResourceUntilFence(overlap->second->buffer);
command.RetainResourceUntilFence(overlap->second->buffer);
m_buffers.erase(overlap);
}
}
@@ -871,8 +852,8 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
},
[&]() noexcept {
for (const auto& [upload_vaddr, upload_size]: ranges) {
Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex,
cached.buffer.get(), upload_vaddr - cached.vaddr,
Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *cached.buffer,
upload_vaddr - cached.vaddr,
reinterpret_cast<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);
}
cached.queue_mask |= queue_mask;
command->RetainResourceUntilFence(cached.buffer);
return {cached.buffer.get(), vaddr - cached.vaddr};
command.RetainResourceUntilFence(cached.buffer);
return {*cached.buffer, vaddr - cached.vaddr};
}
bool BufferCache::UploadHostData(CommandBuffer* command, GraphicContext* ctx, const void* src,
uint64_t size, uint64_t alignment, VulkanBuffer** out_buffer,
uint64_t* out_offset, uint64_t* out_range) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr) {
bool BufferCache::UploadHostData(CommandBuffer& command, const void* src, uint64_t size,
uint64_t alignment, VulkanBuffer*& out_buffer,
uint64_t& out_offset, uint64_t& out_range) {
if (command.IsInvalid() || command.IsExecute()) {
EXIT("BufferCache: host stream upload requires a recording command buffer\n");
}
return command->m_host_stream.Copy(ctx, src, size, alignment, out_buffer, out_offset,
out_range);
return command.m_host_stream.Copy(src, size, alignment, out_buffer, out_offset, out_range);
}
VulkanBuffer* BufferCache::ObtainNullBuffer(CommandBuffer* command, GraphicContext* ctx) {
if (command == nullptr || command->IsInvalid() || command->IsExecute() || ctx == nullptr) {
VulkanBuffer& BufferCache::ObtainNullBuffer(CommandBuffer& command) {
if (command.IsInvalid() || command.IsExecute()) {
EXIT("BufferCache: null buffer requires a graphics context\n");
}
FaultSafeCacheLock lock(this, m_mutex);
if (m_null_buffer == nullptr) {
// robustBufferAccess makes every fetch safe; TODO: Use a
// persistent 16-byte fallback when Vulkan null vertex descriptors are unavailable.
auto buffer = MakeSharedVulkanBuffer(ctx);
auto buffer = MakeSharedVulkanBuffer();
buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eIndexBuffer;
buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, 16, buffer.get());
m_graphics.CreateBuffer(16, *buffer);
void* data = nullptr;
VulkanMapMemory(ctx, &buffer->memory, &data);
m_graphics.MapMemory(buffer->memory, data);
std::memset(data, 0, 16);
VulkanUnmapMemory(ctx, &buffer->memory);
m_graphics.UnmapMemory(buffer->memory);
m_null_buffer = std::move(buffer);
}
// The buffer remains cache-persistent, while every recorded consumer keeps the allocation
// alive until its own fence even if an unrelated command processor resets the global cache.
command->RetainResourceUntilFence(m_null_buffer);
return m_null_buffer.get();
command.RetainResourceUntilFence(m_null_buffer);
return *m_null_buffer;
}
BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t size) {
@@ -949,8 +929,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
--owner;
auto& cached = *owner->second;
const auto offset = address - cached.vaddr;
if (offset > cached.size || bytes > cached.size - offset || cached.ctx == nullptr ||
cached.buffer == nullptr || cached.buffer->buffer == nullptr) {
if (offset > cached.size || bytes > cached.size - offset || cached.buffer == nullptr ||
cached.buffer->buffer == nullptr) {
EXIT("BufferCache: GPU image-source bytes have no containing native buffer\n");
}
return cached;
@@ -964,14 +944,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
vaddr, size, GraphicsRunIsCommandProcessorThread(),
GraphicsRunSubmissionLockHeld(), LabelInCallback());
}
std::vector<GraphicContext*> waited;
for (const auto& range: dirty_ranges) {
auto& owner = find_owner(range.address, range.size);
if (std::find(waited.begin(), waited.end(), owner.ctx) == waited.end()) {
Transfer::WaitForGraphicsIdle(owner.ctx);
waited.push_back(owner.ctx);
}
}
Transfer::WaitForGraphicsIdle();
auto backing_writes = ReserveBackingWrites(m_page_manager, dirty_ranges);
uint64_t downloaded = 0;
m_memory_tracker.ForEachDownloadRange<true>(
@@ -990,8 +963,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
auto& owner = find_owner(range.address, range.size);
const auto buffer_offset = range.address - owner.vaddr;
std::vector<uint8_t> data(range.size);
Transfer::DownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset,
data.data(), range.size);
Transfer::DownloadBuffer(*owner.buffer, buffer_offset, data.data(), range.size);
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
downloaded += range.size;
}
@@ -1013,7 +985,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
if (offset > cached.size || size > cached.size - offset) {
return {nullptr, 0, vaddr, size, true, cpu_modified};
}
if (cached.ctx == nullptr || cached.buffer == nullptr || cached.buffer->buffer == nullptr) {
if (cached.buffer == nullptr || cached.buffer->buffer == nullptr) {
EXIT("BufferCache: containing image source is inconsistent\n");
}
if (cpu_modified) {
@@ -1025,8 +997,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
},
[&]() noexcept {
for (const auto& [address, bytes]: uploads) {
Transfer::UploadBuffer(cached.ctx, Transfer::StagingBufferType::Vertex,
cached.buffer.get(), address - cached.vaddr,
Transfer::UploadBuffer(Transfer::StagingBufferType::Vertex, *cached.buffer,
address - cached.vaddr,
reinterpret_cast<const void*>(address), bytes);
}
});
@@ -1047,15 +1019,14 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
}
namespace {
vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, uint64_t size,
vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer& buffer, uint64_t offset, uint64_t size,
vk::AccessFlags source, vk::AccessFlags destination) {
if (buffer == nullptr || buffer->buffer == nullptr || size == 0 ||
offset > buffer->buffer_size || size > buffer->buffer_size - offset) {
if (buffer.buffer == nullptr || size == 0 || offset > buffer.buffer_size ||
size > buffer.buffer_size - offset) {
EXIT("BufferCache: invalid DMA barrier, buffer=%p handle=%p offset=0x%016" PRIx64
" size=0x%016" PRIx64 " buffer_size=0x%016" PRIx64 "\n",
static_cast<const void*>(buffer),
buffer == nullptr ? nullptr : static_cast<const void*>(buffer->buffer), offset, size,
buffer == nullptr ? 0 : buffer->buffer_size);
static_cast<const void*>(&buffer), static_cast<const void*>(buffer.buffer), offset,
size, buffer.buffer_size);
}
vk::BufferMemoryBarrier barrier {};
barrier.sType = vk::StructureType::eBufferMemoryBarrier;
@@ -1063,23 +1034,19 @@ vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, ui
barrier.dstAccessMask = destination;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = buffer->buffer;
barrier.buffer = buffer.buffer;
barrier.offset = offset;
barrier.size = size;
return barrier;
}
vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer* command) {
if (command == nullptr) {
EXIT("BufferCache: invalid DMA command buffer, command=%p\n",
static_cast<const void*>(command));
}
return command->Handle();
vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer& command) {
return command.Handle();
}
} // namespace
void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr,
uint64_t size, uint32_t value) {
void BufferCache::FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size,
uint32_t value) {
if ((vaddr & 3u) != 0 || (size & 3u) != 0) {
EXIT("BufferCache: fill range must be dword aligned, addr=0x%016" PRIx64
" size=0x%016" PRIx64 "\n",
@@ -1114,15 +1081,16 @@ void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
vaddr, size);
}
}
const auto [dst, dst_offset] = ObtainBuffer(command, ctx, vaddr, size, true, false);
EXIT_IF(command == nullptr);
const auto [dst, dst_offset] = ObtainBuffer(*command, vaddr, size, true, false);
const auto before = MakeDmaBarrier(
dst, dst_offset, size, vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferWrite);
const auto vk_buffer = GetDmaCommandBuffer(command);
const auto vk_buffer = GetDmaCommandBuffer(*command);
vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &before, 0, nullptr);
vk_buffer.fillBuffer(dst->buffer, dst_offset, size, value);
vk_buffer.fillBuffer(dst.buffer, dst_offset, size, value);
const auto after =
MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite);
@@ -1131,8 +1099,8 @@ void BufferCache::FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
vk::DependencyFlagBits::eByRegion, 0, nullptr, 1, &after, 0, nullptr);
}
void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t dst_vaddr,
uint64_t src_vaddr, uint64_t size) {
void BufferCache::CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr,
uint64_t size) {
if (dst_vaddr == 0 || src_vaddr == 0 || size == 0 ||
((dst_vaddr | src_vaddr | size) & 3u) != 0 || size > UINT64_MAX - dst_vaddr ||
size > UINT64_MAX - src_vaddr ||
@@ -1195,10 +1163,11 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
src_vaddr, dst_vaddr, size);
}
}
const auto [src, src_offset] = ObtainBuffer(command, ctx, src_vaddr, size, false, true);
EXIT_IF(command == nullptr);
const auto [src, src_offset] = ObtainBuffer(*command, src_vaddr, size, false, true);
const auto [dst, dst_offset] =
ObtainBuffer(command, ctx, dst_vaddr, size, true, false, dst_image_transition);
if (src == dst && src_offset < dst_offset + size && dst_offset < src_offset + size) {
ObtainBuffer(*command, dst_vaddr, size, true, false, dst_image_transition);
if (&src == &dst && src_offset < dst_offset + size && dst_offset < src_offset + size) {
EXIT("BufferCache: resolved Vulkan copy ranges overlap, src_offset=0x%016" PRIx64
" dst_offset=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
src_offset, dst_offset, size);
@@ -1210,12 +1179,12 @@ void BufferCache::CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64
MakeDmaBarrier(src, src_offset, size, vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferRead),
};
const auto vk_buffer = GetDmaCommandBuffer(command);
const auto vk_buffer = GetDmaCommandBuffer(*command);
vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, 0, nullptr, 2, before, 0, nullptr);
const vk::BufferCopy copy {src_offset, dst_offset, size};
vk_buffer.copyBuffer(src->buffer, dst->buffer, 1, &copy);
vk_buffer.copyBuffer(src.buffer, dst.buffer, 1, &copy);
const vk::BufferMemoryBarrier after[] = {
MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite),
+17 -13
View File
@@ -35,7 +35,12 @@ struct BufferCacheRange {
uint64_t size = 0;
};
[[nodiscard]] bool MergeOverlappingBufferCacheRange(BufferCacheRange* merged,
struct BufferBinding {
VulkanBuffer& buffer;
uint64_t offset;
};
[[nodiscard]] bool MergeOverlappingBufferCacheRange(BufferCacheRange& merged,
BufferCacheRange candidate) noexcept;
[[nodiscard]] bool CanMergeBufferCacheQueueMask(uint64_t queue_mask, uint32_t queue) noexcept;
@@ -46,27 +51,25 @@ public:
return vaddr & (CACHING_PAGE_SIZE - 1);
}
BufferCache(PageManager& page_manager, ResourceMutex& resource_mutex);
BufferCache(GraphicContext& graphics, PageManager& page_manager, ResourceMutex& resource_mutex);
~BufferCache();
KYTY_CLASS_NO_COPY(BufferCache);
[[nodiscard]] bool InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint64_t size,
PageFaultPhase phase) noexcept;
void UnmapMemory(uint64_t vaddr, uint64_t size);
[[nodiscard]] std::pair<VulkanBuffer*, uint64_t>
ObtainBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, uint64_t size,
bool is_written = false, bool is_read = true, bool is_formatted = false);
[[nodiscard]] BufferBinding ObtainBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
bool is_written = false, bool is_read = true,
bool is_formatted = false);
// Emulator-owned, CPU-current scratch only. Guest ranges must use ObtainBuffer so page
// ownership is resolved before any CPU access.
[[nodiscard]] bool UploadHostData(CommandBuffer* command, GraphicContext* ctx, const void* src,
uint64_t size, uint64_t alignment, VulkanBuffer** out_buffer,
uint64_t* out_offset, uint64_t* out_range);
[[nodiscard]] VulkanBuffer* ObtainNullBuffer(CommandBuffer* command, GraphicContext* ctx);
[[nodiscard]] bool UploadHostData(CommandBuffer& command, const void* src, uint64_t size,
uint64_t alignment, VulkanBuffer*& out_buffer,
uint64_t& out_offset, uint64_t& out_range);
[[nodiscard]] VulkanBuffer& ObtainNullBuffer(CommandBuffer& command);
[[nodiscard]] BufferImageCopySource ObtainBufferForImage(uint64_t vaddr, uint64_t size);
void FillBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t vaddr, uint64_t size,
uint32_t value);
void CopyBuffer(CommandBuffer* command, GraphicContext* ctx, uint64_t dst_vaddr,
uint64_t src_vaddr, uint64_t size);
void FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, uint32_t value);
void CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);
[[nodiscard]] bool HasPageOverlap(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsRegionCpuModified(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsRegionGpuModified(uint64_t vaddr, uint64_t size);
@@ -80,6 +83,7 @@ private:
struct CachedBuffer;
struct ReadbackWorker;
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::shared_ptr<VulkanBuffer> m_null_buffer;
// TODO: add LRU cache
@@ -25,15 +25,13 @@ namespace Libs::Graphics {
static std::atomic<uint32_t> g_render_color_log_count = 0;
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderColorInfo* r, uint32_t render_target_slice_offset,
uint32_t render_target_slot, bool ignore_target_mask,
bool reuse_existing_render_texture) {
void ResolveRenderColorTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderColorInfo& r,
uint32_t render_target_slice_offset, uint32_t render_target_slot,
bool ignore_target_mask, bool reuse_existing_render_texture) {
KYTY_PROFILER_FUNCTION();
const auto& hw = buffer.GetRegisters();
EXIT_IF(r == nullptr);
const auto rt_slot = (render_target_slot == UINT32_MAX ? render_target_first_bound_slot(hw)
const auto rt_slot = (render_target_slot == UINT32_MAX ? render_target_first_bound_slot(buffer)
: render_target_slot);
const auto& rt = hw.GetRenderTarget(rt_slot);
auto mask = render_target_mask_slot(hw.GetRenderTargetMask(), rt_slot);
@@ -41,8 +39,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
mask = 0x0f;
}
r->target_slot = rt_slot;
r->export_mapping = {};
r.target_slot = rt_slot;
r.export_mapping = {};
if (rt.base.addr == 0 || mask == 0) {
if (graphics_debug_dump_enabled()) {
@@ -58,17 +56,17 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
}
// No color output
r->type = RenderColorType::NoColorOutput;
r->base_addr = 0;
r->vulkan_buffer = nullptr;
r->vulkan_view = nullptr;
r->format = vk::Format::eUndefined;
r->extent = {};
r->base_mip_level = 0;
r->buffer_size = 0;
r->samples = 1;
r->color_clear_enable = false;
r->color_clear_value = {};
r.type = RenderColorType::NoColorOutput;
r.base_addr = 0;
r.vulkan_buffer = nullptr;
r.vulkan_view = nullptr;
r.format = vk::Format::eUndefined;
r.extent = {};
r.base_mip_level = 0;
r.buffer_size = 0;
r.samples = 1;
r.color_clear_enable = false;
r.color_clear_value = {};
return;
}
const auto samples = render_sample_count(rt.attrib.num_fragments);
@@ -88,7 +86,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
rt.view.base_array_slice_index, rt.view.last_array_slice_index,
render_target_slice_offset);
}
r->base_array_layer = view.base_layer;
r.base_array_layer = view.base_layer;
const uint32_t levels = rt.attrib2.num_mip_levels + 1u;
if (levels == 0 || levels > 16 || rt.view.current_mip_level >= levels) {
EXIT("unsupported render-target mip range: current=%u levels=%u\n",
@@ -113,8 +111,8 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
// SRGB clear words are still encoded as normalized component values.
// Fast color clears are metadata driven and must be handled explicitly when
// that metadata path is implemented; render-pass load must preserve contents.
r->color_clear_enable = false;
r->color_clear_value = {};
r.color_clear_enable = false;
r.color_clear_value = {};
uint32_t width = 0;
uint32_t height = 0;
@@ -189,9 +187,9 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
} else {
valid_layout =
levels == 1 ? TileGetRenderTargetSize(width, height, pitch, bytes_per_element,
&layout, rt.attrib.num_fragments)
layout, rt.attrib.num_fragments)
: TileGetRenderTargetMipLayout(width, height, pitch, bytes_per_element,
levels, &layout, nullptr, nullptr);
levels, layout, nullptr, nullptr);
}
if (!valid_layout) {
EXIT("unsupported render-target layout: %ux%u pitch=%u bytes=%u levels=%u\n", width,
@@ -257,23 +255,22 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
target.levels = levels;
target.layers = view.image_layers;
target.samples = samples;
auto* texture_cache = g_render_ctx->GetTextureCache();
auto* buffer_vulkan =
texture_cache->FindRenderTarget(buffer, g_render_ctx->GetGraphicCtx(), target);
r->type = RenderColorType::RenderTexture;
r->base_addr = rt.base.addr;
r->vulkan_buffer = buffer_vulkan;
r->vulkan_view = texture_cache->GetRenderTargetAttachmentView(
g_render_ctx->GetGraphicCtx(), buffer_vulkan, target.format, rt.view.current_mip_level,
view.base_layer, view.layer_count);
r->format = target.format;
r->extent = view_extent;
r->base_mip_level = rt.view.current_mip_level;
r->buffer_size = backing_size;
r->samples = samples;
r->export_mapping = target_format.export_mapping;
r->color_clear_enable = buffer_vulkan->initial_clear_pending;
r->color_clear_value = {};
auto& texture_cache = GetRenderContext().GetTextureCache();
auto& buffer_vulkan = texture_cache.FindRenderTarget(buffer, target);
r.type = RenderColorType::RenderTexture;
r.base_addr = rt.base.addr;
r.vulkan_buffer = &buffer_vulkan;
r.vulkan_view = texture_cache.GetRenderTargetAttachmentView(
buffer_vulkan, target.format, rt.view.current_mip_level, view.base_layer,
view.layer_count);
r.format = target.format;
r.extent = view_extent;
r.base_mip_level = rt.view.current_mip_level;
r.buffer_size = backing_size;
r.samples = samples;
r.export_mapping = target_format.export_mapping;
r.color_clear_enable = buffer_vulkan.initial_clear_pending;
r.color_clear_value = {};
} else {
if (samples != 1) {
EXIT("multisampled display render targets are unsupported\n");
@@ -305,16 +302,16 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
}
EXIT_NOT_IMPLEMENTED(video_image.size < size);
EXIT_NOT_IMPLEMENTED(video_image.pitch != pitch);
r->type = RenderColorType::DisplayBuffer;
r->base_addr = rt.base.addr;
r->vulkan_buffer = video_image.image;
r->vulkan_view = video_image.image->image_view[VulkanImage::VIEW_DEFAULT];
r->format = video_image.image->format;
r->extent = video_image.image->extent;
r->base_mip_level = 0;
r->buffer_size = video_image.size;
r->samples = 1;
r->export_mapping = target_format.export_mapping;
r.type = RenderColorType::DisplayBuffer;
r.base_addr = rt.base.addr;
r.vulkan_buffer = video_image.image;
r.vulkan_view = video_image.image->image_view[VulkanImage::VIEW_DEFAULT];
r.format = video_image.image->format;
r.extent = video_image.image->extent;
r.base_mip_level = 0;
r.buffer_size = video_image.size;
r.samples = 1;
r.export_mapping = target_format.export_mapping;
}
}
@@ -324,7 +321,7 @@ void MarkRenderTargetGpuWritten(const RenderColorInfo& target) {
if (with_color) {
if (target.type == RenderColorType::RenderTexture ||
target.type == RenderColorType::DisplayBuffer) {
g_render_ctx->GetTextureCache()->MarkGpuWritten(target.vulkan_buffer);
GetRenderContext().GetTextureCache().MarkGpuWritten(*target.vulkan_buffer);
} else {
EXIT("unknown writable render-color resource type\n");
}
@@ -9,13 +9,9 @@
namespace Libs::Graphics {
class CommandBuffer;
class RenderCommandBuffer;
struct VulkanImage;
namespace HW {
class Context;
} // namespace HW
enum class RenderColorType {
NoColorOutput,
DisplayBuffer,
@@ -39,8 +35,8 @@ struct RenderColorInfo {
vk::ClearColorValue color_clear_value {};
};
void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderColorInfo* r, uint32_t render_target_slice_offset = 0,
void ResolveRenderColorTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderColorInfo& r,
uint32_t render_target_slice_offset = 0,
uint32_t render_target_slot = UINT32_MAX,
bool ignore_target_mask = false,
bool reuse_existing_render_texture = false);
+74 -60
View File
@@ -23,8 +23,11 @@
#include <atomic>
#include <cstring>
#include <memory>
#include <mutex>
namespace Libs::Graphics {
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) {
EXIT_IF(queue_id < 0 || queue_id >= GraphicContext::QUEUES_NUM);
@@ -65,9 +68,18 @@ private:
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;
bool HasRenderContext() noexcept {
return g_render_ctx != nullptr;
}
RenderContext& GetRenderContext() {
EXIT_IF(g_render_ctx == nullptr);
return *g_render_ctx;
}
FenceResourceRetainer::~FenceResourceRetainer() {
if (!m_resources.empty()) {
EXIT("fence resource retainer destroyed before release\n");
@@ -90,9 +102,9 @@ void FenceResourceRetainer::ReleaseAfterFence() noexcept {
}
void GraphicsRenderInit() {
EXIT_IF(g_render_ctx != nullptr);
g_render_ctx = new RenderContext;
std::scoped_lock lock(g_render_init_mutex);
EXIT_IF(g_render_initialized || g_render_ctx != nullptr);
g_render_initialized = true;
}
void GraphicsRenderReleaseThreadCommandPools() {
@@ -102,32 +114,43 @@ void GraphicsRenderReleaseThreadCommandPools() {
}
void GraphicsRenderCreateContext() {
EXIT_IF(g_render_ctx == nullptr);
std::scoped_lock lock(g_render_init_mutex);
EXIT_IF(!g_render_initialized);
if (g_render_ctx == nullptr) {
g_render_ctx = new RenderContext(WindowGetGraphicContext());
}
}
g_render_ctx->SetGraphicCtx(WindowGetGraphicContext());
void GraphicsRenderSetContext(RenderContext& context) {
std::scoped_lock lock(g_render_init_mutex);
EXIT_IF(!g_render_initialized || g_render_ctx != nullptr);
g_render_ctx = &context;
}
CommandBuffer::CommandBuffer(int queue)
: m_graphics(GetRenderContext().GetGraphics()), m_queue(queue), m_host_stream(m_graphics) {
Allocate();
}
void CommandPool::Create(int queue_id) {
RequireValidQueueId(queue_id);
EXIT_IF(g_render_ctx == nullptr);
auto* ctx = g_render_ctx->GetGraphicCtx();
auto& graphics = GetRenderContext().GetGraphics();
auto*& pool = m_pools[queue_id];
EXIT_IF(pool != nullptr);
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
EXIT_IF(ctx->queues[queue_id].family == static_cast<uint32_t>(-1));
EXIT_IF(graphics.device == nullptr);
EXIT_IF(graphics.queues[queue_id].family == static_cast<uint32_t>(-1));
pool = new VulkanCommandPool;
vk::CommandPoolCreateInfo pool_info {};
pool_info.sType = vk::StructureType::eCommandPoolCreateInfo;
pool_info.pNext = nullptr;
pool_info.queueFamilyIndex = ctx->queues[queue_id].family;
pool_info.queueFamilyIndex = graphics.queues[queue_id].family;
pool_info.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
const auto result = ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool);
const auto result = graphics.device.createCommandPool(&pool_info, nullptr, &pool->pool);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool->pool == nullptr);
pool->buffers_count = 8;
@@ -142,7 +165,7 @@ void CommandPool::Create(int queue_id) {
alloc_info.level = vk::CommandBufferLevel::ePrimary;
alloc_info.commandBufferCount = pool->buffers_count;
if (ctx->device.allocateCommandBuffers(&alloc_info, pool->buffers.get()) !=
if (graphics.device.allocateCommandBuffers(&alloc_info, pool->buffers.get()) !=
vk::Result::eSuccess) {
EXIT("Can't allocate command buffers");
}
@@ -155,7 +178,7 @@ void CommandPool::Create(int queue_id) {
fence_info.pNext = nullptr;
fence_info.flags = vk::FenceCreateFlagBits::eSignaled;
if (ctx->device.createFence(&fence_info, nullptr, &pool->fences[i]) !=
if (graphics.device.createFence(&fence_info, nullptr, &pool->fences[i]) !=
vk::Result::eSuccess) {
EXIT("Can't create fence");
}
@@ -165,7 +188,7 @@ void CommandPool::Create(int queue_id) {
semaphore_info.pNext = nullptr;
semaphore_info.flags = {};
if (ctx->device.createSemaphore(&semaphore_info, nullptr, &pool->semaphores[i]) !=
if (graphics.device.createSemaphore(&semaphore_info, nullptr, &pool->semaphores[i]) !=
vk::Result::eSuccess) {
EXIT("Can't create semaphore");
}
@@ -177,21 +200,21 @@ void CommandPool::Create(int queue_id) {
}
void CommandPool::DeleteAll() {
auto* ctx = g_render_ctx->GetGraphicCtx();
auto& graphics = GetRenderContext().GetGraphics();
for (auto& pool: m_pools) {
if (pool != nullptr) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
EXIT_IF(graphics.device == nullptr);
for (uint32_t i = 0; i < pool->buffers_count; i++) {
ctx->device.destroySemaphore(pool->semaphores[i], nullptr);
ctx->device.destroyFence(pool->fences[i], nullptr);
graphics.device.destroySemaphore(pool->semaphores[i], nullptr);
graphics.device.destroyFence(pool->fences[i], nullptr);
}
ctx->device.freeCommandBuffers(pool->pool, pool->buffers_count, pool->buffers.get());
graphics.device.freeCommandBuffers(pool->pool, pool->buffers_count,
pool->buffers.get());
ctx->device.destroyCommandPool(pool->pool, nullptr);
graphics.device.destroyCommandPool(pool->pool, nullptr);
delete pool;
pool = nullptr;
@@ -200,8 +223,6 @@ void CommandPool::DeleteAll() {
}
bool CommandBuffer::IsInvalid() const {
EXIT_IF(g_render_ctx == nullptr);
if (m_pool != nullptr) {
Common::LockGuard lock(m_pool->mutex);
@@ -255,10 +276,8 @@ void CommandBuffer::Free() {
EXIT_NOT_IMPLEMENTED(!IsInvalid());
}
void CommandBuffer::DeleteAfterFence(VulkanBuffer* buffer) {
EXIT_IF(buffer == nullptr);
m_delete_after_fence.push_back(buffer);
void CommandBuffer::DeleteAfterFence(VulkanBuffer& buffer) {
m_delete_after_fence.push_back(&buffer);
}
void CommandBuffer::RetainResourceUntilFence(std::shared_ptr<void> resource) {
@@ -268,15 +287,13 @@ void CommandBuffer::RetainResourceUntilFence(std::shared_ptr<void> resource) {
m_fence_resources.Retain(std::move(resource));
}
void CommandBuffer::RecycleDescriptorAfterFence(VulkanDescriptorSet* set) {
EXIT_IF(set == nullptr);
m_descriptor_sets_after_fence.push_back(set);
void CommandBuffer::RecycleDescriptorAfterFence(VulkanDescriptorSet& set) {
m_descriptor_sets_after_fence.push_back(&set);
}
void CommandBuffer::RecycleDescriptorsAfterFence() {
for (auto* set: m_descriptor_sets_after_fence) {
g_render_ctx->GetDescriptorCache()->Recycle(set);
GetRenderContext().GetDescriptorCache().Recycle(*set);
}
m_descriptor_sets_after_fence.clear();
}
@@ -351,12 +368,11 @@ void CommandBuffer::Submit(vk::Semaphore wait_semaphore, vk::PipelineStageFlags
submit_info.signalSemaphoreCount = has_signal ? 1u : 0u;
submit_info.pSignalSemaphores = has_signal ? &signal_semaphore : nullptr;
auto* ctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
const auto& queue = ctx->queues[m_queue];
auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(graphics.device == nullptr);
const auto& queue = graphics.queues[m_queue];
auto result = ctx->device.resetFences(1, &fence);
auto result = graphics.device.resetFences(1, &fence);
if (result != vk::Result::eSuccess) {
LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(),
static_cast<int>(result));
@@ -412,7 +428,7 @@ void CommandBuffer::WaitForFenceOnly() {
if (!m_execute || m_fence_waited) {
return;
}
auto device = g_render_ctx->GetGraphicCtx()->device;
auto device = GetRenderContext().GetGraphics().device;
auto result = device.waitForFences(1, &m_pool->fences[m_index], VK_TRUE, UINT64_MAX);
if (result != vk::Result::eSuccess) {
LOGF("vkWaitForFences failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64
@@ -456,21 +472,20 @@ void CommandBuffer::ReleaseResourcesAfterFence() {
void CommandBuffer::DeleteBuffersAfterFence() {
for (auto* buffer: m_delete_after_fence) {
VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer);
GetRenderContext().GetGraphics().DeleteBuffer(*buffer);
delete buffer;
}
m_delete_after_fence.clear();
}
void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors,
uint32_t requested_color_count, RenderDepthInfo* depth) const {
void CommandBuffer::BeginRenderPass(VulkanFramebuffer& framebuffer, RenderColorInfo* colors,
uint32_t requested_color_count, RenderDepthInfo& depth) const {
auto buffer = Handle();
EXIT_IF(framebuffer == nullptr);
EXIT_IF(colors == nullptr);
EXIT_IF(requested_color_count > RENDER_COLOR_ATTACHMENTS_MAX);
bool with_depth = (depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr);
bool with_depth = (depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr);
uint32_t color_count = 0;
for (uint32_t i = 0; i < requested_color_count; i++) {
if (colors[i].vulkan_buffer == nullptr) {
@@ -486,22 +501,22 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
for (uint32_t i = 0; i < color_count; i++) {
clears[i].color = colors[i].color_clear_value;
}
clears[color_count].depthStencil = {depth->depth_clear_value, depth->stencil_clear_value};
clears[color_count].depthStencil = {depth.depth_clear_value, depth.stencil_clear_value};
vk::Extent2D extent = (with_color ? colors[0].extent : depth->vulkan_buffer->extent);
vk::Extent2D extent = (with_color ? colors[0].extent : depth.vulkan_buffer->extent);
vk::RenderPassBeginInfo render_pass_info {};
render_pass_info.sType = vk::StructureType::eRenderPassBeginInfo;
render_pass_info.pNext = nullptr;
render_pass_info.renderPass = framebuffer->render_pass;
render_pass_info.framebuffer = framebuffer->framebuffer;
render_pass_info.renderPass = framebuffer.render_pass;
render_pass_info.framebuffer = framebuffer.framebuffer;
render_pass_info.renderArea.offset = {0, 0};
render_pass_info.renderArea.extent = extent;
render_pass_info.clearValueCount = color_count + (with_depth ? 1u : 0u);
render_pass_info.pClearValues = clears;
for (uint32_t i = 0; i < color_count; i++) {
const auto color_initial_layout = framebuffer->color_layout[i];
const auto color_initial_layout = framebuffer.color_layout[i];
if (colors[i].vulkan_buffer->layout != color_initial_layout) {
if (graphics_debug_dump_enabled()) {
LOGF("BeginRenderPass: color%u initial barrier image=%p mem=%" PRIu64 " %s -> %s\n",
@@ -543,10 +558,9 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
}
const auto depth_layout =
(with_depth && framebuffer != nullptr ? framebuffer->depth_layout
: vk::ImageLayout::eDepthStencilAttachmentOptimal);
with_depth ? framebuffer.depth_layout : vk::ImageLayout::eDepthStencilAttachmentOptimal;
if (with_depth && depth->vulkan_buffer->layout != depth_layout) {
if (with_depth && depth.vulkan_buffer->layout != depth_layout) {
vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier;
image_memory_barrier.pNext = nullptr;
@@ -556,24 +570,24 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
(depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal
? vk::AccessFlagBits::eMemoryRead
: vk::AccessFlagBits::eMemoryWrite);
image_memory_barrier.oldLayout = depth->vulkan_buffer->layout;
image_memory_barrier.oldLayout = depth.vulkan_buffer->layout;
image_memory_barrier.newLayout = depth_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = depth->vulkan_buffer->image;
image_memory_barrier.image = depth.vulkan_buffer->image;
image_memory_barrier.subresourceRange.aspectMask =
ImageViewOps::DepthAspectMask(depth->vulkan_buffer->format);
ImageViewOps::DepthAspectMask(depth.vulkan_buffer->format);
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = depth->vulkan_buffer->layers;
image_memory_barrier.subresourceRange.layerCount = depth.vulkan_buffer->layers;
buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
depth->vulkan_buffer->layout = image_memory_barrier.newLayout;
depth.vulkan_buffer->layout = image_memory_barrier.newLayout;
}
buffer.beginRenderPass(&render_pass_info, vk::SubpassContents::eInline);
@@ -586,8 +600,8 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
}
}
if (with_depth) {
depth->vulkan_buffer->initial_depth_clear_pending = false;
depth->vulkan_buffer->initial_stencil_clear_pending = false;
depth.vulkan_buffer->initial_depth_clear_pending = false;
depth.vulkan_buffer->initial_stencil_clear_pending = false;
}
}
+11 -7
View File
@@ -25,7 +25,8 @@ static bool RenderTargetMaskHasMrt(uint32_t mask) {
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();
if (!RenderTargetMaskHasMrt(mask)) {
@@ -42,7 +43,8 @@ static bool RenderTargetMaskHasBoundMrt(const HW::Context& hw) {
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();
for (uint32_t i = 0; i < 8; i++) {
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);
}
void hw_check(const HW::Context& hw) {
const auto rt_slot = render_target_first_bound_slot(hw);
void hw_check(const RenderCommandBuffer& buffer) {
const auto& hw = buffer.GetRegisters();
const auto rt_slot = render_target_first_bound_slot(buffer);
const auto& rt = hw.GetRenderTarget(rt_slot);
const auto& bc = hw.GetBlendControl(rt_slot);
const auto& bclr = hw.GetBlendColor();
@@ -1291,7 +1294,7 @@ void hw_check(const HW::Context& hw) {
AaCheck(aa, ac);
log_phase("done");
if (RenderTargetMaskHasBoundMrt(hw)) {
if (RenderTargetMaskHasBoundMrt(buffer)) {
LOGF("MRT render target mask: 0x%08" PRIx32 "\n", hw.GetRenderTargetMask());
for (uint32_t i = 0; i < 8; i++) {
const auto& mrt = hw.GetRenderTarget(i);
@@ -1312,8 +1315,9 @@ void hw_check(const HW::Context& hw) {
// EXIT_NOT_IMPLEMENTED(hw.GetStencilClearValue() != 0);
}
void hw_print(const HW::Context& hw) {
const auto rt_slot = render_target_first_bound_slot(hw);
void hw_print(const RenderCommandBuffer& buffer) {
const auto& hw = buffer.GetRegisters();
const auto rt_slot = render_target_first_bound_slot(buffer);
const auto& rt = hw.GetRenderTarget(rt_slot);
const auto& bc = hw.GetBlendControl(rt_slot);
const auto& bclr = hw.GetBlendColor();
+5 -3
View File
@@ -9,6 +9,8 @@
namespace Libs::Graphics {
class RenderCommandBuffer;
namespace HW {
class Context;
class Shader;
@@ -26,7 +28,7 @@ struct ScissorRect {
};
uint32_t render_target_mask_slot(uint32_t mask, uint32_t slot);
uint32_t render_target_first_bound_slot(const HW::Context& hw);
uint32_t render_target_first_bound_slot(const RenderCommandBuffer& buffer);
bool graphics_debug_dump_enabled();
void uc_print(const char* func, const HW::UserConfig& uc);
void uc_check(const HW::UserConfig& uc);
@@ -34,8 +36,8 @@ void sh_print(const char* func, const HW::Shader& uc);
void sh_check(const HW::Shader& uc);
std::vector<std::string> rt_print(const char* func, const HW::RenderTarget& rt);
bool RenderIsColorTileModeLinear(uint32_t tile_mode);
void hw_print(const HW::Context& hw);
void hw_check(const HW::Context& hw);
void hw_print(const RenderCommandBuffer& buffer);
void hw_check(const RenderCommandBuffer& buffer);
void LogDrawPhase(const char* draw_name, const char* phase);
ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc,
vk::Extent2D extent);
@@ -61,20 +61,18 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) {
depth_fail == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp);
}
[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(GraphicContext* ctx,
[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(const RenderCommandBuffer& buffer,
const DepthFormatPolicy& policy,
bool has_stencil,
uint32_t samples) {
if (ctx == nullptr) {
return vk::Format::eUndefined;
}
auto& graphics = buffer.GetGraphics();
const auto required_samples = vulkan_sample_count(samples);
const auto supports = [&](vk::Format format) {
vk::ImageFormatProperties properties {};
return format != vk::Format::eUndefined &&
ctx->GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal,
DepthTargetImageUsage(), vk::ImageCreateFlags {},
&properties) == vk::Result::eSuccess &&
graphics.GetImageFormatProperties(
format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, DepthTargetImageUsage(),
vk::ImageCreateFlags {}, &properties) == vk::Result::eSuccess &&
static_cast<bool>(properties.sampleCounts & required_samples);
};
if (!has_stencil) {
@@ -90,12 +88,10 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) {
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderDepthInfo* r) {
void ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderDepthInfo& r) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(r == nullptr);
(void)submit_id;
(void)buffer;
const auto& hw = buffer.GetRegisters();
const auto& z = hw.GetDepthRenderTarget();
const auto& rc = hw.GetRenderControl();
const auto& dc = hw.GetDepthControl();
@@ -232,9 +228,8 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
DepthFatal("unsupported depth/stencil format pair");
}
const auto ideal_format = DepthAttachmentFormat(*policy, has_stencil);
r->format = ResolveHostDepthAttachmentFormat(g_render_ctx->GetGraphicCtx(), *policy,
has_stencil, samples);
if (r->format == vk::Format::eUndefined) {
r.format = ResolveHostDepthAttachmentFormat(buffer, *policy, has_stencil, samples);
if (r.format == vk::Format::eUndefined) {
DepthFatal("no host depth/stencil format supports required usage for %s",
VulkanToString(ideal_format).c_str());
}
@@ -250,7 +245,7 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
TileSizeAlign stencil_size {};
TileSizeAlign htile_size {};
if (!TileGetDepthSize(width, height, 0, z.z_info.format, z.stencil_info.format, has_htile,
&stencil_size, &htile_size, &depth_size, z.z_info.num_samples) ||
stencil_size, htile_size, depth_size, z.z_info.num_samples) ||
depth_size.align != 65536 || depth_size.size == 0 ||
(has_stencil != (stencil_size.align == 65536 && stencil_size.size != 0)) ||
(has_htile != (htile_size.align == 32768 && htile_size.size != 0))) {
@@ -277,41 +272,40 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
(has_htile && htile_backing_size > TRACKER_ADDRESS_SIZE - z.htile_data_base_addr)) {
DepthFatal("layered depth backing range is invalid");
}
r->htile = has_htile;
r->width = width;
r->height = height;
r->samples = samples;
r->depth_buffer_size = depth_backing_size;
r->depth_buffer_vaddr = z.z_read_base_addr;
r->stencil_buffer_size = has_stencil ? stencil_backing_size : 0;
r->stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0;
r->htile_buffer_size = has_htile ? htile_backing_size : 0;
r->htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0;
auto* cache = g_render_ctx->GetTextureCache();
r.htile = has_htile;
r.width = width;
r.height = height;
r.samples = samples;
r.depth_buffer_size = depth_backing_size;
r.depth_buffer_vaddr = z.z_read_base_addr;
r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0;
r.stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0;
r.htile_buffer_size = has_htile ? htile_backing_size : 0;
r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0;
auto& cache = GetRenderContext().GetTextureCache();
if (has_htile) {
cache->RegisterMeta(g_render_ctx->GetGraphicCtx(), r->htile_buffer_vaddr,
r->htile_buffer_size, view.image_layers);
cache.RegisterMeta(r.htile_buffer_vaddr, r.htile_buffer_size, view.image_layers);
}
if (has_htile && rc.depth_clear_enable && !cache->ClearMeta(z.htile_data_base_addr)) {
if (has_htile && rc.depth_clear_enable && !cache.ClearMeta(z.htile_data_base_addr)) {
DepthFatal("failed to acquire HTile metadata for a depth clear");
}
const bool meta_clear =
has_htile && cache->IsMetaCleared(z.htile_data_base_addr, z.depth_view.slice_start);
r->depth_clear_enable = rc.depth_clear_enable;
r->depth_meta_clear_enable = meta_clear;
r->depth_load_clear_enable = r->depth_clear_enable || r->depth_meta_clear_enable;
r->depth_clear_value = hw.GetDepthClearValue();
r->depth_test_enable = dc.z_enable;
r->depth_write_enable = dc.z_write_enable && !z.depth_view.depth_write_disable;
r->depth_compare_op = static_cast<vk::CompareOp>(dc.zfunc);
has_htile && cache.IsMetaCleared(z.htile_data_base_addr, z.depth_view.slice_start);
r.depth_clear_enable = rc.depth_clear_enable;
r.depth_meta_clear_enable = meta_clear;
r.depth_load_clear_enable = r.depth_clear_enable || r.depth_meta_clear_enable;
r.depth_clear_value = hw.GetDepthClearValue();
r.depth_test_enable = dc.z_enable;
r.depth_write_enable = dc.z_write_enable && !z.depth_view.depth_write_disable;
r.depth_compare_op = static_cast<vk::CompareOp>(dc.zfunc);
r->depth_bounds_test_enable = dc.depth_bounds_enable;
r->depth_min_bounds = hw.GetDepthBoundsMin();
r->depth_max_bounds = hw.GetDepthBoundsMax();
r.depth_bounds_test_enable = dc.depth_bounds_enable;
r.depth_min_bounds = hw.GetDepthBoundsMin();
r.depth_max_bounds = hw.GetDepthBoundsMax();
r->stencil_clear_enable = rc.stencil_clear_enable;
r->stencil_clear_value = hw.GetStencilClearValue();
r->stencil_test_enable = dc.stencil_enable;
r.stencil_clear_enable = rc.stencil_clear_enable;
r.stencil_clear_value = hw.GetStencilClearValue();
r.stencil_test_enable = dc.stencil_enable;
if (dc.stencil_enable) {
if (dc.stencilfunc > static_cast<uint8_t>(vk::CompareOp::eAlways) ||
(dc.backface_enable &&
@@ -323,40 +317,40 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
sm.stencil_opval_bf != sm.stencil_testval_bf)) {
DepthFatal("unsupported stencil compare or replacement state");
}
r->stencil_static_front = {
r.stencil_static_front = {
ConvertStencilOp(sc.stencil_fail), ConvertStencilOp(sc.stencil_zpass),
ConvertStencilOp(sc.stencil_zfail), static_cast<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,
sm.stencil_testval};
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_zfail_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,
sm.stencil_testval_bf};
} else {
r->stencil_static_back = r->stencil_static_front;
r->stencil_dynamic_back = r->stencil_dynamic_front;
r.stencil_static_back = r.stencil_static_front;
r.stencil_dynamic_back = r.stencil_dynamic_front;
}
}
r->vaddr_num = has_stencil ? 2 : 1;
r->vaddr[0] = r->depth_buffer_vaddr;
r->size[0] = r->depth_buffer_size;
r.vaddr_num = has_stencil ? 2 : 1;
r.vaddr[0] = r.depth_buffer_vaddr;
r.size[0] = r.depth_buffer_size;
if (has_stencil) {
r->vaddr[1] = r->stencil_buffer_vaddr;
r->size[1] = r->stencil_buffer_size;
r.vaddr[1] = r.stencil_buffer_vaddr;
r.size[1] = r.stencil_buffer_size;
}
DepthTargetInfo info {};
info.address = r->depth_buffer_vaddr;
info.size = r->depth_buffer_size;
info.stencil_address = r->stencil_buffer_vaddr;
info.stencil_size = r->stencil_buffer_size;
info.htile_address = r->htile_buffer_vaddr;
info.htile_size = r->htile_buffer_size;
info.format = r->format;
info.address = r.depth_buffer_vaddr;
info.size = r.depth_buffer_size;
info.stencil_address = r.stencil_buffer_vaddr;
info.stencil_size = r.stencil_buffer_size;
info.htile_address = r.htile_buffer_vaddr;
info.htile_size = r.htile_buffer_size;
info.format = r.format;
info.guest_format = guest_format;
info.width = width;
info.height = height;
@@ -365,28 +359,28 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
info.tile_mode = Prospero::GpuEnumValue(Prospero::TileMode::kDepth);
info.layers = view.image_layers;
info.samples = samples;
info.depth_load_clear = r->depth_load_clear_enable;
info.depth_load_clear = r.depth_load_clear_enable;
info.depth_access = depth_active;
info.stencil_load_clear = rc.stencil_clear_enable;
info.stencil_access =
r->stencil_clear_enable ||
(r->stencil_test_enable &&
(stencil_face_accesses_attachment(r->stencil_static_front, r->stencil_dynamic_front) ||
stencil_face_accesses_attachment(r->stencil_static_back, r->stencil_dynamic_back)));
r.stencil_clear_enable ||
(r.stencil_test_enable &&
(stencil_face_accesses_attachment(r.stencil_static_front, r.stencil_dynamic_front) ||
stencil_face_accesses_attachment(r.stencil_static_back, r.stencil_dynamic_back)));
info.stencil_htile_compressed =
has_stencil && has_htile && !z.stencil_info.tile_stencil_disable;
r->vulkan_buffer = cache->FindDepthTarget(buffer, g_render_ctx->GetGraphicCtx(), info);
r->vulkan_view = cache->GetDepthTargetAttachmentView(
g_render_ctx->GetGraphicCtx(), r->vulkan_buffer, view.base_layer, view.layer_count);
if (r->vulkan_buffer->initial_depth_clear_pending) {
r->depth_load_clear_enable = true;
r->depth_clear_value = 0.0f;
r.vulkan_buffer = &cache.FindDepthTarget(buffer, info);
r.vulkan_view =
cache.GetDepthTargetAttachmentView(*r.vulkan_buffer, view.base_layer, view.layer_count);
if (r.vulkan_buffer->initial_depth_clear_pending) {
r.depth_load_clear_enable = true;
r.depth_clear_value = 0.0f;
}
if (r->vulkan_buffer->initial_stencil_clear_pending) {
r->stencil_clear_enable = true;
r->stencil_clear_value = 0;
if (r.vulkan_buffer->initial_stencil_clear_pending) {
r.stencil_clear_enable = true;
r.stencil_clear_value = 0;
}
if (meta_clear && !cache->TouchMeta(z.htile_data_base_addr, z.depth_view.slice_start, false)) {
if (meta_clear && !cache.TouchMeta(z.htile_data_base_addr, z.depth_view.slice_start, false)) {
DepthFatal("failed to consume HTile clear state");
}
}
@@ -395,8 +389,8 @@ void MarkRenderTargetGpuWritten(const RenderDepthInfo& target) {
const bool with_depth =
target.format != vk::Format::eUndefined && target.vulkan_buffer != nullptr;
if (with_depth && !depth_attachment_read_only(&target)) {
g_render_ctx->GetTextureCache()->MarkGpuWritten(target.vulkan_buffer);
if (with_depth && !depth_attachment_read_only(target)) {
GetRenderContext().GetTextureCache().MarkGpuWritten(*target.vulkan_buffer);
}
}
@@ -9,13 +9,9 @@
namespace Libs::Graphics {
class CommandBuffer;
class RenderCommandBuffer;
struct DepthStencilVulkanImage;
namespace HW {
class Context;
} // namespace HW
inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stencil, bool has_htile,
bool acceleration_disabled) {
return acceleration_disabled || (has_stencil && has_htile);
@@ -60,22 +56,20 @@ struct RenderDepthInfo {
int vaddr_num = 0;
};
inline bool depth_attachment_read_only(const RenderDepthInfo* depth) {
EXIT_IF(depth == nullptr);
inline bool depth_attachment_read_only(const RenderDepthInfo& depth) {
const bool stencil_write =
depth->stencil_test_enable &&
(depth->stencil_dynamic_front.writeMask != 0 || depth->stencil_dynamic_back.writeMask != 0);
return !depth->depth_load_clear_enable && !depth->stencil_clear_enable &&
!depth->depth_write_enable && !stencil_write;
depth.stencil_test_enable &&
(depth.stencil_dynamic_front.writeMask != 0 || depth.stencil_dynamic_back.writeMask != 0);
return !depth.depth_load_clear_enable && !depth.stencil_clear_enable &&
!depth.depth_write_enable && !stencil_write;
}
inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo* depth) {
inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) {
return depth_attachment_read_only(depth) ? vk::ImageLayout::eDepthStencilReadOnlyOptimal
: vk::ImageLayout::eDepthStencilAttachmentOptimal;
}
void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderDepthInfo* r);
void ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, RenderDepthInfo& r);
void MarkRenderTargetGpuWritten(const RenderDepthInfo& target);
} // namespace Libs::Graphics
@@ -76,13 +76,12 @@ std::vector<uint32_t> LayoutKey(DescriptorCache::Stage stage,
return key;
}
vk::ImageLayout SampledLayout(const VulkanImage* image) {
EXIT_IF(image == nullptr);
switch (image->layout) {
vk::ImageLayout SampledLayout(const VulkanImage& image) {
switch (image.layout) {
case vk::ImageLayout::eTransferDstOptimal:
case vk::ImageLayout::eTransferSrcOptimal:
case vk::ImageLayout::eColorAttachmentOptimal: return vk::ImageLayout::eGeneral;
default: return image->layout;
default: return image.layout;
}
}
@@ -103,9 +102,8 @@ vk::DescriptorImageInfo MakeDescriptorImageInfo(const DescriptorCache::TextureBi
} // namespace
vk::DescriptorSetLayout
DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage,
DescriptorCache::GetDescriptorSetLayoutInternal(Stage stage,
const ShaderRecompiler::IR::Program& program) {
EXIT_IF(gctx == nullptr);
const auto key = LayoutKey(stage, program);
if (const auto found = m_descriptor_set_layouts.find(key);
found != m_descriptor_set_layouts.end()) {
@@ -127,15 +125,14 @@ DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stag
info.bindingCount = static_cast<uint32_t>(bindings.size());
info.pBindings = bindings.data();
vk::DescriptorSetLayout layout = nullptr;
const auto result = gctx->device.createDescriptorSetLayout(&info, nullptr, &layout);
const auto result = m_graphics.device.createDescriptorSetLayout(&info, nullptr, &layout);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || layout == nullptr);
m_descriptor_set_layouts.emplace(key, layout);
return layout;
}
void DescriptorCache::CreatePool(GraphicContext* gctx) {
void DescriptorCache::CreatePool() {
KYTY_PROFILER_FUNCTION();
EXIT_IF(gctx == nullptr);
constexpr uint32_t MaxSets = 512;
const vk::DescriptorPoolSize sizes[] = {
{vk::DescriptorType::eStorageBuffer,
@@ -152,7 +149,7 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) {
info.maxSets = MaxSets;
const auto pool_id = static_cast<int>(m_pools.size());
auto& pool = m_pools.emplace_back();
const auto result = gctx->device.createDescriptorPool(&info, nullptr, &pool.pool);
const auto result = m_graphics.device.createDescriptorPool(&info, nullptr, &pool.pool);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool.pool == nullptr);
pool.next_free_pool = m_first_free_pool;
m_first_free_pool = pool_id;
@@ -161,10 +158,8 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) {
VulkanDescriptorSet* DescriptorCache::Allocate(Stage stage,
const ShaderRecompiler::IR::Program& program) {
KYTY_PROFILER_FUNCTION();
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
Common::LockGuard lock(m_mutex);
const auto layout = GetDescriptorSetLayoutInternal(gctx, stage, program);
const auto layout = GetDescriptorSetLayoutInternal(stage, program);
EXIT_IF(layout == nullptr);
auto& free_sets = m_free_sets_by_layout[layout];
if (!free_sets.empty()) {
@@ -186,7 +181,8 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage
info.descriptorPool = pool.pool;
info.descriptorSetCount = Batch;
info.pSetLayouts = layouts.data();
if (gctx->device.allocateDescriptorSets(&info, sets.data()) == vk::Result::eSuccess) {
if (m_graphics.device.allocateDescriptorSets(&info, sets.data()) ==
vk::Result::eSuccess) {
free_sets.reserve(free_sets.size() + Batch - 1u);
for (uint32_t i = 0; i + 1u < Batch; i++) {
free_sets.push_back(new VulkanDescriptorSet {sets[i], layout, pool_id});
@@ -196,18 +192,18 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage
m_first_free_pool = pool.next_free_pool;
break;
}
CreatePool(gctx);
CreatePool();
}
return nullptr;
}
void DescriptorCache::Recycle(VulkanDescriptorSet* set) {
EXIT_IF(set == nullptr || set->set == nullptr || set->layout == nullptr);
void DescriptorCache::Recycle(VulkanDescriptorSet& set) {
EXIT_IF(set.set == nullptr || set.layout == nullptr);
Common::LockGuard lock(m_mutex);
m_free_sets_by_layout[set->layout].push_back(set);
m_free_sets_by_layout[set.layout].push_back(&set);
}
VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage stage,
VulkanDescriptorSet& DescriptorCache::GetDescriptor(Stage stage,
const ShaderRecompiler::IR::Program& program,
const NativeDescriptors& data) {
KYTY_PROFILER_FUNCTION();
@@ -215,8 +211,6 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
data.images.size() != program.info.images.size() ||
data.samplers.size() != program.info.samplers.size() ||
data.addresses.size() != program.info.addresses.size());
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
auto* set = Allocate(stage, program);
EXIT_NOT_IMPLEMENTED(set == nullptr);
@@ -268,7 +262,7 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
const auto& texture = data.images.at(resource);
image_infos.push_back(MakeDescriptorImageInfo(
texture,
IsSampledImage(binding.kind) ? SampledLayout(texture.image) : layout));
IsSampledImage(binding.kind) ? SampledLayout(*texture.image) : layout));
}
break;
}
@@ -281,17 +275,15 @@ VulkanDescriptorSet* DescriptorCache::GetDescriptor(Stage
}
writes.push_back(write);
}
gctx->device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0,
m_graphics.device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0,
nullptr);
return set;
return *set;
}
vk::DescriptorSetLayout
DescriptorCache::GetDescriptorSetLayout(Stage stage, const ShaderRecompiler::IR::Program& program) {
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
Common::LockGuard lock(m_mutex);
return GetDescriptorSetLayoutInternal(gctx, stage, program);
return GetDescriptorSetLayoutInternal(stage, program);
}
} // namespace Libs::Graphics
@@ -63,14 +63,16 @@ public:
BufferView user_data;
};
DescriptorCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit DescriptorCache(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~DescriptorCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(DescriptorCache);
vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage,
const ShaderRecompiler::IR::Program& program);
void Recycle(VulkanDescriptorSet* set);
VulkanDescriptorSet* GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program,
void Recycle(VulkanDescriptorSet& set);
VulkanDescriptorSet& GetDescriptor(Stage stage, const ShaderRecompiler::IR::Program& program,
const NativeDescriptors& descriptors);
private:
@@ -79,12 +81,12 @@ private:
int next_free_pool = -1;
};
void CreatePool(GraphicContext* gctx);
void CreatePool();
VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program);
vk::DescriptorSetLayout
GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage,
const ShaderRecompiler::IR::Program& program);
GetDescriptorSetLayoutInternal(Stage stage, const ShaderRecompiler::IR::Program& program);
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::vector<Pool> m_pools;
int m_first_free_pool = -1;
@@ -93,7 +95,7 @@ private:
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,
const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage,
DescriptorCache::Stage stage);
+84 -147
View File
@@ -49,13 +49,10 @@ namespace Libs::Graphics {
using TextureVariant = DescriptorCache::TextureVariant;
static void BindNullStorageBuffer(CommandBuffer* cmd_buffer, BufferView* dst) {
EXIT_IF(cmd_buffer == nullptr || dst == nullptr);
dst->buffer =
g_render_ctx->GetBufferCache()->ObtainNullBuffer(cmd_buffer, g_render_ctx->GetGraphicCtx());
dst->offset = 0;
dst->range = 16;
static void BindNullStorageBuffer(CommandBuffer& cmd_buffer, BufferView& dst) {
dst.buffer = &GetRenderContext().GetBufferCache().ObtainNullBuffer(cmd_buffer);
dst.offset = 0;
dst.range = 16;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
@@ -71,21 +68,19 @@ static const char* VulkanImageTypeName(VulkanImageType type) {
}
}
static int SampledArrayViewIndex(const VulkanImage* image, int view_index) {
EXIT_IF(image == nullptr);
static int SampledArrayViewIndex(const VulkanImage& image, int view_index) {
switch (view_index) {
case VulkanImage::VIEW_DEFAULT: return VulkanImage::VIEW_DEFAULT_ARRAY;
default: return view_index;
}
}
static int SelectSampledTextureArrayView(const VulkanImage* image, int base_view) {
static int SelectSampledTextureArrayView(const VulkanImage& image, int base_view) {
const int array_view = SampledArrayViewIndex(image, base_view);
if (image->image_view[array_view] == nullptr) {
if (image.image_view[array_view] == nullptr) {
EXIT("missing sampled array image view: image_type=%s base_view=%d array_view=%d "
"layers=%u\n",
VulkanImageTypeName(image->type), base_view, array_view, image->layers);
VulkanImageTypeName(image.type), base_view, array_view, image.layers);
}
return array_view;
}
@@ -108,14 +103,14 @@ static int TextureVariantDefaultView(TextureVariant variant) {
: VulkanImage::VIEW_DEFAULT;
}
static VulkanImage* GetDummySampledTexture(TextureVariant variant) {
return g_render_ctx->GetTextureCache()->GetDummySampledTexture(TextureVariantIsUint(variant),
TextureVariantIs3D(variant));
static VulkanImage& GetDummySampledTexture(TextureVariant variant) {
return GetRenderContext().GetTextureCache().GetDummySampledTexture(
TextureVariantIsUint(variant), TextureVariantIs3D(variant));
}
static VulkanImage* GetDummyStorageTexture(TextureVariant variant) {
return g_render_ctx->GetTextureCache()->GetDummyStorageTexture(TextureVariantIsUint(variant),
TextureVariantIs3D(variant));
static VulkanImage& GetDummyStorageTexture(TextureVariant variant) {
return GetRenderContext().GetTextureCache().GetDummyStorageTexture(
TextureVariantIsUint(variant), TextureVariantIs3D(variant));
}
static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& source,
@@ -124,63 +119,11 @@ static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& so
std::copy_n(source.dwords.begin(), destination.size(), destination.begin());
}
static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer& command_buffer,
const ShaderBufferResource& descriptor,
const ShaderRecompiler::IR::BufferResource& resource) {
BufferView result;
// Regression
// Bind a null buffer when these four dwords are
// the tracked prefix of an active image sharp. Image validity is encoded by dword 3 bit 31.
/*if (resource.image_alias != ShaderRecompiler::IR::BufferResource::NoImageAlias &&
(descriptor.Type() & 2u) != 0) {
BindNullStorageBuffer(command_buffer, &result);
return result;
}
// Buffer TYPE is zero. A nonzero value means a buffer instruction received the first four
// dwords of an image sharp without a tracked image alias; support the known write-only path.
if (descriptor.Type() != 0) {
ShaderTextureResource texture {};
std::copy_n(descriptor.fields, 4, texture.fields);
const auto width = static_cast<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 stride = descriptor.Stride();
const auto records = descriptor.NumRecords();
@@ -189,34 +132,35 @@ static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command
}
const auto size = stride != 0 ? static_cast<uint64_t>(stride) * records : records;
if (address == 0 || size == 0) {
BindNullStorageBuffer(command_buffer, &result);
BindNullStorageBuffer(command_buffer, result);
return result;
}
auto* const ctx = g_render_ctx->GetGraphicCtx();
const auto alignment = ctx->StorageMinAlignment();
if (alignment == 0 || size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
const auto& graphics = GetRenderContext().GetGraphics();
const auto alignment = graphics.StorageMinAlignment();
if (alignment == 0 ||
size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
BufferCache::CACHING_PAGE_SIZE % alignment != 0) {
EXIT("storage buffer range or device alignment is unsupported\n");
}
(void)submit_id;
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
command_buffer, ctx, address, size, resource.written, resource.read, resource.formatted);
if (binding.second % alignment != 0) {
auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(
command_buffer, address, size, resource.written, resource.read, resource.formatted);
if (binding.offset % alignment != 0) {
EXIT("storage buffer binding is not device-aligned\n");
}
result.buffer = binding.first;
result.offset = binding.second;
result.buffer = &binding.buffer;
result.offset = binding.offset;
result.range = static_cast<vk::DeviceSize>(size);
return result;
}
static BufferView
NativeAddressBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
NativeAddressBuffer(uint64_t submit_id, CommandBuffer& command_buffer,
const ShaderRecompiler::IR::AddressResource& resource,
const ShaderRecompiler::IR::ResourceSnapshot::Address& address) {
BufferView result;
if (address.binding_base == 0) {
BindNullStorageBuffer(command_buffer, &result);
BindNullStorageBuffer(command_buffer, result);
return result;
}
if (resource.written) {
@@ -224,26 +168,28 @@ NativeAddressBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
}
const auto limit = resource.kind == ShaderRecompiler::IR::ResourceKind::Flat
? ShaderRecompiler::IR::FlatAddressWindowSize
: static_cast<uint64_t>(g_render_ctx->GetGraphicCtx()
->GetPhysicalDeviceProperties()
: static_cast<uint64_t>(GetRenderContext()
.GetGraphics()
.GetPhysicalDeviceProperties()
.limits.maxStorageBufferRange);
uint64_t size = 0;
const auto access = HostMemoryAccess::Mapped;
if (!HostMemoryQueryRange(address.binding_base, limit, access, &size)) {
if (!HostMemoryQueryRange(address.binding_base, limit, access, size)) {
EXIT("address resource is not host-accessible: base=0x%016" PRIx64 "\n",
address.binding_base);
}
auto* const ctx = g_render_ctx->GetGraphicCtx();
const auto alignment = ctx->StorageMinAlignment();
if (alignment == 0 || size > ctx->GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
const auto& graphics = GetRenderContext().GetGraphics();
const auto alignment = graphics.StorageMinAlignment();
if (alignment == 0 ||
size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange ||
BufferCache::GetBufferOffset(address.binding_base) % alignment != 0) {
EXIT("address resource range or alignment is unsupported\n");
}
(void)submit_id;
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(command_buffer, ctx,
auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(command_buffer,
address.binding_base, size);
result.buffer = binding.first;
result.offset = binding.second;
result.buffer = &binding.buffer;
result.offset = binding.offset;
result.range = static_cast<vk::DeviceSize>(size);
return result;
}
@@ -529,7 +475,7 @@ void ValidateMetadataReuseTexture(const ShaderRecompiler::IR::ImageResource& res
}
static DescriptorCache::TextureBinding
NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
NativeTexture(uint64_t submit_id, CommandBuffer& command_buffer,
const ShaderRecompiler::IR::ImageResource& resource,
const ShaderRecompiler::IR::DescriptorValue& value) {
ShaderTextureResource descriptor;
@@ -541,9 +487,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
ValidateStorageImageResource(resource);
}
if (descriptor.IsNull()) {
return storage ? DescriptorCache::TextureBinding {GetDummyStorageTexture(variant),
return storage ? DescriptorCache::TextureBinding {&GetDummyStorageTexture(variant),
TextureVariantDefaultView(variant)}
: DescriptorCache::TextureBinding {GetDummySampledTexture(variant),
: DescriptorCache::TextureBinding {&GetDummySampledTexture(variant),
TextureVariantDefaultView(variant)};
}
const auto address = descriptor.Base40();
@@ -578,12 +524,12 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
const auto swizzle = descriptor.DstSelXYZW();
TileSizeAlign size;
TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile,
type == Prospero::ImageType::kColor3D, &size);
type == Prospero::ImageType::kColor3D, size);
EXIT_NOT_IMPLEMENTED(size.size == 0 ||
(address & (static_cast<uint64_t>(size.align) - 1u)) != 0);
if (storage) {
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);
}
@@ -594,11 +540,11 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
descriptor.MsaaDepth();
if (image == nullptr) {
if (check_depth) {
image = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(command_buffer, address,
size.size, true);
image = GetRenderContext().GetTextureCache().FindDepthTargetByRange(
command_buffer, address, size.size, true);
} else {
image = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(command_buffer,
address, size.size);
image = GetRenderContext().GetTextureCache().FindRenderTargetByRange(
command_buffer, address, size.size);
}
if (image != nullptr) {
if (check_depth) {
@@ -628,10 +574,9 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
static_cast<uint32_t>(resource.dimension), descriptor.Type(),
descriptor.BaseArray5(), image->layers);
}
image_view = g_render_ctx->GetTextureCache()->GetDepthTargetSampledView(
g_render_ctx->GetGraphicCtx(), static_cast<DepthStencilVulkanImage*>(image),
view_format, swizzle, 0, 1, depth_view.type, depth_view.base_layer,
depth_view.layer_count);
image_view = GetRenderContext().GetTextureCache().GetDepthTargetSampledView(
*static_cast<DepthStencilVulkanImage*>(image), view_format, swizzle, 0, 1,
depth_view.type, depth_view.base_layer, depth_view.layer_count);
}
} else {
if (!(storage ? IsSupportedStorageImageResource(resource)
@@ -657,23 +602,21 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
}
if (storage) {
view = SelectStorageColorView(image->format, view_format, swizzle);
image_view = g_render_ctx->GetTextureCache()->GetRenderTargetStorageView(
g_render_ctx->GetGraphicCtx(),
static_cast<RenderTextureVulkanImage*>(image), view_format, base_level,
image_view = GetRenderContext().GetTextureCache().GetRenderTargetStorageView(
*static_cast<RenderTextureVulkanImage*>(image), view_format, base_level,
view_levels, target_view.type, target_view.base_layer,
target_view.layer_count);
} else {
image_view = g_render_ctx->GetTextureCache()->GetSampledColorView(
g_render_ctx->GetGraphicCtx(), image, view_format, swizzle, base_level,
view_levels, target_view.type, target_view.base_layer,
target_view.layer_count);
image_view = GetRenderContext().GetTextureCache().GetSampledColorView(
*image, view_format, swizzle, base_level, view_levels, target_view.type,
target_view.base_layer, target_view.layer_count);
}
}
if (image != nullptr && image_view == nullptr && image->image_view[view] == nullptr) {
EXIT("required cached texture image view is missing\n");
}
if (storage && image != nullptr) {
g_render_ctx->GetTextureCache()->MarkGpuWritten(image);
GetRenderContext().GetTextureCache().MarkGpuWritten(*image);
}
}
}
@@ -701,7 +644,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
}
image = video.image;
view = VulkanImage::VIEW_STORAGE;
g_render_ctx->GetTextureCache()->MarkGpuWritten(image);
GetRenderContext().GetTextureCache().MarkGpuWritten(*image);
} else {
const bool exact =
IsSupportedSampledVideoOutView(resource, descriptor, *video.image) &&
@@ -721,15 +664,14 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
static_cast<uint32_t>(type), size.size, video.size, pitch, video.pitch);
}
image = video.image;
image_view = g_render_ctx->GetTextureCache()->GetSampledColorView(
g_render_ctx->GetGraphicCtx(), video.image, view_format, swizzle, 0, 1,
vk::ImageViewType::e2D, 0, 1);
image_view = GetRenderContext().GetTextureCache().GetSampledColorView(
*video.image, view_format, swizzle, 0, 1, vk::ImageViewType::e2D, 0, 1);
}
}
}
if (image == nullptr) {
auto* texture_cache = g_render_ctx->GetTextureCache();
const bool metadata_read = texture_cache->QueryRegion(address, size.size).metadata_pages;
auto& texture_cache = GetRenderContext().GetTextureCache();
const bool metadata_read = texture_cache.QueryRegion(address, size.size).metadata_pages;
if (storage && metadata_read) {
EXIT("storage texture overlaps surface metadata\n");
}
@@ -754,19 +696,15 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
info.type = descriptor.Type();
info.base_array = descriptor.BaseArray5();
if (storage) {
image = texture_cache->FindStorageTexture(command_buffer, g_render_ctx->GetGraphicCtx(),
info);
image = &texture_cache.FindStorageTexture(command_buffer, info);
view = VulkanImage::VIEW_DEFAULT;
image_view = texture_cache->GetStorageTextureStorageView(
g_render_ctx->GetGraphicCtx(), static_cast<StorageTextureVulkanImage*>(image),
base_level);
image_view = texture_cache.GetStorageTextureStorageView(
*static_cast<StorageTextureVulkanImage*>(image), base_level);
} else {
image = texture_cache->FindTexture(command_buffer, g_render_ctx->GetGraphicCtx(), info,
metadata_read);
image = &texture_cache.FindTexture(command_buffer, info, metadata_read);
if (image->type == VulkanImageType::StorageTexture) {
image_view = texture_cache->GetStorageTextureSampledView(
g_render_ctx->GetGraphicCtx(), static_cast<StorageTextureVulkanImage*>(image),
info);
image_view = texture_cache.GetStorageTextureSampledView(
*static_cast<StorageTextureVulkanImage*>(image), info);
}
}
}
@@ -774,7 +712,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
if (NeedsStaticSampledArrayView(resource.dimension ==
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray,
image_view != nullptr)) {
view = SelectSampledTextureArrayView(image, view);
view = SelectSampledTextureArrayView(*image, view);
}
return {image, view, image_view};
}
@@ -792,31 +730,31 @@ static vk::Sampler NativeSampler(const ShaderRecompiler::IR::Program& program, u
if (!depth_compare) {
descriptor.fields[0] &= ~(0x7u << 12u);
}
return g_render_ctx->GetSamplerCache()->GetSampler(descriptor);
return GetRenderContext().GetSamplerCache().GetSampler(descriptor);
}
static BufferView NativeUpload(CommandBuffer* command_buffer, std::span<const uint32_t> data) {
static BufferView NativeUpload(CommandBuffer& command_buffer, std::span<const uint32_t> data) {
EXIT_IF(data.empty());
BufferView result;
EXIT_IF(!g_render_ctx->GetBufferCache()->UploadHostData(
command_buffer, g_render_ctx->GetGraphicCtx(), data.data(), data.size_bytes(), 256,
&result.buffer, &result.offset, &result.range));
EXIT_IF(!GetRenderContext().GetBufferCache().UploadHostData(
command_buffer, data.data(), data.size_bytes(), 256, result.buffer, result.offset,
result.range));
return result;
}
void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
void BindDescriptors(uint64_t submit_id, CommandBuffer& buffer,
vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout,
const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage,
DescriptorCache::Stage stage) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(buffer == nullptr || !runtime);
EXIT_IF(!runtime);
const auto& program = *runtime.program;
const auto& snapshot = *runtime.resources;
std::string error;
if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) {
EXIT("invalid native shader runtime snapshot: %s\n", error.c_str());
}
auto vk_buffer = buffer->Handle();
auto vk_buffer = buffer.Handle();
const auto shader_stages = ShaderPipelineStages(vk_stage);
DescriptorCache::NativeDescriptors descriptors;
@@ -864,8 +802,7 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
}
if (ShaderRecompiler::IR::FindBinding(
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) {
descriptors.gds.buffer =
g_render_ctx->GetGdsBuffer()->GetBuffer(g_render_ctx->GetGraphicCtx());
descriptors.gds.buffer = &GetRenderContext().GetGdsBuffer().GetBuffer();
const auto barrier = MakeGdsDependency(*descriptors.gds.buffer);
vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eHost | vk::PipelineStageFlagBits::eTransfer |
@@ -880,14 +817,14 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) {
switch (image->type) {
case VulkanImageType::DepthStencil:
GraphicsRenderDepthStencilBarrier(vk_buffer, image);
GraphicsRenderDepthStencilBarrier(vk_buffer, *image);
break;
case VulkanImageType::RenderTexture:
case VulkanImageType::StorageTexture:
GraphicsRenderTextureBarrier(vk_buffer, image);
GraphicsRenderTextureBarrier(vk_buffer, *image);
break;
case VulkanImageType::VideoOut:
GraphicsRenderColorImageBarrier(vk_buffer, image, RENDER_COLOR_IMAGE_LAYOUT);
GraphicsRenderColorImageBarrier(vk_buffer, *image, RENDER_COLOR_IMAGE_LAYOUT);
break;
default: break;
}
@@ -901,11 +838,11 @@ void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
}
if (!program.bindings.descriptors.empty()) {
auto* set = g_render_ctx->GetDescriptorCache()->GetDescriptor(stage, program, descriptors);
EXIT_IF(set == nullptr);
auto& set =
GetRenderContext().GetDescriptorCache().GetDescriptor(stage, program, descriptors);
vk_buffer.bindDescriptorSets(pipeline_bind_point, layout, program.bindings.descriptor_set,
1, &set->set, 0, nullptr);
buffer->RecycleDescriptorAfterFence(set);
1, &set.set, 0, nullptr);
buffer.RecycleDescriptorAfterFence(set);
}
if (program.bindings.push_constant_size != 0) {
EXIT_IF(program.bindings.push_constant_size != user_data.size() * sizeof(uint32_t));
@@ -4,6 +4,8 @@
#include "graphics/host_gpu/renderer/image.h"
#include "graphics/host_gpu/transfer.h"
#include <algorithm>
namespace Libs::Graphics {
namespace {
@@ -16,15 +18,17 @@ namespace {
DummyTextureCache::~DummyTextureCache() {
Common::LockGuard lock(m_mutex);
if (m_ctx == nullptr) {
const auto populated = [](const auto& slots) {
return std::ranges::any_of(slots, [](const auto& slot) { return slot.image != nullptr; });
};
if (!populated(m_sampled) && !populated(m_storage)) {
return;
}
Transfer::WaitForGraphicsIdle(m_ctx);
const auto destroy = [this](auto& slots) {
Transfer::WaitForGraphicsIdle();
const auto destroy = [](auto& slots) {
for (auto& slot: slots) {
if (slot.image != nullptr) {
ImageOps::Destroy(m_ctx, slot.image);
ImageOps::Destroy(*slot.image);
slot.image = nullptr;
}
}
@@ -33,26 +37,15 @@ DummyTextureCache::~DummyTextureCache() {
destroy(m_storage);
}
VulkanImage* DummyTextureCache::Get(GraphicContext* ctx, Usage usage, bool uint_format,
bool image_3d) {
VulkanImage& DummyTextureCache::Get(Usage usage, bool uint_format, bool image_3d) {
Common::LockGuard lock(m_mutex);
if (ctx == nullptr) {
EXIT("TextureCache: dummy texture requires a graphics context\n");
}
if (m_ctx != nullptr && m_ctx != ctx) {
EXIT("TextureCache: dummy texture context changed, previous=%p current=%p usage=%u\n",
static_cast<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& slot = slots[DummyTextureIndex(uint_format, image_3d)];
if (slot.image == nullptr) {
slot.image =
ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, usage == Usage::Storage);
slot.image = ImageOps::CreateDummyTexture(uint_format, image_3d,
usage == Usage::Storage);
}
return slot.image;
return *slot.image;
}
} // namespace Libs::Graphics
@@ -18,8 +18,7 @@ public:
~DummyTextureCache();
KYTY_CLASS_NO_COPY(DummyTextureCache);
[[nodiscard]] VulkanImage* Get(GraphicContext* ctx, Usage usage, bool uint_format,
bool image_3d);
[[nodiscard]] VulkanImage& Get(Usage usage, bool uint_format, bool image_3d);
private:
struct Slot {
@@ -29,7 +28,6 @@ private:
Common::Mutex m_mutex;
std::array<Slot, 4> m_sampled {};
std::array<Slot, 4> m_storage {};
GraphicContext* m_ctx = nullptr;
};
} // namespace Libs::Graphics
@@ -15,17 +15,15 @@ namespace Libs::Graphics {
VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
uint32_t requested_color_count,
RenderDepthInfo* depth) {
RenderDepthInfo& depth) {
KYTY_PROFILER_FUNCTION();
Common::LockGuard lock(m_mutex);
EXIT_IF(colors == nullptr);
EXIT_IF(depth == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(requested_color_count > RENDER_COLOR_ATTACHMENTS_MAX);
bool with_depth = (depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr);
bool with_depth = (depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr);
bool with_color[RENDER_COLOR_ATTACHMENTS_MAX] = {};
uint32_t color_count = 0;
VulkanImage* first_color = nullptr;
@@ -58,16 +56,16 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
color_count++;
}
if (with_depth) {
if (depth->samples != depth->vulkan_buffer->samples) {
if (depth.samples != depth.vulkan_buffer->samples) {
EXIT("Framebuffer: depth attachment sample identity mismatch, requested=%u image=%u\n",
depth->samples, depth->vulkan_buffer->samples);
depth.samples, depth.vulkan_buffer->samples);
}
if (attachment_samples == 0) {
attachment_samples = depth->samples;
} else if (attachment_samples != depth->samples) {
attachment_samples = depth.samples;
} else if (attachment_samples != depth.samples) {
EXIT(
"Framebuffer: mixed color/depth sample counts are unsupported, color=%u depth=%u\n",
attachment_samples, depth->samples);
attachment_samples, depth.samples);
}
}
if (!with_depth && color_count == 0) {
@@ -87,26 +85,26 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
(with_depth && depth_layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal);
if (with_depth && first_color != nullptr &&
(first_color_extent.width != depth->vulkan_buffer->extent.width ||
first_color_extent.height != depth->vulkan_buffer->extent.height)) {
(first_color_extent.width != depth.vulkan_buffer->extent.width ||
first_color_extent.height != depth.vulkan_buffer->extent.height)) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF("Framebuffer: temporary: dropping mismatched PS5 depth attachment color=%ux%u "
"depth=%ux%u format=%s\n",
first_color_extent.width, first_color_extent.height,
depth->vulkan_buffer->extent.width, depth->vulkan_buffer->extent.height,
VulkanToString(depth->format).c_str());
depth.vulkan_buffer->extent.width, depth.vulkan_buffer->extent.height,
VulkanToString(depth.format).c_str());
}
depth->format = vk::Format::eUndefined;
depth->vulkan_buffer = nullptr;
depth->vulkan_view = nullptr;
depth->depth_test_enable = false;
depth->depth_write_enable = false;
depth->depth_bounds_test_enable = false;
depth->stencil_test_enable = false;
depth->depth_clear_enable = false;
depth->depth_load_clear_enable = false;
depth->stencil_clear_enable = false;
depth.format = vk::Format::eUndefined;
depth.vulkan_buffer = nullptr;
depth.vulkan_view = nullptr;
depth.depth_test_enable = false;
depth.depth_write_enable = false;
depth.depth_bounds_test_enable = false;
depth.stencil_test_enable = false;
depth.depth_clear_enable = false;
depth.depth_load_clear_enable = false;
depth.stencil_clear_enable = false;
with_depth = false;
depth_layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
depth_read_only = false;
@@ -125,22 +123,21 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
(i < color_count && with_color[i] && colors[i].color_clear_enable) &&
f.color_layout[i] == color_layout[i];
}
if (color_match &&
f.depth_id == (with_depth ? depth->vulkan_buffer->memory.unique_id : 0) &&
f.depth_view == (with_depth ? depth->vulkan_view : nullptr) &&
f.depth_clear_enable == depth->depth_load_clear_enable &&
f.stencil_clear_enable == depth->stencil_clear_enable &&
if (color_match && f.depth_id == (with_depth ? depth.vulkan_buffer->memory.unique_id : 0) &&
f.depth_view == (with_depth ? depth.vulkan_view : nullptr) &&
f.depth_clear_enable == depth.depth_load_clear_enable &&
f.stencil_clear_enable == depth.stencil_clear_enable &&
f.depth_read_only == depth_read_only) {
return f.framebuffer;
}
}
EXIT_NOT_IMPLEMENTED(with_depth && first_color != nullptr &&
(first_color_extent.width != depth->vulkan_buffer->extent.width ||
first_color_extent.height != depth->vulkan_buffer->extent.height));
(first_color_extent.width != depth.vulkan_buffer->extent.width ||
first_color_extent.height != depth.vulkan_buffer->extent.height));
if (first_color == nullptr) {
first_color_extent = depth->vulkan_buffer->extent;
first_color_extent = depth.vulkan_buffer->extent;
}
auto* framebuffer = new VulkanFramebuffer;
@@ -152,10 +149,6 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
}
framebuffer->depth_layout = depth_layout;
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
vk::AttachmentDescription attachments[RENDER_COLOR_ATTACHMENTS_MAX + 1] = {};
for (uint32_t i = 0; i < color_count; i++) {
attachments[i].flags = {};
@@ -172,14 +165,14 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
const uint32_t depth_attachment = color_count;
attachments[depth_attachment].flags = {};
attachments[depth_attachment].format = depth->format;
attachments[depth_attachment].format = depth.format;
attachments[depth_attachment].samples = vulkan_sample_count(attachment_samples);
attachments[depth_attachment].loadOp =
(depth->depth_load_clear_enable ? vk::AttachmentLoadOp::eClear
(depth.depth_load_clear_enable ? vk::AttachmentLoadOp::eClear
: vk::AttachmentLoadOp::eLoad);
attachments[depth_attachment].storeOp = vk::AttachmentStoreOp::eStore;
attachments[depth_attachment].stencilLoadOp =
(depth->stencil_clear_enable ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad);
(depth.stencil_clear_enable ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad);
attachments[depth_attachment].stencilStoreOp = vk::AttachmentStoreOp::eStore;
attachments[depth_attachment].initialLayout = depth_layout;
attachments[depth_attachment].finalLayout = depth_layout;
@@ -246,7 +239,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
render_pass_info.pDependencies = dependencies;
auto result =
gctx->device.createRenderPass(&render_pass_info, nullptr, &framebuffer->render_pass);
m_graphics.device.createRenderPass(&render_pass_info, nullptr, &framebuffer->render_pass);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
vk::Format color_formats[RENDER_COLOR_ATTACHMENTS_MAX] = {};
@@ -254,7 +247,7 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
color_formats[i] = colors[i].format;
}
framebuffer->render_pass_id = render_pass_compat_id(
color_count, color_formats, with_depth, depth->format, depth_layout, attachment_samples);
color_count, color_formats, with_depth, depth.format, depth_layout, attachment_samples);
EXIT_NOT_IMPLEMENTED(framebuffer->render_pass == nullptr);
@@ -266,10 +259,10 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
views[i] = colors[i].vulkan_view;
}
if (with_depth) {
if (depth->vulkan_view == nullptr) {
if (depth.vulkan_view == nullptr) {
EXIT("Framebuffer: depth attachment view is missing\n");
}
views[color_count] = depth->vulkan_view;
views[color_count] = depth.vulkan_view;
}
vk::FramebufferCreateInfo framebuffer_info {};
@@ -283,7 +276,8 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
framebuffer_info.height = first_color_extent.height;
framebuffer_info.layers = 1;
result = gctx->device.createFramebuffer(&framebuffer_info, nullptr, &framebuffer->framebuffer);
result =
m_graphics.device.createFramebuffer(&framebuffer_info, nullptr, &framebuffer->framebuffer);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(framebuffer->framebuffer == nullptr);
@@ -298,10 +292,10 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
(i < color_count && with_color[i] && colors[i].color_clear_enable);
fnew.color_layout[i] = color_layout[i];
}
fnew.depth_id = (with_depth ? depth->vulkan_buffer->memory.unique_id : 0);
fnew.depth_view = (with_depth ? depth->vulkan_view : nullptr);
fnew.depth_clear_enable = depth->depth_load_clear_enable;
fnew.stencil_clear_enable = depth->stencil_clear_enable;
fnew.depth_id = (with_depth ? depth.vulkan_buffer->memory.unique_id : 0);
fnew.depth_view = (with_depth ? depth.vulkan_view : nullptr);
fnew.depth_clear_enable = depth.depth_load_clear_enable;
fnew.stencil_clear_enable = depth.stencil_clear_enable;
fnew.depth_read_only = depth_read_only;
bool updated = false;
@@ -321,28 +315,21 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
return framebuffer;
}
void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(image == nullptr);
void FramebufferCache::FreeFramebufferByColor(VulkanImage& image) {
Common::LockGuard lock(m_mutex);
for (auto& f: m_framebuffers) {
bool uses_image = false;
for (auto image_id: f.image_id) {
if (image_id == image->memory.unique_id) {
if (image_id == image.memory.unique_id) {
uses_image = true;
break;
}
}
if (f.framebuffer != nullptr && uses_image) {
auto* gctx = g_render_ctx->GetGraphicCtx();
m_graphics.device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
EXIT_IF(gctx == nullptr);
gctx->device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
gctx->device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
m_graphics.device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
delete f.framebuffer;
@@ -351,21 +338,14 @@ void FramebufferCache::FreeFramebufferByColor(VulkanImage* image) {
}
}
void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage* image) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(image == nullptr);
void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage& image) {
Common::LockGuard lock(m_mutex);
for (auto& f: m_framebuffers) {
if (f.framebuffer != nullptr && f.depth_id == image->memory.unique_id) {
auto* gctx = g_render_ctx->GetGraphicCtx();
if (f.framebuffer != nullptr && f.depth_id == image.memory.unique_id) {
m_graphics.device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
EXIT_IF(gctx == nullptr);
gctx->device.destroyFramebuffer(f.framebuffer->framebuffer, nullptr);
gctx->device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
m_graphics.device.destroyRenderPass(f.framebuffer->render_pass, nullptr);
delete f.framebuffer;
@@ -50,14 +50,16 @@ inline uint64_t render_pass_compat_id(uint32_t color_count, const vk::Format* co
class FramebufferCache {
public:
FramebufferCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit FramebufferCache(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~FramebufferCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FramebufferCache);
VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth);
void FreeFramebufferByColor(VulkanImage* image);
void FreeFramebufferByDepth(DepthStencilVulkanImage* image);
RenderDepthInfo& depth);
void FreeFramebufferByColor(VulkanImage& image);
void FreeFramebufferByDepth(DepthStencilVulkanImage& image);
private:
struct Framebuffer {
@@ -73,6 +75,7 @@ private:
bool depth_read_only = false;
};
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::vector<Framebuffer> m_framebuffers;
};
+13 -16
View File
@@ -6,7 +6,7 @@
namespace Libs::Graphics {
void GdsBuffer::Init(GraphicContext* ctx) {
void GdsBuffer::Init() {
if (m_buffer == nullptr) {
m_buffer = std::make_unique<VulkanBuffer>();
@@ -14,57 +14,54 @@ void GdsBuffer::Init(GraphicContext* ctx) {
m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, DW_SIZE * 4, m_buffer.get());
m_graphics.CreateBuffer(DW_SIZE * 4, *m_buffer);
}
}
void GdsBuffer::Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num,
uint32_t clear_value) {
EXIT_IF(ctx == nullptr);
void GdsBuffer::Clear(uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value) {
Common::LockGuard lock(m_mutex);
Init(ctx);
Init();
EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE);
EXIT_NOT_IMPLEMENTED(dw_offset + dw_num > DW_SIZE);
void* data = nullptr;
VulkanMapMemory(ctx, &m_buffer->memory, &data);
m_graphics.MapMemory(m_buffer->memory, data);
for (uint32_t i = 0; i < dw_num; i++) {
static_cast<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);
Common::LockGuard lock(m_mutex);
Init(ctx);
Init();
EXIT_NOT_IMPLEMENTED(dw_offset >= DW_SIZE);
EXIT_NOT_IMPLEMENTED(dw_offset + dw_size > DW_SIZE);
void* data = nullptr;
VulkanMapMemory(ctx, &m_buffer->memory, &data);
m_graphics.MapMemory(m_buffer->memory, data);
for (uint32_t i = 0; i < dw_size; i++) {
dst[i] = static_cast<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);
Init(ctx);
Init();
return m_buffer.get();
return *m_buffer;
}
} // namespace Libs::Graphics
+8 -5
View File
@@ -13,20 +13,23 @@ namespace Libs::Graphics {
class GdsBuffer {
public:
GdsBuffer() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit GdsBuffer(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~GdsBuffer() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(GdsBuffer);
void Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value);
void Read(GraphicContext* ctx, uint32_t* dst, uint32_t dw_offset, uint32_t dw_size);
void Clear(uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value);
void Read(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size);
VulkanBuffer* GetBuffer(GraphicContext* ctx);
VulkanBuffer& GetBuffer();
private:
static constexpr uint64_t DW_SIZE = 0x3000;
void Init(GraphicContext* ctx);
void Init();
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::unique_ptr<VulkanBuffer> m_buffer;
};
@@ -9,9 +9,9 @@
namespace Libs::Graphics {
GpuResourceManager::GpuResourceManager()
: m_page_manager(FaultThunk, this), m_buffer_cache(m_page_manager, m_resource_mutex),
m_texture_cache(m_page_manager, m_buffer_cache, m_resource_mutex) {
GpuResourceManager::GpuResourceManager(GraphicContext& graphics)
: m_page_manager(FaultThunk, this), m_buffer_cache(graphics, m_page_manager, m_resource_mutex),
m_texture_cache(graphics, m_page_manager, m_buffer_cache, m_resource_mutex) {
m_buffer_cache.SetTextureCache(m_texture_cache);
}
@@ -72,8 +72,7 @@ void GpuResourceManager::PrepareHostWrite(uint64_t vaddr, uint64_t size) {
}
const auto handle_range = [this, vaddr, size]() {
if (!m_page_manager.HandleWriteRange(vaddr, size)) {
EXIT("failed to prepare host write, addr=0x%016" PRIx64 " size=0x%016" PRIx64
"\n",
EXIT("failed to prepare host write, addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
vaddr, size);
}
};
@@ -113,22 +112,22 @@ void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size, GpuAccess ac
m_page_manager.OnGpuUnmap(vaddr, size, access);
}
void GpuResourceManager::FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size,
void GpuResourceManager::FillBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size,
uint32_t value) {
if (g_render_ctx == nullptr || command == nullptr || command->IsInvalid()) {
if (command.IsInvalid()) {
EXIT("cannot fill a buffer without a valid render command context\n");
}
Common::LockGuard lock(g_render_ctx->GetMutex());
m_buffer_cache.FillBuffer(command, g_render_ctx->GetGraphicCtx(), vaddr, size, value);
Common::LockGuard lock(GetRenderContext().GetMutex());
m_buffer_cache.FillBuffer(&command, vaddr, size, value);
}
void GpuResourceManager::CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr,
void GpuResourceManager::CopyBuffer(CommandBuffer& command, uint64_t dst_vaddr, uint64_t src_vaddr,
uint64_t size) {
if (g_render_ctx == nullptr || command == nullptr || command->IsInvalid()) {
if (command.IsInvalid()) {
EXIT("cannot copy a buffer without a valid render command context\n");
}
Common::LockGuard lock(g_render_ctx->GetMutex());
m_buffer_cache.CopyBuffer(command, g_render_ctx->GetGraphicCtx(), dst_vaddr, src_vaddr, size);
Common::LockGuard lock(GetRenderContext().GetMutex());
m_buffer_cache.CopyBuffer(&command, dst_vaddr, src_vaddr, size);
}
} // namespace Libs::Graphics
@@ -16,20 +16,20 @@ class CommandBuffer;
class GpuResourceManager {
public:
GpuResourceManager();
explicit GpuResourceManager(GraphicContext& graphics);
~GpuResourceManager();
KYTY_CLASS_NO_COPY(GpuResourceManager);
[[nodiscard]] BufferCache* GetBufferCache() { return &m_buffer_cache; }
[[nodiscard]] TextureCache* GetTextureCache() { return &m_texture_cache; }
[[nodiscard]] BufferCache& GetBufferCache() { return m_buffer_cache; }
[[nodiscard]] TextureCache& GetTextureCache() { return m_texture_cache; }
[[nodiscard]] bool HandleFault(PageFaultAccess access, uint64_t fault_vaddr) noexcept;
void PrepareHostWrite(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsMapped(uint64_t vaddr, uint64_t size) const noexcept;
void MapMemory(uint64_t vaddr, uint64_t size, GpuAccess access);
void UnmapMemory(uint64_t vaddr, uint64_t size, GpuAccess access);
void FillBuffer(CommandBuffer* command, uint64_t vaddr, uint64_t size, uint32_t value);
void CopyBuffer(CommandBuffer* command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);
void FillBuffer(CommandBuffer& command, uint64_t vaddr, uint64_t size, uint32_t value);
void CopyBuffer(CommandBuffer& command, uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size);
private:
static bool FaultThunk(void* context, PageFaultAccess access, uint64_t vaddr, uint64_t size,
+88 -86
View File
@@ -50,15 +50,15 @@ TextureImageCreateParams MakeImageParams(const ImageInfo& info, bool storage) {
return params;
}
bool RenderTargetSupportsStorage(GraphicContext* ctx, vk::Format format,
bool RenderTargetSupportsStorage(vk::Format format,
vk::ImageCreateFlags flags) {
const auto compatible = SrgbStorageViewFormat(format);
const auto required_flags =
vk::ImageCreateFlagBits::eMutableFormat | vk::ImageCreateFlagBits::eExtendedUsage;
const bool compatible_views = (flags & required_flags) == required_flags;
return ImageViewOps::FormatSupportsStorage(ctx, format) ||
return ImageViewOps::FormatSupportsStorage(format) ||
(compatible_views && compatible != vk::Format::eUndefined &&
ImageViewOps::FormatSupportsStorage(ctx, compatible));
ImageViewOps::FormatSupportsStorage(compatible));
}
vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) {
@@ -72,20 +72,21 @@ vk::ImageCreateFlags RenderTargetCreateFlags(vk::Format format) {
: vk::ImageCreateFlags {0};
}
vk::ImageUsageFlags RenderTargetUsage(GraphicContext* ctx, vk::Format format,
vk::ImageUsageFlags RenderTargetUsage(vk::Format format,
vk::ImageCreateFlags flags, uint32_t samples) {
auto& graphics = GetRenderContext().GetGraphics();
auto usage = static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eColorAttachment) |
static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eTransferSrc) |
static_cast<vk::ImageUsageFlags>(vk::ImageUsageFlagBits::eTransferDst);
if (samples == 1) {
usage |= vk::ImageUsageFlagBits::eSampled;
if (RenderTargetSupportsStorage(ctx, format, flags)) {
if (RenderTargetSupportsStorage(format, flags)) {
usage |= vk::ImageUsageFlagBits::eStorage;
}
}
vk::ImageFormatProperties properties {};
if (ctx->GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, usage,
flags, &properties) != vk::Result::eSuccess ||
if (graphics.GetImageFormatProperties(format, vk::ImageType::e2D, vk::ImageTiling::eOptimal,
usage, flags, &properties) != vk::Result::eSuccess ||
!static_cast<bool>(properties.sampleCounts & vulkan_sample_count(samples))) {
EXIT("TextureCache: render-target format does not support required usage, format=%d "
"usage=0x%x samples=%u supported=0x%x\n",
@@ -146,44 +147,42 @@ uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element) {
return RenderTargetTransferFormatImpl(bytes_per_element);
}
GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage,
vk::ComponentMapping* components) {
if (components == nullptr) {
EXIT("TextureCache: invalid texture component output\n");
}
GpuTextureVulkanImage* CreateTexture(const ImageInfo& info, bool storage,
vk::ComponentMapping& components) {
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
: new TextureVulkanImage;
*components = TextureCreateImage(ctx, image, MakeImageParams(info, storage));
components = TextureCreateImage(*image, MakeImageParams(info, storage));
return image;
}
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
bool storage, vk::ComponentMapping components) {
void CreateTextureViews(GpuTextureVulkanImage& image,
const ImageInfo& info, bool storage, vk::ComponentMapping components) {
if (storage) {
TextureCreateImageViews(ctx, image, components, info.type, 0, 0, 1, info.depth, false,
TextureCreateImageViews(image, components, info.type, 0, 0, 1, info.depth, false,
TextureFormatUsage::Sampled | TextureFormatUsage::Storage);
} else {
TextureCreateImageViews(ctx, image, components, info.type, info.base_array, info.base_level,
info.view_levels, info.depth, true, TextureFormatUsage::Sampled);
TextureCreateImageViews(image, components, info.type, info.base_array,
info.base_level, info.view_levels, info.depth, true,
TextureFormatUsage::Sampled);
}
}
void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image,
void UploadRenderTargetLayers(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, uint32_t base_layer,
uint32_t layer_count, bool refresh) {
if (info.layers == 0 || info.size % info.layers != 0 || layer_count == 0 ||
base_layer >= info.layers || layer_count > info.layers - base_layer || image == nullptr ||
base_layer >= image->layers || layer_count > image->layers - base_layer) {
base_layer >= info.layers || layer_count > info.layers - base_layer ||
base_layer >= image.layers || layer_count > image.layers - base_layer) {
EXIT("TextureCache: invalid render-target layer upload, base=%u count=%u "
"info_layers=%u image_layers=%u size=0x%016" PRIx64 "\n",
base_layer, layer_count, info.layers, image != nullptr ? image->layers : 0, info.size);
base_layer, layer_count, info.layers, image.layers, info.size);
}
if (info.samples != 1 || image->samples != 1) {
if (info.samples != 1 || image.samples != 1) {
EXIT("TextureCache: multisampled render-target upload is unsupported, samples=%u/%u\n",
info.samples, image->samples);
info.samples, image.samples);
}
if (refresh) {
Transfer::WaitForGraphicsIdle(ctx);
Transfer::WaitForGraphicsIdle();
}
const auto slice_size = info.size / info.layers;
const auto upload_size = slice_size * layer_count;
@@ -208,7 +207,7 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
region.dst_layer += base_layer;
}
const auto source_address = info.address + slice_size * base_layer;
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(source_address),
TextureUploadGuestImage(image, reinterpret_cast<const void*>(source_address),
upload_size, regions, layout, format, info.width, info.height,
layer_count, info.levels, "TextureCache render target",
vk::ImageLayout::eGeneral);
@@ -222,21 +221,23 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
"TextureCache render target");
auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1,
true, false, TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size,
regions, layout, format, info.width, info.height, 1, 1,
TextureUploadGuestImage(image, reinterpret_cast<const void*>(info.address),
slice_size, regions, layout, format, info.width, info.height, 1, 1,
"TextureCache render target", vk::ImageLayout::eGeneral);
} else {
Transfer::UploadImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size,
info.pitch, vk::ImageLayout::eGeneral);
Transfer::UploadImage(image, reinterpret_cast<const void*>(info.address),
slice_size, info.pitch, vk::ImageLayout::eGeneral);
}
}
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
void UploadRenderTarget(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, bool refresh) {
UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh);
UploadRenderTargetLayers(image, info, 0, info.layers, refresh);
}
RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info) {
RenderTextureVulkanImage* CreateRenderTarget(
const RenderTargetInfo& info) {
auto& graphics = GetRenderContext().GetGraphics();
auto* image = new RenderTextureVulkanImage;
image->extent.width = info.width;
image->extent.height = info.height;
@@ -255,20 +256,21 @@ RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTa
create.format = info.format;
create.tiling = vk::ImageTiling::eOptimal;
create.initialLayout = vk::ImageLayout::eUndefined;
create.usage = RenderTargetUsage(ctx, info.format, create.flags, info.samples);
create.usage = RenderTargetUsage(info.format, create.flags, info.samples);
create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vulkan_sample_count(info.samples);
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
if (!VulkanCreateImage(ctx, create, image)) {
if (!graphics.CreateImage(create, *image)) {
EXIT("TextureCache: failed to create render target, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format));
}
ImageViewOps::CreateRenderTargetViews(ctx, image);
ImageViewOps::CreateRenderTargetViews(*image);
return image;
}
DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info) {
DepthStencilVulkanImage* CreateDepthTarget(const DepthTargetInfo& info) {
auto& graphics = GetRenderContext().GetGraphics();
vk::ImageCreateInfo create {};
create.sType = vk::StructureType::eImageCreateInfo;
create.imageType = vk::ImageType::e2D;
@@ -282,9 +284,9 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vulkan_sample_count(info.samples);
vk::ImageFormatProperties properties {};
if (ctx->GetImageFormatProperties(info.format, vk::ImageType::e2D, vk::ImageTiling::eOptimal,
create.usage, vk::ImageCreateFlags {},
&properties) != vk::Result::eSuccess ||
if (graphics.GetImageFormatProperties(
info.format, vk::ImageType::e2D, vk::ImageTiling::eOptimal, create.usage,
vk::ImageCreateFlags {}, &properties) != vk::Result::eSuccess ||
!static_cast<bool>(properties.sampleCounts & create.samples)) {
EXIT("TextureCache: depth format does not support required usage, format=%d usage=0x%x "
"samples=%u supported=0x%x\n",
@@ -302,16 +304,16 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
image->layout = vk::ImageLayout::eUndefined;
image->compressed = false;
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
if (!VulkanCreateImage(ctx, create, image)) {
if (!graphics.CreateImage(create, *image)) {
EXIT("TextureCache: failed to create depth target, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format));
}
ImageViewOps::CreateDepthViews(ctx, image);
ImageViewOps::CreateDepthViews(*image);
return image;
}
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
void ValidateVideoOut(const VideoOutInfo& info) {
const auto compression =
ClassifyVideoOutCompression(info.compression != VideoOutCompression::Uncompressed,
info.metadata_address, info.dcc_control, 0);
@@ -320,23 +322,23 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
(info.metadata_address >= TRACKER_ADDRESS_SIZE ||
(info.metadata_address >= info.address &&
info.metadata_address < info.address + info.size));
if (ctx == nullptr || info.address == 0 || info.size == 0 ||
info.address >= TRACKER_ADDRESS_SIZE || info.size > TRACKER_ADDRESS_SIZE - info.address ||
(info.address & 0xffffu) != 0 || info.width == 0 || info.height == 0 ||
info.width > 16384 || info.height > 16384 || info.pitch < info.width ||
if (info.address == 0 || info.size == 0 || info.address >= TRACKER_ADDRESS_SIZE ||
info.size > TRACKER_ADDRESS_SIZE - info.address || (info.address & 0xffffu) != 0 ||
info.width == 0 || info.height == 0 || info.width > 16384 || info.height > 16384 ||
info.pitch < info.width ||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
compression == VideoOutCompression::Unsupported || compression != info.compression ||
metadata_invalid || !IsSupportedVideoOutFormat(info)) {
EXIT("TextureCache: unsupported video-out surface, ctx=%p addr=0x%016" PRIx64
" size=0x%016" PRIx64 " metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32
EXIT("TextureCache: unsupported video-out surface, addr=0x%016" PRIx64 " size=0x%016" PRIx64
" metadata=0x%016" PRIx64 " dcc=0x%08" PRIx32
" extent=%ux%u pitch=%u tile=%u guest_format=%u bpe=%u vk_format=%d\n",
static_cast<const void*>(ctx), info.address, info.size, info.metadata_address,
info.dcc_control, info.width, info.height, info.pitch, info.tile_mode,
info.guest_format, info.bytes_per_element, static_cast<int>(info.format));
info.address, info.size, info.metadata_address, info.dcc_control, info.width,
info.height, info.pitch, info.tile_mode, info.guest_format, info.bytes_per_element,
static_cast<int>(info.format));
}
TileSizeAlign exact {};
TileGetTextureTotalSize(info.guest_format, info.width, info.height, 1, info.pitch, 1,
info.tile_mode, false, &exact);
info.tile_mode, false, exact);
if (exact.align != 65536 || exact.size != info.size ||
TileGetTexturePitch(info.guest_format, info.width, 1, info.tile_mode) != info.pitch) {
EXIT("TextureCache: video-out tile layout mismatch, addr=0x%016" PRIx64
@@ -344,10 +346,11 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
" pitch=%u\n",
info.address, info.size, exact.size, exact.align, info.pitch);
}
(void)RenderTargetUsage(ctx, info.format, vk::ImageCreateFlags {}, 1);
(void)RenderTargetUsage(info.format, vk::ImageCreateFlags {}, 1);
}
VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
VideoOutVulkanImage* CreateVideoOut(const VideoOutInfo& info) {
auto& graphics = GetRenderContext().GetGraphics();
auto* image = new VideoOutVulkanImage;
image->extent.width = info.width;
image->extent.height = info.height;
@@ -363,20 +366,20 @@ VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& inf
create.tiling = vk::ImageTiling::eOptimal;
create.initialLayout = vk::ImageLayout::eUndefined;
create.flags = RenderTargetCreateFlags(info.format);
create.usage = RenderTargetUsage(ctx, info.format, create.flags, 1);
create.usage = RenderTargetUsage(info.format, create.flags, 1);
create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vk::SampleCountFlagBits::e1;
image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
if (!VulkanCreateImage(ctx, create, image)) {
if (!graphics.CreateImage(create, *image)) {
EXIT("TextureCache: failed to create video-out image, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format));
}
ImageViewOps::CreateVideoOutViews(ctx, image);
ImageViewOps::CreateVideoOutViews(*image);
return image;
}
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info,
void UploadVideoOut(VideoOutVulkanImage& image, const VideoOutInfo& info,
bool refresh) {
if (info.compression != VideoOutCompression::Uncompressed) {
EXIT("TextureCache: compressed video-out guest upload is unsupported, "
@@ -384,24 +387,24 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
info.address, info.metadata_address, info.dcc_control);
}
if (refresh) {
Transfer::WaitForGraphicsIdle(ctx);
Transfer::WaitForGraphicsIdle();
}
image->layout = vk::ImageLayout::eUndefined;
image.layout = vk::ImageLayout::eUndefined;
if (!info.bgra16) {
auto layout =
TextureCalcUploadLayout(info.guest_format, info.width, info.height, 1, 1, info.pitch,
info.tile_mode, info.size, false, false, "VideoOut");
auto regions = TextureBuildUploadRegions(layout, info.format, info.width, info.height, 1, 1,
false, false, TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<const void*>(info.address), info.size,
regions, layout, info.guest_format, info.width, info.height, 1, 1,
"VideoOut", vk::ImageLayout::eGeneral);
TextureUploadGuestImage(image, reinterpret_cast<const void*>(info.address),
info.size, regions, layout, info.guest_format, info.width,
info.height, 1, 1, "VideoOut", vk::ImageLayout::eGeneral);
return;
}
Transfer::ScratchBuffer scratch(info.size);
TileBlockLayout block {};
EXIT_NOT_IMPLEMENTED(
!TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, info.bytes_per_element, &block));
!TileGetBlockLayout(TileBlockFamily::RenderTarget64KB, info.bytes_per_element, block));
const GpuTileInfo tile_info {block.family,
block.bytes_per_element,
0,
@@ -413,10 +416,10 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
info.height,
1,
info.pitch};
GpuDetile(ctx, reinterpret_cast<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));
SwapVideoOutBgra16(scratch.Data(), info.size);
Transfer::UploadImage(ctx, image, scratch.Data(), info.size, info.pitch,
Transfer::UploadImage(image, scratch.Data(), info.size, info.pitch,
vk::ImageLayout::eGeneral);
}
@@ -427,7 +430,7 @@ void SwapVideoOutBgra16(void* data, uint64_t size) {
}
}
GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, bool image_3d,
GpuTextureVulkanImage* CreateDummyTexture(bool uint_format, bool image_3d,
bool storage) {
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
: new TextureVulkanImage;
@@ -436,48 +439,47 @@ GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture";
auto params = MakeDummyTextureParams(uint_format, image_3d, usage, owner);
auto components = TextureCreateImage(ctx, image, params);
auto components = TextureCreateImage(*image, params);
static constexpr uint32_t zero = 0;
Transfer::UploadImage(ctx, image, &zero, sizeof(zero), 1, layout);
TextureCreateImageViews(ctx, image, components, params.type, 0, params.base_level,
Transfer::UploadImage(*image, &zero, sizeof(zero), 1, layout);
TextureCreateImageViews(*image, components, params.type, 0, params.base_level,
params.levels, params.depth, params.allow_cube_view, params.view_usage);
return image;
}
void Destroy(GraphicContext* ctx, VulkanImage* image) {
void Destroy(VulkanImage& image) {
auto& graphics = GetRenderContext().GetGraphics();
KYTY_PROFILER_BLOCK("TextureCache::DeleteImage");
EXIT_IF(ctx == nullptr || image == nullptr || g_render_ctx == nullptr);
switch (image->type) {
switch (image.type) {
case VulkanImageType::RenderTexture:
case VulkanImageType::VideoOut:
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image);
GetRenderContext().GetFramebufferCache().FreeFramebufferByColor(image);
break;
case VulkanImageType::DepthStencil:
g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth(
static_cast<DepthStencilVulkanImage*>(image));
GetRenderContext().GetFramebufferCache().FreeFramebufferByDepth(
static_cast<DepthStencilVulkanImage&>(image));
break;
case VulkanImageType::Texture:
case VulkanImageType::StorageTexture: break;
case VulkanImageType::Unknown: EXIT("cannot destroy an untyped Vulkan image\n");
}
ImageViewOps::DestroyViews(ctx, image);
VulkanDeleteImage(ctx, image);
ImageViewOps::DestroyViews(image);
graphics.DeleteImage(image);
switch (image->type) {
case VulkanImageType::Texture: delete static_cast<TextureVulkanImage*>(image); break;
switch (image.type) {
case VulkanImageType::Texture: delete &static_cast<TextureVulkanImage&>(image); break;
case VulkanImageType::StorageTexture:
delete static_cast<StorageTextureVulkanImage*>(image);
delete &static_cast<StorageTextureVulkanImage&>(image);
break;
case VulkanImageType::RenderTexture:
delete static_cast<RenderTextureVulkanImage*>(image);
delete &static_cast<RenderTextureVulkanImage&>(image);
break;
case VulkanImageType::DepthStencil:
delete static_cast<DepthStencilVulkanImage*>(image);
delete &static_cast<DepthStencilVulkanImage&>(image);
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");
}
}
+14 -13
View File
@@ -100,33 +100,34 @@ private:
namespace ImageOps {
[[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info,
bool storage, vk::ComponentMapping* components);
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
bool storage, vk::ComponentMapping components);
[[nodiscard]] GpuTextureVulkanImage* CreateTexture(const ImageInfo& info,
bool storage, vk::ComponentMapping& components);
void CreateTextureViews(GpuTextureVulkanImage& image,
const ImageInfo& info, bool storage, vk::ComponentMapping components);
[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx,
[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(
const RenderTargetInfo& info);
[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element);
void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image,
void UploadRenderTargetLayers(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, uint32_t base_layer,
uint32_t layer_count, bool refresh);
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
void UploadRenderTarget(RenderTextureVulkanImage& image,
const RenderTargetInfo& info, bool refresh);
[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx,
[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(
const DepthTargetInfo& info);
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
void ValidateVideoOut(const VideoOutInfo& info);
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(
const VideoOutInfo& info);
void SwapVideoOutBgra16(void* data, uint64_t size);
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info,
void UploadVideoOut(VideoOutVulkanImage& image, const VideoOutInfo& info,
bool refresh);
[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(bool uint_format,
bool image_3d, bool storage);
void Destroy(GraphicContext* ctx, VulkanImage* image);
void Destroy(VulkanImage& image);
} // namespace ImageOps
+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,
VideoOutPixelFormatInfo* info) {
if (info == nullptr) {
return false;
}
VideoOutPixelFormatInfo& info) {
for (const auto& policy: VIDEO_OUT_FORMAT_POLICIES) {
if (policy.pixel_format == pixel_format) {
*info = policy.info;
info = policy.info;
return true;
}
}
@@ -388,9 +385,8 @@ enum class BufferImageWrite : uint8_t {
[[nodiscard]] inline constexpr bool
HasGuestCurrentImageOwnership(bool image_gpu_modified, bool buffer_modified, bool cpu_dirty,
bool tracker_gpu_modified, bool same_context) noexcept {
return !image_gpu_modified && !buffer_modified && !cpu_dirty && !tracker_gpu_modified &&
same_context;
bool tracker_gpu_modified) noexcept {
return !image_gpu_modified && !buffer_modified && !cpu_dirty && !tracker_gpu_modified;
}
enum class StorageBufferRebind : uint8_t { Reuse, RefreshFromBacking, Unsupported };
@@ -398,11 +394,11 @@ enum class MetaImageOverlap : uint8_t { RetainSampled, RetireImage, Unsupported
[[nodiscard]] inline constexpr bool CanRetireGuestCurrentDepthForMetadataReuse(
bool depth_gpu_modified, bool depth_buffer_modified, bool depth_tracker_gpu_modified,
bool metadata_gpu_modified, bool metadata_tracker_gpu_modified, uint32_t metadata_clear_mask,
bool same_context) noexcept {
bool metadata_gpu_modified, bool metadata_tracker_gpu_modified,
uint32_t metadata_clear_mask) noexcept {
return !metadata_gpu_modified && !metadata_tracker_gpu_modified && metadata_clear_mask == 0 &&
HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false,
depth_tracker_gpu_modified, same_context);
depth_tracker_gpu_modified);
}
[[nodiscard]] inline constexpr uint32_t SelectImageBackingBaseLevel(bool storage,
@@ -493,12 +489,12 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
[[nodiscard]] inline MetaImageOverlap ClassifyMetaImageOverlap(bool sampled, bool writable_image,
bool gpu_modified,
bool buffer_modified, bool cpu_dirty,
bool same_context) {
bool buffer_modified,
bool cpu_dirty) {
if (sampled && !gpu_modified) {
return MetaImageOverlap::RetainSampled;
}
if (writable_image && !gpu_modified && !buffer_modified && !cpu_dirty && same_context) {
if (writable_image && !gpu_modified && !buffer_modified && !cpu_dirty) {
return MetaImageOverlap::RetireImage;
}
return MetaImageOverlap::Unsupported;
@@ -510,10 +506,7 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
}
[[nodiscard]] inline bool DecodePackedColorClear(vk::Format format, uint32_t packed,
vk::ClearColorValue* clear) {
if (clear == nullptr) {
return false;
}
vk::ClearColorValue& clear) {
vk::ClearColorValue next {};
const auto unorm8 = [](uint32_t value) { return static_cast<float>(value & 0xffu) / 255.0f; };
switch (format) {
@@ -555,32 +548,28 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
break;
default: return false;
}
*clear = next;
clear = next;
return true;
}
[[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t* clear) {
if (clear == nullptr) {
return false;
}
[[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t& clear) {
const auto value = static_cast<uint8_t>(packed);
if (packed != static_cast<uint32_t>(value) * 0x01010101u) {
return false;
}
*clear = value;
clear = value;
return true;
}
[[nodiscard]] inline bool DecodePackedDepthClear(vk::Format format, uint32_t packed, float* clear) {
if (clear == nullptr ||
(format != vk::Format::eD32Sfloat && format != vk::Format::eD32SfloatS8Uint)) {
[[nodiscard]] inline bool DecodePackedDepthClear(vk::Format format, uint32_t packed, float& clear) {
if (format != vk::Format::eD32Sfloat && format != vk::Format::eD32SfloatS8Uint) {
return false;
}
const auto value = std::bit_cast<float>(packed);
if (!std::isfinite(value) || value < 0.0f || value > 1.0f) {
return false;
}
*clear = value;
clear = value;
return true;
}
@@ -643,13 +632,11 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
[[nodiscard]] inline SampledOverlap ClassifySampledOverlap(const ImageInfo& requested,
const ImageInfo& cached,
bool cached_gpu_modified,
bool same_context) {
bool cached_gpu_modified) {
if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) {
return SampledOverlap::None;
}
return !cached_gpu_modified && same_context ? SampledOverlap::ReadOnlyAlias
: SampledOverlap::Unsupported;
return !cached_gpu_modified ? SampledOverlap::ReadOnlyAlias : SampledOverlap::Unsupported;
}
[[nodiscard]] inline bool IsRgba8SrgbReinterpretation(vk::Format cached,
@@ -702,7 +689,7 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
[[nodiscard]] inline StorageSampledOverlap ClassifyStorageSampledOverlap(
const ImageInfo& requested, const ImageInfo& cached, vk::Format requested_view_format,
vk::Format cached_image_format, bool cached_gpu_modified, bool cached_cpu_dirty,
bool same_context, bool exact_mip_subresource = false, bool cached_buffer_modified = false,
bool exact_mip_subresource = false, bool cached_buffer_modified = false,
bool tracker_gpu_modified = true) {
if (!ImagePageRangesOverlap(requested.address, requested.size, cached.address, cached.size)) {
return StorageSampledOverlap::None;
@@ -718,12 +705,11 @@ SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available
(requested.format == cached.format && requested_view_format == cached_image_format) ||
IsRgba8SrgbReinterpretation(cached_image_format, requested_view_format) ||
IsR32UintFloatReinterpretation(cached_image_format, requested_view_format);
if (same_backing && compatible_format && cached_gpu_modified && !cached_cpu_dirty &&
same_context) {
if (same_backing && compatible_format && cached_gpu_modified && !cached_cpu_dirty) {
return StorageSampledOverlap::ExactImage;
}
if (exact_mip_subresource && cached_gpu_modified && tracker_gpu_modified &&
!cached_buffer_modified && !cached_cpu_dirty && same_context) {
!cached_buffer_modified && !cached_cpu_dirty) {
return StorageSampledOverlap::RetireStorage;
}
return StorageSampledOverlap::Unsupported;
@@ -866,8 +852,7 @@ ClassifyStorageBufferRebind(bool buffer_overlap, bool cached_gpu_modified,
[[nodiscard]] inline DepthOverlap
ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
bool storage_buffer_modified, bool storage_cpu_dirty,
bool tracker_gpu_modified, bool same_context,
const DepthTargetInfo& depth) {
bool tracker_gpu_modified, const DepthTargetInfo& depth) {
const bool overlaps_depth =
ImageRangeOverlaps(storage.address, storage.size, depth.address, depth.size);
const bool overlaps_stencil =
@@ -876,21 +861,20 @@ ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
if (!overlaps_depth && !overlaps_stencil) {
return DepthOverlap::None;
}
const bool guest_current =
HasGuestCurrentImageOwnership(storage_gpu_modified, storage_buffer_modified,
storage_cpu_dirty, tracker_gpu_modified, same_context);
const bool guest_current = HasGuestCurrentImageOwnership(
storage_gpu_modified, storage_buffer_modified, storage_cpu_dirty, tracker_gpu_modified);
const bool aspects_discarded =
(!overlaps_depth || !depth.depth_access) && (!overlaps_stencil || !depth.stencil_access);
return guest_current || (!storage_buffer_modified && !storage_cpu_dirty && same_context &&
aspects_discarded)
return guest_current || (!storage_buffer_modified && !storage_cpu_dirty && aspects_discarded)
? DepthOverlap::RetireStorage
: DepthOverlap::Unsupported;
}
[[nodiscard]] inline bool CanRetireGuestCurrentDepthForSampled(
const ImageInfo& sampled, const DepthTargetInfo& depth, bool depth_gpu_modified,
bool depth_buffer_modified, bool depth_tracker_gpu_modified, bool stencil_tracker_gpu_modified,
bool same_context) noexcept {
[[nodiscard]] inline bool
CanRetireGuestCurrentDepthForSampled(const ImageInfo& sampled, const DepthTargetInfo& depth,
bool depth_gpu_modified, bool depth_buffer_modified,
bool depth_tracker_gpu_modified,
bool stencil_tracker_gpu_modified) noexcept {
const bool overlaps_depth =
ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size);
const bool overlaps_stencil =
@@ -898,15 +882,15 @@ ClassifyStorageDepthOverlap(const ImageInfo& storage, bool storage_gpu_modified,
depth.stencil_address, depth.stencil_size);
return (overlaps_depth || overlaps_stencil) &&
HasGuestCurrentImageOwnership(depth_gpu_modified, depth_buffer_modified, false,
depth_tracker_gpu_modified || stencil_tracker_gpu_modified,
same_context);
depth_tracker_gpu_modified ||
stencil_tracker_gpu_modified);
}
[[nodiscard]] inline bool
CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTargetInfo& depth,
bool sampled_gpu_modified, bool sampled_buffer_modified,
bool sampled_cpu_dirty, bool tracker_gpu_modified,
bool same_context, bool guest_source_current) noexcept {
bool guest_source_current) noexcept {
const bool overlaps_depth =
ImageRangeOverlaps(sampled.address, sampled.size, depth.address, depth.size);
const bool overlaps_stencil =
@@ -914,11 +898,11 @@ CanRetireGuestCurrentSampledForDepth(const ImageInfo& sampled, const DepthTarget
depth.stencil_address, depth.stencil_size);
return (overlaps_depth || overlaps_stencil) && guest_source_current &&
HasGuestCurrentImageOwnership(sampled_gpu_modified, sampled_buffer_modified,
sampled_cpu_dirty, tracker_gpu_modified, same_context);
sampled_cpu_dirty, tracker_gpu_modified);
}
[[nodiscard]] inline RenderTargetOverlap
ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified, bool same_context,
ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified,
const RenderTargetInfo& target) {
if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None;
@@ -926,7 +910,7 @@ ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified,
if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None;
}
return !sampled_gpu_modified && same_context ? RenderTargetOverlap::RetireSampled
return !sampled_gpu_modified ? RenderTargetOverlap::RetireSampled
: RenderTargetOverlap::Unsupported;
}
@@ -934,7 +918,7 @@ ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified,
ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_format,
bool storage_gpu_modified, bool storage_buffer_modified,
bool storage_cpu_dirty, bool tracker_gpu_modified,
bool same_context, const RenderTargetInfo& target) {
const RenderTargetInfo& target) {
if (!ImagePageRangesOverlap(storage.address, storage.size, target.address, target.size)) {
return RenderTargetOverlap::None;
}
@@ -950,11 +934,11 @@ ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_
storage.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
storage.base_array == 0 && target.levels == 1 && target.layers == 1 && target.samples == 1;
if (exact_native_image && storage_gpu_modified && tracker_gpu_modified &&
!storage_buffer_modified && !storage_cpu_dirty && same_context) {
!storage_buffer_modified && !storage_cpu_dirty) {
return RenderTargetOverlap::PreserveStorage;
}
return HasGuestCurrentImageOwnership(storage_gpu_modified, storage_buffer_modified,
storage_cpu_dirty, tracker_gpu_modified, same_context)
storage_cpu_dirty, tracker_gpu_modified)
? RenderTargetOverlap::RetireStorage
: RenderTargetOverlap::Unsupported;
}
@@ -988,29 +972,28 @@ ClassifyStorageRenderTargetOverlap(const ImageInfo& storage, vk::Format storage_
[[nodiscard]] inline RenderTargetOverlap
ClassifySampledRenderTargetOverlap(const ImageInfo& sampled, const RenderTargetInfo& target,
bool target_buffer_modified, bool same_context) {
bool target_buffer_modified) {
if (!ImagePageRangesOverlap(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None;
}
if (!ImageRangeOverlaps(sampled.address, sampled.size, target.address, target.size)) {
return RenderTargetOverlap::None;
}
return same_context && !target_buffer_modified ? RenderTargetOverlap::RetireTarget
return !target_buffer_modified ? RenderTargetOverlap::RetireTarget
: RenderTargetOverlap::Unsupported;
}
[[nodiscard]] inline StorageImageOverlap
ClassifyStorageImageOverlap(uint64_t requested_address, uint64_t requested_size,
uint64_t cached_address, uint64_t cached_size, bool sampled,
bool same_context, bool gpu_modified, bool buffer_modified,
bool tracker_gpu_modified) {
bool gpu_modified, bool buffer_modified, bool tracker_gpu_modified) {
if (!ImagePageRangesOverlap(requested_address, requested_size, cached_address, cached_size)) {
return StorageImageOverlap::None;
}
if (!ImageRangeOverlaps(requested_address, requested_size, cached_address, cached_size)) {
return StorageImageOverlap::PageNeighbor;
}
return sampled && same_context && !gpu_modified && !buffer_modified && !tracker_gpu_modified
return sampled && !gpu_modified && !buffer_modified && !tracker_gpu_modified
? StorageImageOverlap::RetireSampled
: StorageImageOverlap::Unsupported;
}
@@ -1068,8 +1051,7 @@ IsCompatibleDepthTargetBacking(const DepthTargetInfo& cached,
[[nodiscard]] inline RenderTargetOverlap
ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modified,
bool cached_buffer_modified, bool tracker_gpu_modified,
bool same_context, bool guest_source_current,
const RenderTargetInfo& requested) {
bool guest_source_current, const RenderTargetInfo& requested) {
if (!ImagePageRangesOverlap(cached.address, cached.size, requested.address, requested.size)) {
return RenderTargetOverlap::None;
}
@@ -1079,8 +1061,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
const bool expand = requested.layers > cached.layers &&
IsCompatibleRenderTargetBacking(requested, cached) &&
cached.format == requested.format;
if (expand && cached_gpu_modified && tracker_gpu_modified && !cached_buffer_modified &&
same_context) {
if (expand && cached_gpu_modified && tracker_gpu_modified && !cached_buffer_modified) {
return RenderTargetOverlap::ExpandTarget;
}
// A clean, page-isolated overlap is allocation-pool reuse, including a contained subrange.
@@ -1100,7 +1081,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
cached.size != requested.size || pool_storage_shape_changed;
return page_isolated && new_allocation && guest_source_current &&
HasGuestCurrentImageOwnership(cached_gpu_modified, cached_buffer_modified, false,
tracker_gpu_modified, same_context)
tracker_gpu_modified)
? RenderTargetOverlap::RetireTarget
: RenderTargetOverlap::Unsupported;
}
@@ -1108,7 +1089,6 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
[[nodiscard]] inline DepthOverlap ClassifyDepthTargetOverlap(const DepthTargetInfo& cached,
bool cached_gpu_modified,
bool cached_buffer_modified,
bool same_context,
const DepthTargetInfo& requested) {
const auto overlaps = [](uint64_t left, uint64_t left_size, uint64_t right, uint64_t right_size,
bool pages) {
@@ -1132,12 +1112,12 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
}
const bool expand =
requested.layers > cached.layers && IsCompatibleDepthTargetBacking(requested, cached);
if (expand && cached_gpu_modified && !cached_buffer_modified && same_context) {
if (expand && cached_gpu_modified && !cached_buffer_modified) {
return DepthOverlap::ExpandTarget;
}
const bool exact_discard =
requested.depth_load_clear && cached_gpu_modified && !cached_buffer_modified &&
same_context && cached.address == requested.address && cached.size == requested.size &&
cached.address == requested.address && cached.size == requested.size &&
cached.samples == requested.samples && cached.stencil_address == 0 &&
cached.stencil_size == 0 && cached.htile_address == 0 && cached.htile_size == 0 &&
requested.stencil_address == 0 && requested.stencil_size == 0 &&
@@ -1158,7 +1138,7 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
cached.bytes_per_element == requested.bytes_per_element &&
cached.tile_mode == requested.tile_mode && cached.layers == 1 &&
requested.layers == 1 && cached.samples == 1 && requested.samples == 1;
return exact_plane_rebind && same_shape && !cached_buffer_modified && same_context
return exact_plane_rebind && same_shape && !cached_buffer_modified
? DepthOverlap::RecreateTarget
: DepthOverlap::Unsupported;
}
@@ -1166,7 +1146,6 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
[[nodiscard]] inline bool CanRecreateDepthForRenderTarget(const DepthTargetInfo& depth,
bool gpu_modified, bool buffer_modified,
bool tracker_gpu_modified,
bool same_context,
bool guest_source_current,
const RenderTargetInfo& target) noexcept {
const bool exact_depth = depth.address == target.address && depth.size == target.size;
@@ -1189,15 +1168,16 @@ ClassifyRenderTargetOverlap(const RenderTargetInfo& cached, bool cached_gpu_modi
const bool ownership_consistent = gpu_modified == tracker_gpu_modified && !buffer_modified;
const bool source_available =
((exact_depth || exact_stencil) && gpu_modified) || guest_source_current;
return same_context && ownership_consistent && source_available &&
return ownership_consistent && source_available &&
(exact_depth || exact_stencil || page_isolated_rebind) && depth.layers == 1 &&
target.levels == 1 && target.layers == 1 && depth.samples == 1 && target.samples == 1;
}
[[nodiscard]] inline bool
CanRecreateRenderTargetForDepth(const RenderTargetInfo& target, bool gpu_modified,
bool buffer_modified, bool tracker_gpu_modified, bool same_context,
bool guest_source_current, const DepthTargetInfo& depth) noexcept {
[[nodiscard]] inline bool CanRecreateRenderTargetForDepth(const RenderTargetInfo& target,
bool gpu_modified, bool buffer_modified,
bool tracker_gpu_modified,
bool guest_source_current,
const DepthTargetInfo& depth) noexcept {
const bool exact_depth = target.address == depth.address && target.size == depth.size;
const bool exact_stencil =
target.address == depth.stencil_address && target.size == depth.stencil_size;
@@ -1214,10 +1194,9 @@ CanRecreateRenderTargetForDepth(const RenderTargetInfo& target, bool gpu_modifie
depth.stencil_size % TRACKER_PAGE_SIZE == 0));
const bool source_available =
(gpu_modified && (exact_depth || exact_stencil)) || guest_source_current;
return gpu_modified == tracker_gpu_modified && !buffer_modified && same_context &&
source_available && (exact_depth || exact_stencil || page_isolated_rebind) &&
target.levels == 1 && target.layers == 1 && depth.layers == 1 && target.samples == 1 &&
depth.samples == 1;
return gpu_modified == tracker_gpu_modified && !buffer_modified && source_available &&
(exact_depth || exact_stencil || page_isolated_rebind) && target.levels == 1 &&
target.layers == 1 && depth.layers == 1 && target.samples == 1 && depth.samples == 1;
}
[[nodiscard]] inline bool RequiresMultisampleDepthRefresh(const DepthTargetInfo& info,
+123 -154
View File
@@ -2,6 +2,7 @@
#include "common/assert.h"
#include "graphics/host_gpu/objects/textureCommon.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/textureCache.h"
#include <mutex>
@@ -10,19 +11,19 @@ namespace Libs::Graphics {
namespace {
void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index,
void CreateView(VulkanImage& image, int view_index,
vk::ImageViewType view_type, vk::ImageAspectFlags aspect_mask,
vk::ComponentMapping components, uint32_t base_array_layer, uint32_t base_mip_level,
uint32_t layer_count, uint32_t level_count,
vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {}) {
if (ctx == nullptr || image == nullptr || view_index < 0 ||
view_index >= VulkanImage::VIEW_MAX || image->image == nullptr ||
image->image_view[view_index] != nullptr) {
auto& graphics = GetRenderContext().GetGraphics();
if (view_index < 0 || view_index >= VulkanImage::VIEW_MAX ||
image.image_view[view_index] != nullptr) {
EXIT("invalid image-view creation target: image=%p index=%d current_view=%d\n",
static_cast<const void*>(image), view_index,
image != nullptr && view_index >= 0 && view_index < VulkanImage::VIEW_MAX &&
image->image_view[view_index] != nullptr);
static_cast<const void*>(&image), view_index,
view_index >= 0 && view_index < VulkanImage::VIEW_MAX &&
image.image_view[view_index] != nullptr);
}
vk::ImageViewUsageCreateInfo usage_info {};
@@ -32,9 +33,9 @@ void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index,
vk::ImageViewCreateInfo create_info {};
create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = view_usage ? &usage_info : nullptr;
create_info.image = image->image;
create_info.image = image.image;
create_info.viewType = view_type;
create_info.format = view_format != vk::Format::eUndefined ? view_format : image->format;
create_info.format = view_format != vk::Format::eUndefined ? view_format : image.format;
create_info.components = components;
create_info.subresourceRange.aspectMask = aspect_mask;
create_info.subresourceRange.baseArrayLayer = base_array_layer;
@@ -43,22 +44,22 @@ void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index,
create_info.subresourceRange.levelCount = level_count;
const auto result =
ctx->device.createImageView(&create_info, nullptr, &image->image_view[view_index]);
if (result != vk::Result::eSuccess || image->image_view[view_index] == nullptr) {
graphics.device.createImageView(&create_info, nullptr, &image.image_view[view_index]);
if (result != vk::Result::eSuccess || image.image_view[view_index] == nullptr) {
EXIT("failed to create image view: result=%d image_format=%d view_format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(image->format),
static_cast<int>(result), static_cast<int>(image.format),
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 a, vk::ImageViewType type = vk::ImageViewType::e2D,
vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {}, uint32_t level_count = 0) {
const auto layer_count = type == vk::ImageViewType::e2DArray ? image->layers : 1u;
CreateView(ctx, image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, 0,
layer_count, level_count == 0 ? image->mip_levels : level_count, view_format,
const auto layer_count = type == vk::ImageViewType::e2DArray ? image.layers : 1u;
CreateView(image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, 0,
layer_count, level_count == 0 ? image.mip_levels : level_count, view_format,
view_usage);
}
@@ -78,30 +79,31 @@ vk::ImageAspectFlags DepthAspectMask(vk::Format format) {
}
}
bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format) {
const auto properties = ctx->GetFormatProperties(format);
bool FormatSupportsStorage(vk::Format format) {
auto& graphics = GetRenderContext().GetGraphics();
const auto properties = graphics.GetFormatProperties(format);
return static_cast<bool>(properties.optimalTilingFeatures &
vk::FormatFeatureFlagBits::eStorageImage);
}
void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity,
void CreateRenderTargetViews(RenderTextureVulkanImage& image) {
CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity);
if (image->layers > 1) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT_ARRAY,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity);
if (image.layers > 1) {
CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT_ARRAY,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2DArray);
}
if (image->samples == 1 && FormatSupportsStorage(ctx, image->format)) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE,
if (image.samples == 1 && FormatSupportsStorage(image.format)) {
CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2D, vk::Format::eUndefined,
vk::ImageUsageFlags {}, 1);
if (image->layers > 1) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE_ARRAY,
if (image.layers > 1) {
CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE_ARRAY,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2DArray, vk::Format::eUndefined,
@@ -110,22 +112,21 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag
}
}
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) {
CreateView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D,
DepthAspectMask(image->format),
void CreateDepthViews(DepthStencilVulkanImage& image) {
CreateView(image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D,
DepthAspectMask(image.format),
{vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity},
0, 0, 1, 1);
}
void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ComponentSwizzle::eIdentity,
void CreateVideoOutViews(VideoOutVulkanImage& image) {
CreateRenderTargetView(image, VulkanImage::VIEW_DEFAULT,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity);
if ((image->format == vk::Format::eR8G8B8A8Srgb ||
image->format == vk::Format::eB8G8R8A8Srgb) &&
FormatSupportsStorage(ctx, vk::Format::eR8G8B8A8Uint)) {
CreateRenderTargetView(ctx, image, VulkanImage::VIEW_STORAGE,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity);
if ((image.format == vk::Format::eR8G8B8A8Srgb || image.format == vk::Format::eB8G8R8A8Srgb) &&
FormatSupportsStorage(vk::Format::eR8G8B8A8Uint)) {
CreateRenderTargetView(image, VulkanImage::VIEW_STORAGE,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ImageViewType::e2D, vk::Format::eR8G8B8A8Uint,
@@ -133,20 +134,18 @@ void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) {
}
}
void DestroyViews(GraphicContext* ctx, VulkanImage* image) {
EXIT_IF(ctx == nullptr);
EXIT_IF(image == nullptr);
for (auto& cached: image->view_cache.views) {
void DestroyViews(VulkanImage& image) {
auto& graphics = GetRenderContext().GetGraphics();
for (auto& cached: image.view_cache.views) {
if (cached.view != nullptr) {
ctx->device.destroyImageView(cached.view, nullptr);
graphics.device.destroyImageView(cached.view, nullptr);
cached.view = nullptr;
}
}
image->view_cache.views.clear();
for (auto& view: image->image_view) {
image.view_cache.views.clear();
for (auto& view: image.image_view) {
if (view != nullptr) {
ctx->device.destroyImageView(view, nullptr);
graphics.device.destroyImageView(view, nullptr);
view = nullptr;
}
}
@@ -154,54 +153,45 @@ void DestroyViews(GraphicContext* ctx, VulkanImage* image) {
} // namespace ImageViewOps
vk::ImageView TextureCache::GetRenderTargetAttachmentView(GraphicContext* ctx,
RenderTextureVulkanImage* image,
vk::ImageView TextureCache::GetRenderTargetAttachmentView(RenderTextureVulkanImage& image,
vk::Format format, uint32_t level,
uint32_t base_layer,
uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
format == vk::Format::eUndefined || level >= image->mip_levels || level >= 16 ||
layer_count == 0 || base_layer >= image->layers ||
layer_count > image->layers - base_layer) {
if (image.format == vk::Format::eUndefined || level >= image.mip_levels || level >= 16 ||
layer_count == 0 || base_layer >= image.layers || layer_count > image.layers - base_layer) {
EXIT("TextureCache: invalid render-target attachment view, image=%p format=%d"
" level=%u image_levels=%u base_layer=%u layer_count=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(format), level,
image != nullptr ? image->mip_levels : 0, base_layer, layer_count,
image != nullptr ? image->layers : 0);
static_cast<const void*>(&image), static_cast<int>(format), level, image.mip_levels,
base_layer, layer_count, image.layers);
}
if (format != image->format && !IsRgba8SrgbReinterpretation(image->format, format)) {
if (format != image.format && !IsRgba8SrgbReinterpretation(image.format, format)) {
EXIT("TextureCache: incompatible render-target attachment view, image_format=%d"
" view_format=%d level=%u\n",
static_cast<int>(image->format), static_cast<int>(format), level);
static_cast<int>(image.format), static_cast<int>(format), level);
}
return GetImageView(ctx, image,
{format,
layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
return GetImageView(
image, {format, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
vk::ImageAspectFlagBits::eColor, level, 1, base_layer, layer_count,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eColorAttachment});
}
vk::ImageView TextureCache::GetDepthTargetAttachmentView(GraphicContext* ctx,
DepthStencilVulkanImage* image,
vk::ImageView TextureCache::GetDepthTargetAttachmentView(DepthStencilVulkanImage& image,
uint32_t base_layer,
uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr || layer_count == 0 ||
base_layer >= image->layers || layer_count > image->layers - base_layer) {
if (layer_count == 0 || base_layer >= image.layers || layer_count > image.layers - base_layer) {
EXIT("TextureCache: invalid depth-target attachment view, image=%p base_layer=%u "
"layer_count=%u image_layers=%u\n",
static_cast<const void*>(image), base_layer, layer_count,
image != nullptr ? image->layers : 0);
static_cast<const void*>(&image), base_layer, layer_count, image.layers);
}
return GetImageView(
ctx, image,
{image->format, layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
ImageViewOps::DepthAspectMask(image->format), 0, 1, base_layer, layer_count,
return GetImageView(image,
{image.format,
layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray,
ImageViewOps::DepthAspectMask(image.format), 0, 1, base_layer, layer_count,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eDepthStencilAttachment});
}
vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image,
const ImageViewInfo& info) {
vk::ImageView TextureCache::GetImageView(VulkanImage& image, const ImageViewInfo& info) {
const bool supported_type = info.type == vk::ImageViewType::e2D ||
info.type == vk::ImageViewType::e2DArray ||
info.type == vk::ImageViewType::e3D;
@@ -213,23 +203,22 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
(info.type == vk::ImageViewType::e2D && info.layer_count == 1) ||
info.type == vk::ImageViewType::e2DArray ||
(info.type == vk::ImageViewType::e3D && info.base_layer == 0 && info.layer_count == 1);
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
info.format == vk::Format::eUndefined || !info.aspect || info.level_count == 0 ||
info.base_level >= (image != nullptr ? image->mip_levels : 0) ||
info.level_count > image->mip_levels - info.base_level || info.layer_count == 0 ||
info.base_layer >= image->layers || info.layer_count > image->layers - info.base_layer ||
if (info.format == vk::Format::eUndefined || !info.aspect || info.level_count == 0 ||
info.base_level >= (image.mip_levels) ||
info.level_count > image.mip_levels - info.base_level || info.layer_count == 0 ||
info.base_layer >= image.layers || info.layer_count > image.layers - info.base_layer ||
!supported_type || !valid_shape || !supported_usage) {
EXIT("TextureCache: invalid dynamic image view, image=%p format=%d aspect=0x%x"
" swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d usage=0x%x"
" image_levels=%u image_layers=%u\n",
static_cast<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,
info.base_level, info.level_count, info.base_layer, info.layer_count,
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);
for (const auto& cached: cache.views) {
if (cached.info == info) {
@@ -243,7 +232,7 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
vk::ImageViewCreateInfo create {};
create.sType = vk::StructureType::eImageViewCreateInfo;
create.pNext = &usage;
create.image = image->image;
create.image = image.image;
create.viewType = info.type;
create.format = info.format;
create.components = info.usage == vk::ImageUsageFlagBits::eSampled
@@ -255,7 +244,7 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
create.subresourceRange.baseArrayLayer = info.base_layer;
create.subresourceRange.layerCount = info.layer_count;
vk::ImageView view = nullptr;
const auto result = ctx->device.createImageView(&create, nullptr, &view);
const auto result = m_graphics.device.createImageView(&create, nullptr, &view);
if (result != vk::Result::eSuccess || view == nullptr) {
EXIT("TextureCache: failed to create dynamic image view, result=%d format=%d"
" aspect=0x%x swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d usage=0x%x\n",
@@ -268,80 +257,68 @@ vk::ImageView TextureCache::GetImageView(GraphicContext* ctx, VulkanImage* image
return view;
}
vk::ImageView TextureCache::GetDepthTargetSampledView(GraphicContext* ctx,
DepthStencilVulkanImage* image,
vk::ImageView TextureCache::GetDepthTargetSampledView(DepthStencilVulkanImage& image,
vk::Format view_format, uint32_t swizzle,
uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
view_format == vk::Format::eUndefined ||
!IsSupportedSampledDepthView(image->format, view_format, swizzle)) {
if (view_format == vk::Format::eUndefined ||
!IsSupportedSampledDepthView(image.format, view_format, swizzle)) {
EXIT("TextureCache: invalid sampled depth-target view, image=%p image_format=%d"
" view_format=%d swizzle=0x%03x mip=%u+%u layer=%u+%u type=%d"
" image_levels=%u image_layers=%u\n",
static_cast<const void*>(image),
image != nullptr ? static_cast<int>(image->format)
: static_cast<int>(vk::Format::eUndefined),
static_cast<const void*>(&image), static_cast<int>(image.format),
static_cast<int>(view_format), swizzle, base_level, level_count, base_layer,
layer_count, static_cast<int>(type), image != nullptr ? image->mip_levels : 0,
image != nullptr ? image->layers : 0);
layer_count, static_cast<int>(type), image.mip_levels, image.layers);
}
return GetImageView(ctx, image,
{image->format, type, vk::ImageAspectFlagBits::eDepth, base_level,
return GetImageView(image, {image.format, type, vk::ImageAspectFlagBits::eDepth, base_level,
level_count, base_layer, layer_count, swizzle});
}
vk::ImageView TextureCache::GetSampledColorView(GraphicContext* ctx, VulkanImage* image,
vk::Format view_format, uint32_t swizzle,
uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
view_format == vk::Format::eUndefined || base_level >= 16 ||
vk::ImageView TextureCache::GetSampledColorView(VulkanImage& image, vk::Format view_format,
uint32_t swizzle, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count) {
if (view_format == vk::Format::eUndefined || base_level >= 16 ||
(type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray) ||
!IsSupportedSampledColorView(image->format, view_format, swizzle)) {
!IsSupportedSampledColorView(image.format, view_format, swizzle)) {
EXIT("TextureCache: invalid sampled color view, image=%p swizzle=0x%03x"
" view_format=%d mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), swizzle, static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type),
image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0);
static_cast<const void*>(&image), swizzle, static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type), image.mip_levels,
image.layers);
}
const auto precreated_view = type == vk::ImageViewType::e2DArray
? VulkanImage::VIEW_DEFAULT_ARRAY
: VulkanImage::VIEW_DEFAULT;
const bool full_view =
base_level == 0 && level_count == image->mip_levels && base_layer == 0 &&
layer_count == (type == vk::ImageViewType::e2DArray ? image->layers : 1u);
if (view_format == image->format && swizzle == DstSel(4, 5, 6, 7) && full_view &&
image->image_view[precreated_view] != nullptr) {
return image->image_view[precreated_view];
const bool full_view = base_level == 0 && level_count == image.mip_levels && base_layer == 0 &&
layer_count == (type == vk::ImageViewType::e2DArray ? image.layers : 1u);
if (view_format == image.format && swizzle == DstSel(4, 5, 6, 7) && full_view &&
image.image_view[precreated_view] != nullptr) {
return image.image_view[precreated_view];
}
return GetImageView(ctx, image,
{view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
level_count, base_layer, layer_count, swizzle});
}
vk::ImageView TextureCache::GetRenderTargetStorageView(GraphicContext* ctx,
RenderTextureVulkanImage* image,
vk::ImageView TextureCache::GetRenderTargetStorageView(RenderTextureVulkanImage& image,
vk::Format view_format, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
view_format == vk::Format::eUndefined ||
if (view_format == vk::Format::eUndefined ||
(type != vk::ImageViewType::e2D && type != vk::ImageViewType::e2DArray)) {
EXIT("TextureCache: invalid render-target storage view, image=%p view_format=%d"
" mip=%u+%u layer=%u+%u type=%d image_levels=%u image_layers=%u\n",
static_cast<const void*>(image), static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type),
image != nullptr ? image->mip_levels : 0, image != nullptr ? image->layers : 0);
static_cast<const void*>(&image), static_cast<int>(view_format), base_level,
level_count, base_layer, layer_count, static_cast<int>(type), image.mip_levels,
image.layers);
}
const bool exact = view_format == image->format;
const bool compatible = view_format == BgraSrgbStorageViewFormat(image->format);
const bool exact = view_format == image.format;
const bool compatible = view_format == BgraSrgbStorageViewFormat(image.format);
if (!exact && !compatible) {
EXIT("TextureCache: incompatible render-target storage view, image_format=%d"
" view_format=%d base=%u count=%u\n",
static_cast<int>(image->format), static_cast<int>(view_format), base_level,
static_cast<int>(image.format), static_cast<int>(view_format), base_level,
level_count);
}
if (exact) {
@@ -349,44 +326,40 @@ vk::ImageView TextureCache::GetRenderTargetStorageView(GraphicContext*
: VulkanImage::VIEW_STORAGE;
const bool full_view =
base_level == 0 && level_count == 1 && base_layer == 0 &&
layer_count == (type == vk::ImageViewType::e2DArray ? image->layers : 1u);
if (full_view && image->image_view[index] != nullptr) {
return image->image_view[index];
layer_count == (type == vk::ImageViewType::e2DArray ? image.layers : 1u);
if (full_view && image.image_view[index] != nullptr) {
return image.image_view[index];
}
}
if (compatible && !ImageViewOps::FormatSupportsStorage(ctx, view_format)) {
if (compatible && !ImageViewOps::FormatSupportsStorage(view_format)) {
EXIT("TextureCache: compatible render-target storage format lacks storage support,"
" image_format=%d view_format=%d base=%u count=%u\n",
static_cast<int>(image->format), static_cast<int>(view_format), base_level,
static_cast<int>(image.format), static_cast<int>(view_format), base_level,
level_count);
}
return GetImageView(ctx, image,
{view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, base_level,
level_count, base_layer, layer_count, DstSel(4, 5, 6, 7),
vk::ImageUsageFlagBits::eStorage});
}
vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext* ctx,
StorageTextureVulkanImage* image,
vk::ImageView TextureCache::GetStorageTextureSampledView(StorageTextureVulkanImage& image,
const ImageInfo& info) {
const auto shape =
SelectStorageSampledViewShape(info.type, info.depth, image != nullptr ? image->layers : 0);
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
shape == StorageSampledViewShape::Unsupported || info.base_array != 0 ||
info.levels != image->mip_levels || info.base_level >= info.levels ||
const auto shape = SelectStorageSampledViewShape(info.type, info.depth, image.layers);
if (image.image == nullptr || shape == StorageSampledViewShape::Unsupported ||
info.base_array != 0 || info.levels != image.mip_levels || info.base_level >= info.levels ||
info.view_levels == 0 || info.base_level + info.view_levels > info.levels) {
EXIT("TextureCache: invalid sampled view of storage texture, image=%p type=%u depth=%u"
" base=%u levels=%u view_levels=%u image_levels=%u base_array=%u\n",
static_cast<const void*>(image), info.type, info.depth, info.base_level, info.levels,
info.view_levels, image != nullptr ? image->mip_levels : 0, info.base_array);
static_cast<const void*>(&image), info.type, info.depth, info.base_level, info.levels,
info.view_levels, image.mip_levels, info.base_array);
}
const auto view_format = TextureGetFormat(info.format);
if (view_format != image->format && !IsRgba8SrgbReinterpretation(image->format, view_format) &&
!IsR32UintFloatReinterpretation(image->format, view_format)) {
if (view_format != image.format && !IsRgba8SrgbReinterpretation(image.format, view_format) &&
!IsR32UintFloatReinterpretation(image.format, view_format)) {
EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d"
" view_format=%d swizzle=0x%03x\n",
static_cast<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);
@@ -398,26 +371,22 @@ vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext*
EXIT("TextureCache: unsupported sampled storage-image view shape\n");
}
const auto layer_count = shape == StorageSampledViewShape::Image2DArray ? info.depth : 1u;
return GetImageView(ctx, image,
{view_format, type, vk::ImageAspectFlagBits::eColor, info.base_level,
return GetImageView(image, {view_format, type, vk::ImageAspectFlagBits::eColor, info.base_level,
info.view_levels, 0, layer_count, info.swizzle});
}
vk::ImageView TextureCache::GetStorageTextureStorageView(GraphicContext* ctx,
StorageTextureVulkanImage* image,
vk::ImageView TextureCache::GetStorageTextureStorageView(StorageTextureVulkanImage& image,
uint32_t base_level) {
if (ctx == nullptr || image == nullptr || image->image == nullptr ||
base_level >= (image != nullptr ? image->mip_levels : 0)) {
if (image.image == nullptr || base_level >= (image.mip_levels)) {
EXIT("TextureCache: invalid storage-texture mip view, image=%p level=%u levels=%u\n",
static_cast<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) {
return image->image_view[VulkanImage::VIEW_DEFAULT];
return image.image_view[VulkanImage::VIEW_DEFAULT];
}
return GetImageView(ctx, image,
{image->format, vk::ImageViewType::e2D, vk::ImageAspectFlagBits::eColor,
base_level, 1, 0, 1, DstSel(4, 5, 6, 7),
vk::ImageUsageFlagBits::eStorage});
return GetImageView(image, {image.format, vk::ImageViewType::e2D,
vk::ImageAspectFlagBits::eColor, base_level, 1, 0, 1,
DstSel(4, 5, 6, 7), vk::ImageUsageFlagBits::eStorage});
}
} // namespace Libs::Graphics
+5 -5
View File
@@ -216,12 +216,12 @@ ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource
namespace ImageViewOps {
[[nodiscard]] vk::ImageAspectFlags DepthAspectMask(vk::Format format);
[[nodiscard]] bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format);
[[nodiscard]] bool FormatSupportsStorage(vk::Format format);
void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image);
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image);
void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image);
void DestroyViews(GraphicContext* ctx, VulkanImage* image);
void CreateRenderTargetViews(RenderTextureVulkanImage& image);
void CreateDepthViews(DepthStencilVulkanImage& image);
void CreateVideoOutViews(VideoOutVulkanImage& image);
void DestroyViews(VulkanImage& image);
} // namespace ImageViewOps
@@ -8,6 +8,7 @@
#include "graphics/host_gpu/renderer/debug.h"
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
#include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include <atomic>
@@ -39,78 +40,77 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other)
return std::memcmp(this, &other, sizeof(*this)) == 0;
}
PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx,
HW::Shader* sh_ctx, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology,
bool ps_active, std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv) {
PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
VulkanFramebuffer& framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info, RenderCommandBuffer& command,
ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool ps_active,
std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv) {
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Gfx)", profiler::colors::DeepOrangeA200);
EXIT_IF(framebuffer == nullptr);
EXIT_IF(depth == nullptr);
EXIT_IF(colors == nullptr);
EXIT_IF(color_count > RENDER_COLOR_ATTACHMENTS_MAX);
EXIT_IF(vs_spirv.empty());
EXIT_IF(ps_active && ps_spirv.empty());
Common::LockGuard lock(m_mutex);
auto& ctx = command.GetRegisters();
auto& sh_ctx = command.GetShaders();
const auto& vertex_info = sh_ctx->GetVs();
const auto& ps_regs = sh_ctx->GetPs();
const HW::BlendColor& bclr = ctx->GetBlendColor();
const auto& vertex_info = sh_ctx.GetVs();
const auto& ps_regs = sh_ctx.GetPs();
const HW::BlendColor& bclr = ctx.GetBlendColor();
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
for (uint32_t i = 0; i < color_count; i++) {
color_mask[i] = (colors[i].vulkan_buffer != nullptr
? colors[i].export_mapping.ApplyMask(render_target_mask_slot(
ctx->GetRenderTargetMask(), colors[i].target_slot))
ctx.GetRenderTargetMask(), colors[i].target_slot))
: 0);
}
const HW::ModeControl& mc = ctx->GetModeControl();
const HW::ModeControl& mc = ctx.GetModeControl();
auto vs_id = ShaderGetIdVS(&vertex_info, vs_input_info, true);
auto vs_id = ShaderGetIdVS(vertex_info, vs_input_info, true);
ShaderId ps_id {};
if (ps_active) {
ps_id = ShaderGetIdPS(&ps_regs, ps_input_info, true);
ps_id = ShaderGetIdPS(ps_regs, *ps_input_info, true);
}
PipelineStaticParameters static_params {};
GraphicsPipeline p {};
p.render_pass_id = framebuffer->render_pass_id;
p.render_pass_id = framebuffer.render_pass_id;
p.ps_shader_id = ps_id;
p.vs_shader_id = vs_id;
static_params.color_count = color_count;
if (ps_active && depth->depth_test_enable && ps_input_info->ps_execute_on_noop) {
if (ps_active && depth.depth_test_enable && ps_input_info->ps_execute_on_noop) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF("Pipeline: temporary: accepting EXEC_ON_NOOP with depth test enabled\n");
}
}
const auto& clip_control = ctx->GetClipControl();
const auto& clip_control = ctx.GetClipControl();
EXIT_NOT_IMPLEMENTED(!clip_control.IsZClipModeRepresentable());
static_params.negative_one_to_one = !clip_control.dx_clip_space;
static_params.depth_clip_enable = clip_control.IsZClipEnabled();
static_params.topology = topology;
static_params.samples = framebuffer->samples;
static_params.samples = framebuffer.samples;
static_params.sample_shading_enable =
ps_active && framebuffer->samples > 1 && ps_input_info->ps_sample_shading;
if (static_params.sample_shading_enable &&
!g_render_ctx->GetGraphicCtx()->sample_rate_shading_enabled) {
ps_active && framebuffer.samples > 1 && ps_input_info->ps_sample_shading;
if (static_params.sample_shading_enable && !m_graphics.sample_rate_shading_enabled) {
EXIT("Pipeline: sample-rate shading is required but unsupported by the host\n");
}
static_params.with_depth =
(depth->format != vk::Format::eUndefined && depth->vulkan_buffer != nullptr);
static_params.depth_test_enable = depth->depth_test_enable;
static_params.depth_write_enable = (depth->depth_write_enable && !depth->depth_clear_enable);
static_params.depth_compare_op = depth->depth_compare_op;
static_params.depth_bounds_test_enable = depth->depth_bounds_test_enable;
static_params.depth_min_bounds = depth->depth_min_bounds;
static_params.depth_max_bounds = depth->depth_max_bounds;
static_params.stencil_test_enable = depth->stencil_test_enable;
static_params.stencil_front = depth->stencil_static_front;
static_params.stencil_back = depth->stencil_static_back;
(depth.format != vk::Format::eUndefined && depth.vulkan_buffer != nullptr);
static_params.depth_test_enable = depth.depth_test_enable;
static_params.depth_write_enable = (depth.depth_write_enable && !depth.depth_clear_enable);
static_params.depth_compare_op = depth.depth_compare_op;
static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable;
static_params.depth_min_bounds = depth.depth_min_bounds;
static_params.depth_max_bounds = depth.depth_max_bounds;
static_params.stencil_test_enable = depth.stencil_test_enable;
static_params.stencil_front = depth.stencil_static_front;
static_params.stencil_back = depth.stencil_static_back;
for (uint32_t i = 0; i < RENDER_COLOR_ATTACHMENTS_MAX; i++) {
static_params.color_mask[i] = color_mask[i];
}
@@ -119,8 +119,8 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
static_params.face = mc.face;
for (uint32_t i = 0; i < color_count; i++) {
const auto& rt = ctx->GetRenderTarget(colors[i].target_slot);
const auto& bc = ctx->GetBlendControl(colors[i].target_slot);
const auto& rt = ctx.GetRenderTarget(colors[i].target_slot);
const auto& bc = ctx.GetBlendControl(colors[i].target_slot);
static_params.color_srcblend[i] = bc.color_srcblend;
static_params.color_comb_fcn[i] = bc.color_comb_fcn;
static_params.color_destblend[i] = bc.color_destblend;
@@ -145,13 +145,13 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
key.static_params = static_params;
if (auto iter = m_graphics_pipelines.find(key); iter != m_graphics_pipelines.end()) {
return iter->second.get();
return *iter->second;
}
if (graphics_debug_dump_enabled()) {
ShaderDbgDumpInputInfo(vs_input_info);
if (ps_active) {
ShaderDbgDumpInputInfo(ps_input_info);
ShaderDbgDumpInputInfo(*ps_input_info);
}
LOGF("PipelineTrace: shader binaries VS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64
" PS=0x%08" PRIx32 "/0x%08" PRIx32 " words=%" PRIu64 "\n",
@@ -162,9 +162,9 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
auto cached = std::make_unique<GraphicsPipeline>(p);
LogPipelineTrace("CreatePipelineInternal begin", vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.crc32);
CreatePipelineInternal(cached.get(), framebuffer->render_pass, vs_input_info, vs_spirv,
ps_input_info, ps_spirv, static_params, vs_id.hash0, vs_id.crc32,
ps_id.hash0, ps_id.crc32, ps_active);
CreatePipelineInternal(*cached, framebuffer.render_pass, vs_input_info, vs_spirv, ps_input_info,
ps_spirv, static_params, vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.crc32, ps_active);
LogPipelineTrace("CreatePipelineInternal done", vs_id.hash0, vs_id.crc32, ps_id.hash0,
ps_id.crc32);
@@ -174,16 +174,15 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
auto [iter, inserted] = m_graphics_pipelines.emplace(std::move(key), std::move(cached));
EXIT_IF(!inserted);
return iter->second.get();
return *iter->second;
}
PipelineCache::ComputePipeline*
PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
const HW::ComputeShaderInfo* cs_regs,
PipelineCache::ComputePipeline&
PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info,
const HW::ComputeShaderInfo& cs_regs,
std::span<const uint32_t> cs_spirv) {
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100);
EXIT_IF(cs_regs == nullptr);
EXIT_IF(cs_spirv.empty());
Common::LockGuard lock(m_mutex);
@@ -197,7 +196,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
key.cs_shader_id = p.cs_shader_id;
if (auto iter = m_compute_pipelines.find(key); iter != m_compute_pipelines.end()) {
return iter->second.get();
return *iter->second;
}
if (graphics_debug_dump_enabled()) {
@@ -205,7 +204,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
}
auto cached = std::make_unique<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_layout == nullptr);
@@ -213,6 +212,6 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
auto [iter, inserted] = m_compute_pipelines.emplace(std::move(key), std::move(cached));
EXIT_IF(!inserted);
return iter->second.get();
return *iter->second;
}
} // namespace Libs::Graphics
+27 -22
View File
@@ -17,9 +17,11 @@
namespace Libs::Graphics {
struct GraphicContext;
struct RenderColorInfo;
struct RenderDepthInfo;
struct VulkanFramebuffer;
class RenderCommandBuffer;
namespace HW {
class Context;
@@ -86,7 +88,9 @@ static_assert(sizeof(PipelineStaticParameters) ==
class PipelineCache {
public:
PipelineCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit PipelineCache(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~PipelineCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(PipelineCache);
@@ -105,13 +109,13 @@ public:
ShaderId cs_shader_id;
};
GraphicsPipeline* CreateGraphicsPipeline(
VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx,
HW::Shader* sh_ctx, ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology,
bool ps_active, std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv);
ComputePipeline* CreateComputePipeline(ShaderComputeInputInfo* input_info,
const HW::ComputeShaderInfo* cs_regs,
GraphicsPipeline& CreateGraphicsPipeline(
VulkanFramebuffer& framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info, RenderCommandBuffer& command,
ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool ps_active,
std::span<const uint32_t> vs_spirv, std::span<const uint32_t> ps_spirv);
ComputePipeline& CreateComputePipeline(ShaderComputeInputInfo& input_info,
const HW::ComputeShaderInfo& cs_regs,
std::span<const uint32_t> cs_spirv);
private:
@@ -136,12 +140,12 @@ private:
};
struct PipelineKeyHash {
static void Mix(std::size_t* hash, std::size_t value) {
*hash ^= value + static_cast<std::size_t>(0x9e3779b97f4a7c15ull) + (*hash << 6u) +
(*hash >> 2u);
static void Mix(std::size_t& hash, std::size_t value) {
hash ^= value + static_cast<std::size_t>(0x9e3779b97f4a7c15ull) + (hash << 6u) +
(hash >> 2u);
}
static void MixShaderId(std::size_t* hash, const ShaderId& id) {
static void MixShaderId(std::size_t& hash, const ShaderId& id) {
Mix(hash, id.hash0);
Mix(hash, id.crc32);
Mix(hash, id.ids.size());
@@ -150,7 +154,7 @@ private:
}
}
static void MixStaticParams(std::size_t* hash, const PipelineStaticParameters& params) {
static void MixStaticParams(std::size_t& hash, const PipelineStaticParameters& params) {
const auto* bytes = reinterpret_cast<const uint8_t*>(&params);
for (std::size_t i = 0; i < sizeof(params); i++) {
Mix(hash, bytes[i]);
@@ -161,10 +165,10 @@ private:
struct GraphicsPipelineKeyHash {
std::size_t operator()(const GraphicsPipelineKey& key) const {
std::size_t hash = 0;
PipelineKeyHash::Mix(&hash, key.render_pass_id);
PipelineKeyHash::MixShaderId(&hash, key.vs_shader_id);
PipelineKeyHash::MixShaderId(&hash, key.ps_shader_id);
PipelineKeyHash::MixStaticParams(&hash, key.static_params);
PipelineKeyHash::Mix(hash, key.render_pass_id);
PipelineKeyHash::MixShaderId(hash, key.vs_shader_id);
PipelineKeyHash::MixShaderId(hash, key.ps_shader_id);
PipelineKeyHash::MixStaticParams(hash, key.static_params);
return hash;
}
};
@@ -172,11 +176,12 @@ private:
struct ComputePipelineKeyHash {
std::size_t operator()(const ComputePipelineKey& key) const {
std::size_t hash = 0;
PipelineKeyHash::MixShaderId(&hash, key.cs_shader_id);
PipelineKeyHash::MixShaderId(hash, key.cs_shader_id);
return hash;
}
};
GraphicContext& m_graphics;
std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>,
GraphicsPipelineKeyHash>
m_graphics_pipelines;
@@ -187,16 +192,16 @@ private:
void LogPipelineTrace(const char* phase, uint32_t vs_hash0, uint32_t vs_crc32, uint32_t ps_hash0,
uint32_t ps_crc32);
void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo* vs_input_info,
void CreatePipelineInternal(PipelineCache::GraphicsPipeline& pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo& vs_input_info,
std::span<const uint32_t> vs_shader,
const ShaderPixelInputInfo* ps_input_info,
std::span<const uint32_t> ps_shader,
const PipelineStaticParameters& static_params, uint32_t vs_hash0,
uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32,
bool ps_active);
void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
const ShaderComputeInputInfo* input_info,
void CreatePipelineInternal(PipelineCache::ComputePipeline& pipeline,
const ShaderComputeInputInfo& input_info,
std::span<const uint32_t> cs_shader);
} // namespace Libs::Graphics
+36 -18
View File
@@ -33,6 +33,7 @@ struct VulkanFramebuffer;
struct RenderDepthInfo;
struct RenderColorInfo;
class BufferCache;
class RenderContext;
struct HtileClearTarget {
uint64_t address = 0;
@@ -68,7 +69,7 @@ private:
class CommandBuffer {
public:
explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); }
explicit CommandBuffer(int queue);
~CommandBuffer() { Free(); }
KYTY_CLASS_NO_COPY(CommandBuffer);
@@ -85,17 +86,18 @@ public:
vk::Semaphore signal_semaphore);
void SetDebugInfo(uint32_t op, uint64_t submit_id, uint32_t arg0 = 0, uint32_t arg1 = 0,
uint32_t arg2 = 0, uint32_t arg3 = 0, uint64_t arg4 = 0);
void BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors,
uint32_t color_count, RenderDepthInfo* depth) const;
void BeginRenderPass(VulkanFramebuffer& framebuffer, RenderColorInfo* colors,
uint32_t color_count, RenderDepthInfo& depth) const;
void EndRenderPass() const;
void WaitForFenceOnly();
void WaitForFence();
void WaitForFenceAndReset();
void DeleteAfterFence(VulkanBuffer* buffer);
void DeleteAfterFence(VulkanBuffer& buffer);
void RetainResourceUntilFence(std::shared_ptr<void> resource);
void RecycleDescriptorAfterFence(VulkanDescriptorSet* set);
void RecycleDescriptorAfterFence(VulkanDescriptorSet& set);
[[nodiscard]] vk::CommandBuffer Handle() const;
[[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; }
[[nodiscard]] int GetQueue() const { return m_queue; }
[[nodiscard]] bool IsExecute() const { return m_execute; }
[[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; }
@@ -111,6 +113,7 @@ private:
void DeleteBuffersAfterFence();
void RecycleDescriptorsAfterFence();
GraphicContext& m_graphics;
VulkanCommandPool* m_pool = nullptr;
uint32_t m_index = static_cast<uint32_t>(-1);
int m_queue = -1;
@@ -131,34 +134,49 @@ private:
HostStreamBuffer m_host_stream;
};
void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_type_and_size,
class RenderCommandBuffer final: public CommandBuffer {
public:
RenderCommandBuffer(int queue, HW::Context& registers, HW::UserConfig& user_config,
HW::Shader& shaders)
: CommandBuffer(queue), m_registers(registers), m_user_config(user_config),
m_shaders(shaders) {}
[[nodiscard]] HW::Context& GetRegisters() const noexcept { return m_registers; }
[[nodiscard]] HW::UserConfig& GetUserConfig() const noexcept { return m_user_config; }
[[nodiscard]] HW::Shader& GetShaders() const noexcept { return m_shaders; }
private:
HW::Context& m_registers;
HW::UserConfig& m_user_config;
HW::Shader& m_shaders;
};
void RenderDrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_type_and_size,
uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
uint32_t instance_count = 1, uint32_t render_target_slice_offset = 0,
int32_t vertex_offset_add = 0, uint32_t first_instance = 0);
void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_count,
void RenderDrawIndexAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count,
uint32_t flags, uint32_t render_target_slice_offset = 0,
uint32_t instance_count = 1, uint32_t first_vertex = 0,
uint32_t first_instance = 0);
void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::Shader* sh_ctx, uint32_t thread_group_x, uint32_t thread_group_y,
uint32_t thread_group_z, uint32_t mode);
void RenderDispatchDirect(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t thread_group_x,
uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode);
void GraphicsRenderInit();
void GraphicsRenderCreateContext();
void GraphicsRenderSetContext(RenderContext& context);
void GraphicsRenderReleaseThreadCommandPools();
[[nodiscard]] bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode,
ShaderBufferResource* descriptor,
uint32_t* packed_clear, uint64_t* size);
ShaderBufferResource& descriptor,
uint32_t& packed_clear, uint64_t& size);
[[nodiscard]] bool ResolveHtileClearTarget(const HW::DepthRenderTarget& target,
uint64_t descriptor_size, HtileClearTarget* resolved);
uint64_t descriptor_size, HtileClearTarget& resolved);
void GraphicsRenderMemoryBarrier(CommandBuffer* buffer);
void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size);
void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size);
void GraphicsRenderMemoryBarrier(CommandBuffer& buffer);
void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size);
void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size);
} // namespace Libs::Graphics
@@ -51,11 +51,8 @@ static uint64_t BufferDescriptorSize(const ShaderBufferResource& descriptor) {
}
bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor_size,
HtileClearTarget* resolved) {
if (resolved == nullptr) {
return false;
}
*resolved = {};
HtileClearTarget& resolved) {
resolved = {};
const bool has_stencil =
z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid);
const auto* depth_policy = FindDepthFormatPolicy(z.z_info.format);
@@ -112,7 +109,7 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor
if (!descriptor_backed_state) {
return false;
}
*resolved = {.address = z.htile_data_base_addr, .size = descriptor_size};
resolved = {.address = z.htile_data_base_addr, .size = descriptor_size};
return true;
}
const uint32_t width = size_xy_valid ? static_cast<uint32_t>(z.size.x_max) + 1u : z.width;
@@ -124,10 +121,10 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor
return false;
}
TileSizeAlign htile_size {};
if (!TileGetHtileSize(width, height, &htile_size) || htile_size.size != descriptor_size) {
if (!TileGetHtileSize(width, height, htile_size) || htile_size.size != descriptor_size) {
return false;
}
*resolved = {.address = z.htile_data_base_addr, .size = htile_size.size};
resolved = {.address = z.htile_data_base_addr, .size = htile_size.size};
return true;
}
@@ -154,9 +151,10 @@ static void ValidateFullHtileClearDispatch(const ShaderComputeInputInfo& input,
}
}
static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, const HW::Context& ctx,
uint32_t group_x, uint32_t group_y, uint32_t group_z,
uint32_t mode) {
static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input,
const RenderCommandBuffer& buffer, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode) {
const auto& ctx = buffer.GetRegisters();
const auto& program = *input.stage.program;
const auto& resources = *input.stage.resources;
if (resources.buffers.size() != program.info.buffers.size()) {
@@ -164,7 +162,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
}
const auto& z = ctx.GetDepthRenderTarget();
const uint64_t meta_addr = z.htile_data_base_addr;
auto* cache = g_render_ctx->GetTextureCache();
auto& cache = GetRenderContext().GetTextureCache();
uint32_t current_references = 0;
uint32_t registered_writes = 0;
uint64_t described_meta_size = 0;
@@ -182,7 +180,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
// identifiable even when it is no longer the currently bound depth target.
TextureCache::MetaRangeInfo resolved_meta {};
if (resource.written &&
cache->ResolveMetaRange(descriptor.Base48(), descriptor_size, &resolved_meta)) {
cache.ResolveMetaRange(descriptor.Base48(), descriptor_size, resolved_meta)) {
registered_writes++;
registered_target = {.address = descriptor.Base48(), .size = descriptor_size};
registered_meta = resolved_meta;
@@ -197,7 +195,7 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
}
HtileClearTarget target {};
if (current_references != 0) {
if (!ResolveHtileClearTarget(z, described_meta_size, &target)) {
if (!ResolveHtileClearTarget(z, described_meta_size, target)) {
EXIT("unsupported HTile compute-clear target state: current=%u registered=%u "
"meta=0x%016" PRIx64 "+0x%016" PRIx64 " depth=0x%016" PRIx64 "/0x%016" PRIx64
" stencil=0x%016" PRIx64 "/0x%016" PRIx64
@@ -210,14 +208,14 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
z.slice_div64_minus1, z.z_info.format, z.stencil_info.format,
z.z_info.num_samples);
}
cache->RegisterMeta(g_render_ctx->GetGraphicCtx(), target.address, target.size);
if (!cache->ResolveMetaRange(target.address, target.size, &registered_meta)) {
cache.RegisterMeta(target.address, target.size);
if (!cache.ResolveMetaRange(target.address, target.size, registered_meta)) {
EXIT("failed to resolve registered HTile compute-clear range\n");
}
} else {
target = registered_target;
}
g_render_ctx->GetBufferCache()->ValidateGpuAccess(target.address, target.size, false, true);
GetRenderContext().GetBufferCache().ValidateGpuAccess(target.address, target.size, false, true);
uint32_t metadata_writes = 0;
ShaderBufferResource metadata_descriptor {};
@@ -245,10 +243,10 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
}
if (resource.written || !resource.read || resource.atomic || descriptor.Base48() == 0 ||
descriptor_size == 0 ||
cache->QueryRegion(descriptor.Base48(), descriptor_size).metadata_pages) {
cache.QueryRegion(descriptor.Base48(), descriptor_size).metadata_pages) {
EXIT("unsupported HTile clear side-buffer access\n");
}
g_render_ctx->GetBufferCache()->ValidateGpuAccess(descriptor.Base48(), descriptor_size,
GetRenderContext().GetBufferCache().ValidateGpuAccess(descriptor.Base48(), descriptor_size,
true, false);
}
if (metadata_writes != 1) {
@@ -256,8 +254,8 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
metadata_writes);
}
ValidateFullHtileClearDispatch(input, metadata_descriptor, group_x, group_y, group_z, mode);
const bool recorded = registered_meta.full ? cache->ClearMeta(registered_meta.metadata_address)
: cache->TouchMeta(registered_meta.metadata_address,
const bool recorded = registered_meta.full ? cache.ClearMeta(registered_meta.metadata_address)
: cache.TouchMeta(registered_meta.metadata_address,
registered_meta.slice, true);
if (!recorded) {
EXIT("failed to record HTile compute clear\n");
@@ -267,11 +265,8 @@ static bool TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input, cons
bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode,
ShaderBufferResource* resolved_descriptor, uint32_t* resolved_clear,
uint64_t* resolved_size) {
if (resolved_descriptor == nullptr || resolved_clear == nullptr || resolved_size == nullptr) {
return false;
}
ShaderBufferResource& resolved_descriptor, uint32_t& resolved_clear,
uint64_t& resolved_size) {
const auto& program = *input.stage.program;
const auto& resources = *input.stage.resources;
if (program.info.buffers.size() != 1 || resources.buffers.size() != 1 ||
@@ -313,24 +308,24 @@ bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t grou
if (!full_dispatch || size == 0) {
return false;
}
*resolved_descriptor = descriptor;
*resolved_clear = clear;
*resolved_size = size;
resolved_descriptor = descriptor;
resolved_clear = clear;
resolved_size = size;
return true;
}
static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, CommandBuffer* command,
static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, CommandBuffer& command,
uint32_t group_x, uint32_t group_y, uint32_t group_z,
uint32_t mode) {
ShaderBufferResource descriptor;
uint32_t packed_clear = 0;
uint64_t size = 0;
if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, &descriptor,
&packed_clear, &size)) {
if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, descriptor, packed_clear,
size)) {
return false;
}
auto* cache = g_render_ctx->GetTextureCache();
if (!cache->ClearImageFromBuffer(command, descriptor.Base48(), size, packed_clear)) {
auto& cache = GetRenderContext().GetTextureCache();
if (!cache.ClearImageFromBuffer(command, descriptor.Base48(), size, packed_clear)) {
return false;
}
static std::atomic<uint32_t> logged_clears {0};
@@ -342,28 +337,26 @@ static bool TryConsumeComputeImageClear(const ShaderComputeInputInfo& input, Com
return true;
}
void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::Shader* sh_ctx, uint32_t thread_group_x, uint32_t thread_group_y,
uint32_t thread_group_z, uint32_t mode) {
EXIT_IF(ctx == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
void RenderDispatchDirect(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t thread_group_x,
uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode) {
EXIT_IF(buffer.IsInvalid());
auto& ctx = buffer.GetRegisters();
auto& sh_ctx = buffer.GetShaders();
buffer->SetDebugInfo(static_cast<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,
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, "
"groups=%ux%ux%u mode=%u\n",
thread_group_x, thread_group_y, thread_group_z, mode);
return;
}
if (!ShaderAddressValid(sh_ctx->GetCs().cs_regs.data_addr)) {
if (!ShaderAddressValid(sh_ctx.GetCs().cs_regs.data_addr)) {
return;
}
@@ -380,17 +373,17 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
LOGF("GraphicsRenderDispatchDirect: unknown dispatch initiator bits "
"mode=0x%08" PRIx32 " unknown=0x%08" PRIx32 " shader=0x%016" PRIx64
" groups=%ux%ux%u\n",
mode, unknown_mode_bits, sh_ctx->GetCs().cs_regs.data_addr, thread_group_x,
mode, unknown_mode_bits, sh_ctx.GetCs().cs_regs.data_addr, thread_group_x,
thread_group_y, thread_group_z);
}
}
const auto& cs_regs = sh_ctx->GetCs();
const auto& sh_regs = ctx->GetShaderRegisters();
const auto& cs_regs = sh_ctx.GetCs();
const auto& sh_regs = ctx.GetShaderRegisters();
ShaderComputeInputInfo input_info {};
std::span<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",
cs_regs.cs_regs.data_addr);
}
@@ -408,8 +401,8 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
(input_info.threads_num[0] * input_info.threads_num[1] * input_info.threads_num[2] >= 512);
const auto& program = *input_info.stage.program;
const auto& resources = *input_info.stage.resources;
if (TryConsumeComputeMetaClear(input_info, *ctx, thread_group_x, thread_group_y, thread_group_z,
mode)) {
if (TryConsumeComputeMetaClear(input_info, buffer, thread_group_x, thread_group_y,
thread_group_z, mode)) {
return;
}
if (TryConsumeComputeImageClear(input_info, buffer, thread_group_x, thread_group_y,
@@ -428,7 +421,7 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
LOGF("GraphicsRenderDispatchDirect: frame=%u shader=0x%016" PRIx64
" groups=%ux%ux%u mode=0x%08" PRIx32 " local=%ux%ux%u "
"buffers=%zu textures=%zu sampled=%zu storage=%zu samplers=%zu push=%u\n",
frame_num, sh_ctx->GetCs().cs_regs.data_addr, thread_group_x, thread_group_y,
frame_num, sh_ctx.GetCs().cs_regs.data_addr, thread_group_x, thread_group_y,
thread_group_z, mode, input_info.threads_num[0], input_info.threads_num[1],
input_info.threads_num[2], program.info.buffers.size(), program.info.images.size(),
sampled_images, program.info.images.size() - sampled_images,
@@ -503,23 +496,23 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
LOGF("GraphicsRenderDispatchDirect: skipping zero-sized dispatch groups=%ux%ux%u "
"mode=0x%08" PRIx32 " shader=0x%016" PRIx64 "\n",
thread_group_x, thread_group_y, thread_group_z, mode,
sh_ctx->GetCs().cs_regs.data_addr);
sh_ctx.GetCs().cs_regs.data_addr);
}
return;
}
for (;;) {
const auto recording_generation = buffer->GetRecordingGeneration();
auto vk_buffer = buffer->Handle();
auto* pipeline = g_render_ctx->GetPipelineCache()->CreateComputePipeline(
&input_info, &sh_ctx->GetCs(), cs_shader);
const auto recording_generation = buffer.GetRecordingGeneration();
auto vk_buffer = buffer.Handle();
auto& pipeline = GetRenderContext().GetPipelineCache().CreateComputePipeline(
input_info, sh_ctx.GetCs(), cs_shader);
vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->pipeline);
vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline.pipeline);
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eCompute,
pipeline->pipeline_layout, input_info.stage,
pipeline.pipeline_layout, input_info.stage,
vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute);
if (buffer->GetRecordingGeneration() != recording_generation) {
if (buffer.GetRecordingGeneration() != recording_generation) {
continue;
}
@@ -2,7 +2,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "graphics/presentation/window.h"
#include "kernel/pthread.h"
#include "libs/errno.h"
@@ -10,38 +9,11 @@
namespace Libs::Graphics {
void RenderContext::SetGraphicCtx(GraphicContext* ctx) {
EXIT_IF(ctx == nullptr);
Common::LockGuard lock(m_graphic_ctx_mutex);
m_graphic_ctx = ctx;
}
GraphicContext* RenderContext::GetGraphicCtx() {
{
Common::LockGuard lock(m_graphic_ctx_mutex);
if (m_graphic_ctx != nullptr) {
return m_graphic_ctx;
}
}
WindowWaitForGraphicInitialized();
auto* ctx = WindowGetGraphicContext();
LOGF("Graphic context initialized\n ctx = %p\n", static_cast<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;
RenderContext::RenderContext(GraphicContext& graphics)
: m_graphics(graphics), m_pipeline_cache(graphics), m_descriptor_cache(graphics),
m_framebuffer_cache(graphics), m_sampler_cache(graphics), m_gds_buffer(graphics),
m_gpu_resources(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
void RenderContext::AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id) {
+13 -14
View File
@@ -23,22 +23,21 @@ constexpr int AGC_USER_INTERRUPT_EVENT = 0x1800;
class RenderContext {
public:
RenderContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit RenderContext(GraphicContext& graphics);
~RenderContext() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(RenderContext);
void SetGraphicCtx(GraphicContext* ctx);
GraphicContext* GetGraphicCtx();
[[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; }
Common::Mutex& GetMutex() { return m_mutex; }
PipelineCache* GetPipelineCache() { return &m_pipeline_cache; }
DescriptorCache* GetDescriptorCache() { return &m_descriptor_cache; }
FramebufferCache* GetFramebufferCache() { return &m_framebuffer_cache; }
SamplerCache* GetSamplerCache() { return &m_sampler_cache; }
GdsBuffer* GetGdsBuffer() { return &m_gds_buffer; }
GpuResourceManager* GetGpuResources() { return &m_gpu_resources; }
BufferCache* GetBufferCache() { return m_gpu_resources.GetBufferCache(); }
TextureCache* GetTextureCache() { return m_gpu_resources.GetTextureCache(); }
PipelineCache& GetPipelineCache() { return m_pipeline_cache; }
DescriptorCache& GetDescriptorCache() { return m_descriptor_cache; }
FramebufferCache& GetFramebufferCache() { return m_framebuffer_cache; }
SamplerCache& GetSamplerCache() { return m_sampler_cache; }
GdsBuffer& GetGdsBuffer() { return m_gds_buffer; }
GpuResourceManager& GetGpuResources() { return m_gpu_resources; }
BufferCache& GetBufferCache() { return m_gpu_resources.GetBufferCache(); }
TextureCache& GetTextureCache() { return m_gpu_resources.GetTextureCache(); }
void AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id);
void DeleteEopEq(LibKernel::EventQueue::KernelEqueue eq, int id);
@@ -51,13 +50,12 @@ private:
uint32_t count = 0;
};
GraphicContext& m_graphics;
Common::Mutex m_mutex;
Common::Mutex m_graphic_ctx_mutex;
PipelineCache m_pipeline_cache;
DescriptorCache m_descriptor_cache;
FramebufferCache m_framebuffer_cache;
SamplerCache m_sampler_cache;
GraphicContext* m_graphic_ctx = nullptr;
GdsBuffer m_gds_buffer;
GpuResourceManager m_gpu_resources;
@@ -65,7 +63,8 @@ private:
std::vector<EopEqRegistration> m_eop_eqs;
};
extern RenderContext* g_render_ctx;
[[nodiscard]] bool HasRenderContext() noexcept;
[[nodiscard]] RenderContext& GetRenderContext();
} // 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_framebuffer_skip_log_count = 0;
static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
static bool ResolveColorTargets(uint64_t submit_id, RenderCommandBuffer& buffer,
uint32_t render_target_slice_offset);
static const char* RenderColorTypeName(RenderColorType type) {
@@ -87,8 +87,10 @@ static bool IsDualSourceBlendFactor(uint32_t factor) {
}
static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& color,
const RenderDepthInfo& depth, const HW::Context* ctx,
const HW::UserConfig* ucfg, uint32_t index_count, uint32_t flags) {
const RenderDepthInfo& depth, const RenderCommandBuffer& buffer,
uint32_t index_count, uint32_t flags) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
if (!graphics_debug_dump_enabled()) {
return;
}
@@ -104,19 +106,17 @@ static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& col
" prim=%u index_count=%u flags=0x%08" PRIx32 "\n",
log_id, draw_name, RenderColorTypeName(color.type), color.base_addr, color.buffer_size,
color.vulkan_buffer != nullptr ? "yes" : "no", VulkanToString(depth.format).c_str(),
depth.vulkan_buffer != nullptr ? "yes" : "no", depth.vaddr_num,
ctx != nullptr ? ctx->GetRenderTargetMask() : 0, ucfg != nullptr ? ucfg->GetPrimType() : 0,
index_count, flags);
depth.vulkan_buffer != nullptr ? "yes" : "no", depth.vaddr_num, ctx.GetRenderTargetMask(),
ucfg.GetPrimType(), index_count, flags);
}
static void LogMrtState(const char* draw_name, const HW::Context* ctx,
static void LogMrtState(const char* draw_name, const RenderCommandBuffer& buffer,
const ShaderPixelInputInfo& ps_input_info) {
EXIT_IF(ctx == nullptr);
const auto& sh_regs = ctx->GetShaderRegisters();
const auto rt_mask = ctx->GetRenderTargetMask();
const auto& ctx = buffer.GetRegisters();
const auto& sh_regs = ctx.GetShaderRegisters();
const auto rt_mask = ctx.GetRenderTargetMask();
const auto cb_shader_mask = sh_regs.m_cbShaderMask;
const auto& bc0 = ctx->GetBlendControl(0);
const auto& bc0 = ctx.GetBlendControl(0);
bool interesting = rt_mask != 0x0f || (cb_shader_mask & ~0x0fu) != 0 ||
IsDualSourceBlendFactor(bc0.color_srcblend) ||
@@ -125,7 +125,7 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx,
IsDualSourceBlendFactor(bc0.alpha_destblend)));
for (uint32_t i = 1; i < 8; i++) {
const auto& rt = ctx->GetRenderTarget(i);
const auto& rt = ctx.GetRenderTarget(i);
if (rt.base.addr != 0 || ps_input_info.target_output_mode[i] != 0 ||
((rt_mask >> (i * 4u)) & 0x0fu) != 0 || ((cb_shader_mask >> (i * 4u)) & 0x0fu) != 0) {
interesting = true;
@@ -148,8 +148,8 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx,
bc0.separate_alpha_blend ? "true" : "false");
for (uint32_t i = 0; i < 8; i++) {
const auto& rt = ctx->GetRenderTarget(i);
const auto& bc = ctx->GetBlendControl(i);
const auto& rt = ctx.GetRenderTarget(i);
const auto& bc = ctx.GetBlendControl(i);
const auto ctm = (rt_mask >> (i * 4u)) & 0x0fu;
const auto csm = (cb_shader_mask >> (i * 4u)) & 0x0fu;
@@ -171,10 +171,11 @@ static void LogMrtState(const char* draw_name, const HW::Context* ctx,
}
static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& color,
const RenderDepthInfo& depth, const HW::Context* ctx,
const HW::UserConfig* ucfg,
const RenderDepthInfo& depth, const RenderCommandBuffer& buffer,
const ShaderPixelInputInfo& ps_input_info, uint32_t index_count,
uint32_t flags) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
if (color.type == RenderColorType::NoColorOutput) {
return;
}
@@ -184,13 +185,10 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
return;
}
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
const auto& cc = ctx->GetColorControl();
const auto& bc = ctx->GetBlendControl(color.target_slot);
const auto& dc = ctx->GetDepthControl();
const auto& vp = ctx->GetScreenViewport();
const auto& cc = ctx.GetColorControl();
const auto& bc = ctx.GetBlendControl(color.target_slot);
const auto& dc = ctx.GetDepthControl();
const auto& vp = ctx.GetScreenViewport();
const auto& vp0 = vp.viewports[0];
const auto& ps_resources = ps_input_info.stage.program->info;
const auto sampled_images = std::count_if(
@@ -200,7 +198,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
});
vk::Extent2D extent = color.vulkan_buffer != nullptr ? color.extent : vk::Extent2D {};
auto sc = calc_final_scissor(vp, ctx->GetScanModeControl(), extent);
auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent);
LOGF(
"DrawTargetState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64
@@ -210,8 +208,8 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
" depth_test=%s depth_write=%s depth_func=%u depth_clear=%s viewport=(%.1f,%.1f %.1fx%.1f) "
"scissor=(%d,%d)-(%d,%d)\n",
log_id, GraphicsRunGetFrameNum(), draw_name, RenderColorTypeName(color.type),
color.base_addr, extent.width, extent.height, ucfg->GetPrimType(), index_count, flags,
ctx->GetRenderTargetMask(), color.color_clear_enable ? "true" : "false",
color.base_addr, extent.width, extent.height, ucfg.GetPrimType(), index_count, flags,
ctx.GetRenderTargetMask(), color.color_clear_enable ? "true" : "false",
color.color_clear_value.float32[0], color.color_clear_value.float32[1],
color.color_clear_value.float32[2], color.color_clear_value.float32[3], cc.mode, cc.op,
bc.enable ? "true" : "false", bc.color_srcblend, bc.color_destblend, bc.color_comb_fcn,
@@ -223,7 +221,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
vp0.yoffset - vp0.yscale, vp0.xscale * 2.0f, vp0.yscale * 2.0f, sc.left, sc.top, sc.right,
sc.bottom);
LogMrtState(draw_name, ctx, ps_input_info);
LogMrtState(draw_name, buffer, ps_input_info);
}
static void LogDrawInputState(const RenderColorInfo& color,
@@ -305,11 +303,11 @@ static void LogDrawInputState(const RenderColorInfo& color,
}
}
static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuffer command_buffer,
static void VulkanCmdSetColorWriteEnableEXT(const RenderCommandBuffer& buffer,
vk::CommandBuffer command_buffer,
uint32_t attachment_count,
const vk::Bool32* p_color_write_enables) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
EXIT_IF(buffer.GetGraphics().device == nullptr);
if (VULKAN_HPP_DEFAULT_DISPATCHER.vkCmdSetColorWriteEnableEXT == nullptr) {
EXIT("vkCmdSetColorWriteEnableEXT not present\n");
@@ -317,11 +315,12 @@ static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuff
command_buffer.setColorWriteEnableEXT(attachment_count, p_color_write_enables);
}
static PipelineDynamicParameters BuildGraphicsDynamicParams(const HW::Context& ctx,
static PipelineDynamicParameters BuildGraphicsDynamicParams(const RenderCommandBuffer& buffer,
const RenderColorInfo* colors,
uint32_t color_count,
const RenderDepthInfo& depth) {
EXIT_IF(colors == nullptr);
const auto& ctx = buffer.GetRegisters();
PipelineDynamicParameters ret {};
ret.color_write_count = color_count;
@@ -362,7 +361,7 @@ static PipelineDynamicParameters BuildGraphicsDynamicParams(const HW::Context&
return ret;
}
static void SetDynamicParams(vk::CommandBuffer vk_buffer,
static void SetDynamicParams(const RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer,
const PipelineDynamicParameters& dynamic_params) {
KYTY_PROFILER_FUNCTION();
@@ -414,14 +413,12 @@ static void SetDynamicParams(vk::CommandBuffer vk_buffer,
for (uint32_t i = 0; i < dynamic_params.color_write_count; i++) {
enable[i] = (dynamic_params.color_write_enable[i] ? VK_TRUE : VK_FALSE);
}
VulkanCmdSetColorWriteEnableEXT(g_render_ctx->GetGraphicCtx(), vk_buffer,
dynamic_params.color_write_count, enable);
VulkanCmdSetColorWriteEnableEXT(buffer, vk_buffer, dynamic_params.color_write_count, enable);
}
static bool DrawHasValidVertexShader(const HW::Shader* sh_ctx) {
EXIT_IF(sh_ctx == nullptr);
static bool DrawHasValidVertexShader(const HW::Shader& sh_ctx) {
const auto& vs = sh_ctx->GetVs();
const auto& vs = sh_ctx.GetVs();
return vs.gs_regs.chksum != 0 && ShaderAddressValid(vs.es_regs.data_addr);
}
@@ -432,16 +429,14 @@ static bool PixelShaderHasDepthOrCoverageSideEffects(const HW::ShaderRegisters&
db.shader_execute_on_noop;
}
static bool ShouldSkipGeShader(const HW::Context* ctx, const HW::UserConfig* ucfg,
const HW::Shader* sh_ctx) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(sh_ctx == nullptr);
const auto& sh_regs = ctx->GetShaderRegisters();
const auto& ge_cntl = ucfg->GetGeControl();
const auto& vertex_info = sh_ctx->GetVs();
const auto stages = ctx->GetShaderStages();
static bool ShouldSkipGeShader(const RenderCommandBuffer& buffer) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
const auto& sh_ctx = buffer.GetShaders();
const auto& sh_regs = ctx.GetShaderRegisters();
const auto& ge_cntl = ucfg.GetGeControl();
const auto& vertex_info = sh_ctx.GetVs();
const auto stages = ctx.GetShaderStages();
const auto is_known_gs_out_prim_type = [](uint32_t value) {
switch (static_cast<Prospero::GsOutputPrimitiveType>(value)) {
@@ -511,11 +506,11 @@ struct DrawCallInfo {
uint32_t first_instance = 0;
};
static bool DrawHasActivePixelShader(const HW::Context* ctx, const HW::Shader* sh_ctx,
static bool DrawHasActivePixelShader(const RenderCommandBuffer& buffer,
const DrawRenderState& state, const DrawCallInfo& draw) {
EXIT_IF(ctx == nullptr);
EXIT_IF(sh_ctx == nullptr);
EXIT_IF(draw.name == nullptr);
const auto& ctx = buffer.GetRegisters();
const auto& sh_ctx = buffer.GetShaders();
const bool with_depth = (state.depth_info.format != vk::Format::eUndefined &&
state.depth_info.vulkan_buffer != nullptr);
@@ -523,8 +518,8 @@ static bool DrawHasActivePixelShader(const HW::Context* ctx, const HW::Shader* s
return true;
}
const auto& sh_regs = ctx->GetShaderRegisters();
const auto& ps = sh_ctx->GetPs();
const auto& sh_regs = ctx.GetShaderRegisters();
const auto& ps = sh_ctx.GetPs();
return ShaderAddressValid(ps.ps_regs.data_addr) &&
PixelShaderHasDepthOrCoverageSideEffects(sh_regs);
}
@@ -538,7 +533,8 @@ enum class CbColorMode : uint8_t {
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;
// 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.
@@ -570,176 +566,160 @@ static uint64_t VertexBufferDescriptorSize(const ShaderVertexInputBuffer& buffer
: buffer.num_records);
}
static void SetDrawDebugPhase(CommandBuffer* buffer, uint64_t submit_id, const DrawCallInfo& draw,
uint32_t phase) {
EXIT_IF(buffer == nullptr);
static void SetDrawDebugPhase(RenderCommandBuffer& buffer, uint64_t submit_id,
const DrawCallInfo& draw, uint32_t phase) {
EXIT_IF(draw.name == nullptr);
buffer->SetDebugInfo(static_cast<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);
}
static bool GetDrawTopology(const HW::UserConfig* ucfg, bool auto_draw, bool use_ngg_rectlist_draw,
vk::PrimitiveTopology* topology) {
EXIT_IF(ucfg == nullptr);
EXIT_IF(topology == nullptr);
static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw, bool use_ngg_rectlist_draw,
vk::PrimitiveTopology& topology) {
*topology = vk::PrimitiveTopology::ePointList;
topology = vk::PrimitiveTopology::ePointList;
switch (static_cast<Prospero::PrimitiveType>(ucfg->GetPrimType())) {
switch (static_cast<Prospero::PrimitiveType>(ucfg.GetPrimType())) {
case Prospero::PrimitiveType::kNone: return false;
case Prospero::PrimitiveType::kPointList:
*topology = vk::PrimitiveTopology::ePointList;
break;
case Prospero::PrimitiveType::kLineList:
*topology = vk::PrimitiveTopology::eLineList;
topology = vk::PrimitiveTopology::ePointList;
break;
case Prospero::PrimitiveType::kLineList: topology = vk::PrimitiveTopology::eLineList; break;
case Prospero::PrimitiveType::kLineStrip:
*topology = vk::PrimitiveTopology::eLineStrip;
topology = vk::PrimitiveTopology::eLineStrip;
break;
case Prospero::PrimitiveType::kTriList:
*topology = vk::PrimitiveTopology::eTriangleList;
topology = vk::PrimitiveTopology::eTriangleList;
break;
case Prospero::PrimitiveType::kTriFan:
*topology = vk::PrimitiveTopology::eTriangleFan;
topology = vk::PrimitiveTopology::eTriangleFan;
break;
case Prospero::PrimitiveType::kTriStrip:
*topology = vk::PrimitiveTopology::eTriangleStrip;
topology = vk::PrimitiveTopology::eTriangleStrip;
break;
case Prospero::PrimitiveType::kRectList:
*topology = (auto_draw && use_ngg_rectlist_draw ? vk::PrimitiveTopology::eTriangleStrip
topology = (auto_draw && use_ngg_rectlist_draw ? vk::PrimitiveTopology::eTriangleStrip
: vk::PrimitiveTopology::eTriangleList);
break;
case Prospero::PrimitiveType::kRectListLegacy:
if (!auto_draw) {
EXIT("unknown primitive type: %u\n", ucfg->GetPrimType());
EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
}
*topology = vk::PrimitiveTopology::eTriangleStrip;
topology = vk::PrimitiveTopology::eTriangleStrip;
break;
case Prospero::PrimitiveType::kQuadListLegacy:
*topology = vk::PrimitiveTopology::eTriangleFan;
topology = vk::PrimitiveTopology::eTriangleFan;
break;
default: EXIT("unknown primitive type: %u\n", ucfg->GetPrimType());
default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
}
return true;
}
static bool PrepareDrawRenderState(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx,
static bool PrepareDrawRenderState(uint64_t submit_id, RenderCommandBuffer& buffer,
const DrawCallInfo& draw, uint32_t render_target_slice_offset,
bool skip_null_framebuffer, bool log_setup_phases,
DrawRenderState* state) {
EXIT_IF(buffer == nullptr);
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(sh_ctx == nullptr);
DrawRenderState& state) {
EXIT_IF(draw.name == nullptr);
EXIT_IF(state == nullptr);
auto& ctx = buffer.GetRegisters();
if (log_setup_phases) {
LogDrawPhase(draw.name, "ResolveRenderDepthTarget");
}
ResolveRenderDepthTarget(submit_id, buffer, *ctx, &state->depth_info);
ResolveRenderDepthTarget(submit_id, buffer, state.depth_info);
if (ResolveColorTargets(submit_id, buffer, *ctx, render_target_slice_offset)) {
MarkRenderTargetGpuWritten(state->depth_info);
if (ResolveColorTargets(submit_id, buffer, render_target_slice_offset)) {
MarkRenderTargetGpuWritten(state.depth_info);
return false;
}
MarkRenderTargetGpuWritten(state->depth_info);
MarkRenderTargetGpuWritten(state.depth_info);
if (log_setup_phases) {
LogDrawPhase(draw.name, "ResolveRenderColorTarget");
}
for (uint32_t slot = 0; slot < RENDER_COLOR_ATTACHMENTS_MAX; slot++) {
if (slot == 0 || (render_target_mask_slot(ctx->GetRenderTargetMask(), slot) != 0 &&
ctx->GetRenderTarget(slot).base.addr != 0)) {
ResolveRenderColorTarget(submit_id, buffer, *ctx,
&state->color_info[state->color_count],
if (slot == 0 || (render_target_mask_slot(ctx.GetRenderTargetMask(), slot) != 0 &&
ctx.GetRenderTarget(slot).base.addr != 0)) {
ResolveRenderColorTarget(submit_id, buffer, state.color_info[state.color_count],
render_target_slice_offset, slot);
if (state->color_info[state->color_count].vulkan_buffer != nullptr) {
MarkRenderTargetGpuWritten(state->color_info[state->color_count]);
state->color_count++;
if (state.color_info[state.color_count].vulkan_buffer != nullptr) {
MarkRenderTargetGpuWritten(state.color_info[state.color_count]);
state.color_count++;
}
}
}
const bool with_depth = (state->depth_info.format != vk::Format::eUndefined &&
state->depth_info.vulkan_buffer != nullptr);
if (state->color_count == 0 && !with_depth) {
LogFramebufferSkip(draw.name, state->color_info[0], state->depth_info, ctx, ucfg,
const bool with_depth = (state.depth_info.format != vk::Format::eUndefined &&
state.depth_info.vulkan_buffer != nullptr);
if (state.color_count == 0 && !with_depth) {
LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer,
draw.index_count, draw.flags);
return false;
}
state->ps_active = DrawHasActivePixelShader(ctx, sh_ctx, *state, draw);
state.ps_active = DrawHasActivePixelShader(buffer, state, draw);
if (log_setup_phases) {
LogDrawPhase(draw.name, "CreateFramebuffer");
}
state->framebuffer = g_render_ctx->GetFramebufferCache()->CreateFramebuffer(
state->color_info, state->color_count, &state->depth_info);
state.framebuffer = GetRenderContext().GetFramebufferCache().CreateFramebuffer(
state.color_info, state.color_count, state.depth_info);
if (state->framebuffer == nullptr && skip_null_framebuffer) {
LogFramebufferSkip(draw.name, state->color_info[0], state->depth_info, ctx, ucfg,
if (state.framebuffer == nullptr && skip_null_framebuffer) {
LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer,
draw.index_count, draw.flags);
return false;
}
EXIT_NOT_IMPLEMENTED(state->framebuffer == nullptr);
EXIT_NOT_IMPLEMENTED(state->framebuffer->render_pass == nullptr);
EXIT_NOT_IMPLEMENTED(state.framebuffer == nullptr);
EXIT_NOT_IMPLEMENTED(state.framebuffer->render_pass == nullptr);
state->vk_buffer = buffer->Handle();
state.vk_buffer = buffer.Handle();
return true;
}
static void RefreshShaders(HW::Context* ctx, HW::Shader* sh_ctx, const DrawCallInfo& draw,
bool log_phases, DrawRenderState* state) {
EXIT_IF(ctx == nullptr);
EXIT_IF(sh_ctx == nullptr);
static void RefreshShaders(RenderCommandBuffer& buffer, const DrawCallInfo& draw, bool log_phases,
DrawRenderState& state) {
EXIT_IF(draw.name == nullptr);
EXIT_IF(state == nullptr);
auto& ctx = buffer.GetRegisters();
auto& sh_ctx = buffer.GetShaders();
const auto& vertex_shader_info = sh_ctx->GetVs();
const auto& pixel_shader_info = sh_ctx->GetPs();
const auto& shader_regs = ctx->GetShaderRegisters();
const auto& vertex_shader_info = sh_ctx.GetVs();
const auto& pixel_shader_info = sh_ctx.GetPs();
const auto& shader_regs = ctx.GetShaderRegisters();
state->vs_shader = {};
state->ps_shader = {};
state->ps_input_info = {};
state.vs_shader = {};
state.ps_shader = {};
state.ps_input_info = {};
std::array<Prospero::ColorComponentMapping, RENDER_COLOR_ATTACHMENTS_MAX>
target_export_mapping {};
for (uint32_t i = 0; i < state->color_count; i++) {
target_export_mapping[state->color_info[i].target_slot] =
state->color_info[i].export_mapping;
for (uint32_t i = 0; i < state.color_count; i++) {
target_export_mapping[state.color_info[i].target_slot] = state.color_info[i].export_mapping;
}
EXIT_IF(g_render_ctx == nullptr || g_render_ctx->GetGraphicCtx() == nullptr);
const auto lane_mask_mode = SelectGraphicsLaneMaskMode(*g_render_ctx->GetGraphicCtx(), 64u);
const auto lane_mask_mode = SelectGraphicsLaneMaskMode(64u);
if (log_phases) {
LogDrawPhase(draw.name, "ShaderCompileInfoVS");
}
if (!ShaderCompileInfoVS(&vertex_shader_info, &shader_regs, lane_mask_mode,
&state->vs_input_info, &state->vs_shader)) {
if (!ShaderCompileInfoVS(vertex_shader_info, shader_regs, lane_mask_mode, state.vs_input_info,
state.vs_shader)) {
EXIT("ShaderCompileInfoVS failed for draw %s\n", draw.name);
}
if (!state->ps_active) {
if (!state.ps_active) {
return;
}
if (log_phases) {
LogDrawPhase(draw.name, "ShaderCompileInfoPS");
}
if (!ShaderCompileInfoPS(&pixel_shader_info, &shader_regs, lane_mask_mode,
&state->vs_input_info, target_export_mapping, &state->ps_input_info,
&state->ps_shader)) {
if (!ShaderCompileInfoPS(pixel_shader_info, shader_regs, lane_mask_mode, state.vs_input_info,
target_export_mapping, state.ps_input_info, state.ps_shader)) {
EXIT("ShaderCompileInfoPS failed for draw %s\n", draw.name);
}
}
static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer,
static void BindDrawVertexBuffers(uint64_t submit_id, RenderCommandBuffer& buffer,
const DrawCallInfo& draw, vk::CommandBuffer vk_buffer,
const ShaderVertexInputInfo& vs_input_info) {
EXIT_IF(buffer == nullptr);
EXIT_IF(draw.name == nullptr);
(void)submit_id;
@@ -752,13 +732,11 @@ static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer,
vk::DeviceSize offset = 0;
if (size == 0) {
vertices = g_render_ctx->GetBufferCache()->ObtainNullBuffer(
buffer, g_render_ctx->GetGraphicCtx());
vertices = &GetRenderContext().GetBufferCache().ObtainNullBuffer(buffer);
} else {
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
buffer, g_render_ctx->GetGraphicCtx(), addr, size);
vertices = binding.first;
offset = binding.second;
auto binding = GetRenderContext().GetBufferCache().ObtainBuffer(buffer, addr, size);
vertices = &binding.buffer;
offset = binding.offset;
}
EXIT_NOT_IMPLEMENTED(vertices == nullptr);
@@ -766,7 +744,7 @@ static void BindDrawVertexBuffers(uint64_t submit_id, CommandBuffer* buffer,
}
}
static void BindDrawIndexBuffer(CommandBuffer* buffer, vk::CommandBuffer vk_buffer,
static void BindDrawIndexBuffer(RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer,
const DrawIndexBufferSource& source) {
if (!source.enabled) {
return;
@@ -777,27 +755,24 @@ static void BindDrawIndexBuffer(CommandBuffer* buffer, vk::CommandBuffer vk_buff
vk::DeviceSize index_offset = 0;
if (source.host_data != nullptr) {
vk::DeviceSize range = 0;
if (!g_render_ctx->GetBufferCache()->UploadHostData(buffer, g_render_ctx->GetGraphicCtx(),
source.host_data, source.size, 16,
&index_buffer, &index_offset, &range)) {
if (!GetRenderContext().GetBufferCache().UploadHostData(
buffer, source.host_data, source.size, 16, index_buffer, index_offset, range)) {
EXIT("failed to upload host index buffer\n");
}
} else {
auto binding = g_render_ctx->GetBufferCache()->ObtainBuffer(
buffer, g_render_ctx->GetGraphicCtx(), source.address, source.size);
index_buffer = binding.first;
index_offset = binding.second;
auto binding =
GetRenderContext().GetBufferCache().ObtainBuffer(buffer, source.address, source.size);
index_buffer = &binding.buffer;
index_offset = binding.offset;
}
EXIT_IF(index_buffer == nullptr);
vk_buffer.bindIndexBuffer(index_buffer->buffer, index_offset, source.type);
}
static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const DrawCallInfo& draw,
static void LogDrawStateIfNeeded(const RenderCommandBuffer& buffer, const DrawCallInfo& draw,
const DrawRenderState& state, bool always_log,
bool force_legacy_rect_log, uint32_t index_type_and_size,
const void* index_addr) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(draw.name == nullptr);
if (!graphics_debug_dump_enabled()) {
@@ -809,7 +784,7 @@ static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const D
}
if (state.ps_active) {
LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, ctx, ucfg,
LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, buffer,
state.ps_input_info, draw.index_count, draw.flags);
}
LogDrawInputState(state.color_info[0], state.vs_input_info, index_type_and_size,
@@ -831,13 +806,12 @@ static bool IsHostExpandedRectListDrawSupported(const ShaderVertexInputInfo& vs_
return draw.index_count == 3 || draw.index_count == emit.draw_vertex_count;
}
static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_buffer,
static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_buffer,
const ShaderVertexInputInfo& vs_input_info, const DrawCallInfo& draw,
const DrawEmitInfo& emit) {
EXIT_IF(ucfg == nullptr);
EXIT_IF(draw.name == nullptr);
switch (static_cast<Prospero::PrimitiveType>(ucfg->GetPrimType())) {
switch (static_cast<Prospero::PrimitiveType>(ucfg.GetPrimType())) {
case Prospero::PrimitiveType::kPointList:
case Prospero::PrimitiveType::kLineList:
case Prospero::PrimitiveType::kLineStrip:
@@ -865,7 +839,7 @@ static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_
break;
case Prospero::PrimitiveType::kRectListLegacy:
if (emit.indexed) {
EXIT("unknown primitive type: %u\n", ucfg->GetPrimType());
EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
}
// Sarah
EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0));
@@ -883,67 +857,63 @@ static void EmitDrawPrimitives(const HW::UserConfig* ucfg, vk::CommandBuffer vk_
}
}
break;
default: EXIT("unknown primitive type: %u\n", ucfg->GetPrimType());
default: EXIT("unknown primitive type: %u\n", ucfg.GetPrimType());
}
}
static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, const DrawCallInfo& draw,
DrawRenderState* state, vk::PrimitiveTopology topology,
const DrawEmitInfo& emit, const DrawIndexBufferSource& index_source,
bool log_pipeline_phase, bool set_bind_debug, bool set_auto_debug) {
EXIT_IF(buffer == nullptr);
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(sh_ctx == nullptr);
static void ExecutePreparedDraw(uint64_t submit_id, RenderCommandBuffer& buffer,
const DrawCallInfo& draw, DrawRenderState& state,
vk::PrimitiveTopology topology, const DrawEmitInfo& emit,
const DrawIndexBufferSource& index_source, bool log_pipeline_phase,
bool set_bind_debug, bool set_auto_debug) {
EXIT_IF(draw.name == nullptr);
EXIT_IF(state == nullptr);
auto& ucfg = buffer.GetUserConfig();
for (;;) {
const auto recording_generation = buffer->GetRecordingGeneration();
const auto recording_generation = buffer.GetRecordingGeneration();
if (log_pipeline_phase) {
LogDrawPhase(draw.name, "CreatePipeline");
}
auto* pipeline = g_render_ctx->GetPipelineCache()->CreateGraphicsPipeline(
state->framebuffer, state->color_info, state->color_count, &state->depth_info,
&state->vs_input_info, ctx, sh_ctx, &state->ps_input_info, topology, state->ps_active,
state->vs_shader, state->ps_shader);
auto& pipeline = GetRenderContext().GetPipelineCache().CreateGraphicsPipeline(
*state.framebuffer, state.color_info, state.color_count, state.depth_info,
state.vs_input_info, buffer, &state.ps_input_info, topology, state.ps_active,
state.vs_shader, state.ps_shader);
if (set_bind_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x100u);
}
state->vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline->pipeline);
const auto dynamic_params = BuildGraphicsDynamicParams(
*ctx, state->color_info, state->color_count, state->depth_info);
SetDynamicParams(state->vk_buffer, dynamic_params);
state.vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.pipeline);
const auto dynamic_params = BuildGraphicsDynamicParams(buffer, state.color_info,
state.color_count, state.depth_info);
SetDynamicParams(buffer, state.vk_buffer, dynamic_params);
// EXIT_NOT_IMPLEMENTED(vs_input_info.buffers_num > 1);
BindDrawVertexBuffers(submit_id, buffer, draw, state->vk_buffer, state->vs_input_info);
BindDrawVertexBuffers(submit_id, buffer, draw, state.vk_buffer, state.vs_input_info);
LogDrawPhase(draw.name, "BindDescriptorsVS");
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x200u);
}
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
pipeline->pipeline_layout, state->vs_input_info.stage,
pipeline.pipeline_layout, state.vs_input_info.stage,
vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex);
if (state->ps_active) {
if (state.ps_active) {
LogDrawPhase(draw.name, "BindDescriptorsPS");
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x300u);
}
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
pipeline->pipeline_layout, state->ps_input_info.stage,
pipeline.pipeline_layout, state.ps_input_info.stage,
vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel);
}
if (buffer->GetRecordingGeneration() != recording_generation) {
if (buffer.GetRecordingGeneration() != recording_generation) {
continue;
}
// Index data may use this command buffer's host stream. Resolve it only after the other
// fault-capable bindings, and rebuild it whenever a fault reset changes the generation.
BindDrawIndexBuffer(buffer, state->vk_buffer, index_source);
if (buffer->GetRecordingGeneration() != recording_generation) {
BindDrawIndexBuffer(buffer, state.vk_buffer, index_source);
if (buffer.GetRecordingGeneration() != recording_generation) {
continue;
}
@@ -951,29 +921,29 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x400u);
}
buffer->BeginRenderPass(state->framebuffer, state->color_info, state->color_count,
&state->depth_info);
buffer.BeginRenderPass(*state.framebuffer, state.color_info, state.color_count,
state.depth_info);
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x500u);
}
EmitDrawPrimitives(ucfg, state->vk_buffer, state->vs_input_info, draw, emit);
EmitDrawPrimitives(ucfg, state.vk_buffer, state.vs_input_info, draw, emit);
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x600u);
}
buffer->EndRenderPass();
buffer.EndRenderPass();
vk::PipelineStageFlags shader_write_stages = {};
if (HasShaderBufferWrites(state->vs_input_info.stage)) {
if (HasShaderBufferWrites(state.vs_input_info.stage)) {
shader_write_stages |= vk::PipelineStageFlagBits::eVertexShader;
}
if (state->ps_active) {
if (HasShaderBufferWrites(state->ps_input_info.stage)) {
if (state.ps_active) {
if (HasShaderBufferWrites(state.ps_input_info.stage)) {
shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader;
}
}
if (shader_write_stages) {
ShaderWriteBarrier(state->vk_buffer, shader_write_stages);
ShaderWriteBarrier(state.vk_buffer, shader_write_stages);
}
LogDrawPhase(draw.name, "EndRenderPass");
if (set_auto_debug) {
@@ -983,30 +953,27 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
}
}
void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_type_and_size,
void RenderDrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_type_and_size,
uint32_t index_count, const void* index_addr, uint32_t flags, uint32_t type,
uint32_t instance_count, uint32_t render_target_slice_offset,
int32_t vertex_offset_add, uint32_t first_instance) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr);
EXIT_IF(ucfg == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
EXIT_IF(buffer.IsInvalid());
auto& ucfg = buffer.GetUserConfig();
auto& sh_ctx = buffer.GetShaders();
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndex), submit_id,
buffer.SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::DrawIndex), submit_id,
index_count, flags, type, instance_count,
reinterpret_cast<uint64_t>(index_addr));
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
if (index_count == 0) {
return;
}
if (ConsumeMetadataColorOperation(*ctx)) {
if (ConsumeMetadataColorOperation(buffer)) {
return;
}
@@ -1014,14 +981,14 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
return;
}
if (ShouldSkipGeShader(ctx, ucfg, sh_ctx)) {
if (ShouldSkipGeShader(buffer)) {
return;
}
if (graphics_debug_dump_enabled()) {
sh_print("GraphicsRenderDrawIndex():Shader:", *sh_ctx);
uc_print("GraphicsRenderDrawIndex():UserConfig:", *ucfg);
hw_print(*ctx);
sh_print("GraphicsRenderDrawIndex():Shader:", sh_ctx);
uc_print("GraphicsRenderDrawIndex():UserConfig:", ucfg);
hw_print(buffer);
LOGF("GraphicsRenderDrawIndex():Parameters:\n"
"\t index_type_and_size = 0x%08" PRIx32 "\n"
@@ -1037,14 +1004,14 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
instance_count, render_target_slice_offset, static_cast<uint32_t>(vertex_offset_add),
first_instance);
}
sh_check(*sh_ctx);
sh_check(sh_ctx);
uc_check(*ucfg);
uc_check(ucfg);
hw_check(*ctx);
hw_check(buffer);
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
if (!GetDrawTopology(ucfg, false, false, &topology)) {
if (!GetDrawTopology(ucfg, false, false, topology)) {
return;
}
@@ -1099,47 +1066,46 @@ void RenderDrawIndex(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx
index_source.type = index_type;
DrawRenderState state {};
if (!PrepareDrawRenderState(submit_id, buffer, ctx, ucfg, sh_ctx, draw,
render_target_slice_offset, false, true, &state)) {
if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, false, true,
state)) {
return;
}
RefreshShaders(ctx, sh_ctx, draw, true, &state);
RefreshShaders(buffer, draw, true, state);
LogDrawStateIfNeeded(ctx, ucfg, draw, state, true, false, index_type_and_size, index_addr);
LogDrawStateIfNeeded(buffer, draw, state, true, false, index_type_and_size, index_addr);
const auto vertex_offset =
ResolveVertexOffset(ucfg->GetIndexOffset(), state.vs_input_info) + vertex_offset_add;
ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) + vertex_offset_add;
DrawEmitInfo emit {};
emit.indexed = true;
emit.vertex_offset = vertex_offset;
ExecutePreparedDraw(submit_id, buffer, ctx, ucfg, sh_ctx, draw, &state, topology, emit,
index_source, true, true, false);
ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, true, true,
false);
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context* ctx,
HW::UserConfig* ucfg, HW::Shader* sh_ctx, uint32_t index_count,
void RenderDrawIndexAuto(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_count,
uint32_t flags, uint32_t render_target_slice_offset,
uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ucfg == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(buffer == nullptr || buffer->IsInvalid());
EXIT_IF(buffer.IsInvalid());
auto& ucfg = buffer.GetUserConfig();
auto& sh_ctx = buffer.GetShaders();
buffer->SetDebugInfo(static_cast<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);
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
if (index_count == 0) {
return;
}
if (ConsumeMetadataColorOperation(*ctx)) {
if (ConsumeMetadataColorOperation(buffer)) {
return;
}
@@ -1147,14 +1113,14 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
return;
}
if (ShouldSkipGeShader(ctx, ucfg, sh_ctx)) {
if (ShouldSkipGeShader(buffer)) {
return;
}
if (graphics_debug_dump_enabled()) {
sh_print("GraphicsRenderDrawIndexAuto():Shader:", *sh_ctx);
uc_print("GraphicsRenderDrawIndexAuto():UserConfig:", *ucfg);
hw_print(*ctx);
sh_print("GraphicsRenderDrawIndexAuto():Shader:", sh_ctx);
uc_print("GraphicsRenderDrawIndexAuto():UserConfig:", ucfg);
hw_print(buffer);
LOGF("GraphicsRenderDrawIndexAuto():Parameters:\n"
"\t index_count = 0x%08" PRIx32 "\n"
@@ -1166,11 +1132,11 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
index_count, flags, render_target_slice_offset, instance_count, first_vertex,
first_instance);
}
sh_check(*sh_ctx);
sh_check(sh_ctx);
uc_check(*ucfg);
uc_check(ucfg);
hw_check(*ctx);
hw_check(buffer);
EXIT_NOT_IMPLEMENTED(flags != 0);
if (instance_count == 0) {
@@ -1182,41 +1148,41 @@ void RenderDrawIndexAuto(uint64_t submit_id, CommandBuffer* buffer, HW::Context*
instance_count, first_instance};
DrawRenderState state {};
if (!PrepareDrawRenderState(submit_id, buffer, ctx, ucfg, sh_ctx, draw,
render_target_slice_offset, true, false, &state)) {
if (!PrepareDrawRenderState(submit_id, buffer, draw, render_target_slice_offset, true, false,
state)) {
return;
}
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
const bool use_ngg_rectlist_draw = Config::NggRectlistDrawEnabled();
if (!GetDrawTopology(ucfg, true, use_ngg_rectlist_draw, &topology)) {
if (!GetDrawTopology(ucfg, true, use_ngg_rectlist_draw, topology)) {
return;
}
const bool draw_prim7_as_ngg =
(use_ngg_rectlist_draw &&
ucfg->GetPrimType() == Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectList));
ucfg.GetPrimType() == Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectList));
RefreshShaders(ctx, sh_ctx, draw, false, &state);
RefreshShaders(buffer, draw, false, state);
if (draw_prim7_as_ngg && state.vs_input_info.buffers_num == 0 &&
state.vs_input_info.param_export_mask == 0 && state.ps_input_info.input_num != 0) {
if (graphics_debug_dump_enabled()) {
LOGF("DrawIndexAuto: skipping rect-list draw with no VS param exports and PS inputs: "
"ps_inputs=%u ps=0x%016" PRIx64 " es=0x%016" PRIx64 " gs=0x%016" PRIx64 "\n",
state.ps_input_info.input_num, sh_ctx->GetPs().ps_regs.chksum,
sh_ctx->GetVs().es_regs.data_addr, sh_ctx->GetVs().gs_regs.data_addr);
state.ps_input_info.input_num, sh_ctx.GetPs().ps_regs.chksum,
sh_ctx.GetVs().es_regs.data_addr, sh_ctx.GetVs().gs_regs.data_addr);
}
return;
}
LogDrawStateIfNeeded(ctx, ucfg, draw, state, false,
ucfg->GetPrimType() ==
LogDrawStateIfNeeded(buffer, draw, state, false,
ucfg.GetPrimType() ==
Prospero::GpuEnumValue(Prospero::PrimitiveType::kRectListLegacy),
0, nullptr);
const uint32_t draw_vertex_count = (draw_prim7_as_ngg ? 4u : index_count);
const auto vertex_offset = ResolveVertexOffset(ucfg->GetIndexOffset(), state.vs_input_info) +
const auto vertex_offset = ResolveVertexOffset(ucfg.GetIndexOffset(), state.vs_input_info) +
static_cast<int32_t>(first_vertex);
DrawEmitInfo emit {};
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);
DrawIndexBufferSource index_source {};
ExecutePreparedDraw(submit_id, buffer, ctx, ucfg, sh_ctx, draw, &state, topology, emit,
index_source, false, false, true);
ExecutePreparedDraw(submit_id, buffer, draw, state, topology, emit, index_source, false, false,
true);
}
bool IsSameColorResolveSubresource(const RenderColorInfo& src, const RenderColorInfo& dst) {
@@ -1235,8 +1201,7 @@ bool IsSameColorResolveSubresource(const RenderColorInfo& src, const RenderColor
ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColorInfo& dst,
uint32_t width, uint32_t height) {
ImageImageCopy region {};
region.src_image = src.vulkan_buffer;
ImageImageCopy region {*src.vulkan_buffer};
region.src_level = src.base_mip_level;
region.dst_level = dst.base_mip_level;
region.width = width;
@@ -1246,8 +1211,9 @@ ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColo
return region;
}
static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
static bool ResolveColorTargets(uint64_t submit_id, RenderCommandBuffer& buffer,
uint32_t render_target_slice_offset) {
const auto& hw = buffer.GetRegisters();
if (hw.GetColorControl().mode != 3) {
return false;
}
@@ -1260,9 +1226,8 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const
RenderColorInfo src {};
RenderColorInfo dst {};
ResolveRenderColorTarget(submit_id, buffer, hw, &src, render_target_slice_offset, 0, true,
true);
ResolveRenderColorTarget(submit_id, buffer, hw, &dst, render_target_slice_offset, 1, true);
ResolveRenderColorTarget(submit_id, buffer, src, render_target_slice_offset, 0, true, true);
ResolveRenderColorTarget(submit_id, buffer, dst, render_target_slice_offset, 1, true);
if (src.vulkan_buffer == nullptr || dst.vulkan_buffer == nullptr ||
src.type == RenderColorType::NoColorOutput || dst.type == RenderColorType::NoColorOutput) {
return false;
@@ -1280,7 +1245,7 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const
const std::array regions {MakeColorResolveCopy(src, dst, width, height)};
MarkRenderTargetGpuWritten(dst);
Transfer::CopyImage(buffer, regions, dst.vulkan_buffer, dst.vulkan_buffer->layout);
Transfer::CopyImage(buffer, regions, *dst.vulkan_buffer, dst.vulkan_buffer->layout);
return true;
}
@@ -28,13 +28,12 @@
namespace Libs::Graphics {
void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) {
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
void GraphicsRenderMemoryBarrier(CommandBuffer& buffer) {
EXIT_IF(buffer.IsInvalid());
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
auto vk_buffer = buffer->Handle();
auto vk_buffer = buffer.Handle();
VulkanMemoryBarrier mem_barrier {};
mem_barrier.sType = vk::StructureType::eMemoryBarrier;
@@ -47,8 +46,7 @@ void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) {
&mem_barrier, 0, nullptr, 0, nullptr);
}
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image) {
EXIT_IF(image == nullptr);
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) {
vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier;
@@ -57,16 +55,16 @@ void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* imag
vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eTransferWrite |
vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryRead;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
image_memory_barrier.oldLayout = image->layout;
image_memory_barrier.oldLayout = image.layout;
image_memory_barrier.newLayout = RENDER_COLOR_IMAGE_LAYOUT;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image->image;
image_memory_barrier.image = image.image;
image_memory_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers;
image_memory_barrier.subresourceRange.layerCount = image.layers;
vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eColorAttachmentOutput |
@@ -76,21 +74,19 @@ void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* imag
vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
image->layout = image_memory_barrier.newLayout;
image.layout = image_memory_barrier.newLayout;
}
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout) {
EXIT_IF(image == nullptr);
if (image->layout != new_layout) {
if (image->type == VulkanImageType::VideoOut &&
image->layout == vk::ImageLayout::eTransferDstOptimal) {
if (image.layout != new_layout) {
if (image.type == VulkanImageType::VideoOut &&
image.layout == vk::ImageLayout::eTransferDstOptimal) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 128) {
LOGF("GraphicsRenderColorImageBarrier: image=%p type=%d layout=%s -> %s\n",
VulkanHandleToPointer(image->image), static_cast<int>(image->type),
VulkanToString(image->layout).c_str(), VulkanToString(new_layout).c_str());
VulkanHandleToPointer(image.image), static_cast<int>(image.type),
VulkanToString(image.layout).c_str(), VulkanToString(new_layout).c_str());
}
}
vk::ImageMemoryBarrier image_memory_barrier {};
@@ -100,16 +96,16 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i
vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead;
image_memory_barrier.dstAccessMask =
vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead;
image_memory_barrier.oldLayout = image->layout;
image_memory_barrier.oldLayout = image.layout;
image_memory_barrier.newLayout = new_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image->image;
image_memory_barrier.image = image.image;
image_memory_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers;
image_memory_barrier.subresourceRange.layerCount = image.layers;
const auto stages = static_cast<vk::PipelineStageFlags>(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
@@ -117,75 +113,72 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i
vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1,
&image_memory_barrier);
image->layout = image_memory_barrier.newLayout;
image.layout = image_memory_barrier.newLayout;
}
}
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout) {
EXIT_IF(image == nullptr);
EXIT_IF(image->type != VulkanImageType::DepthStencil);
EXIT_IF(image.type != VulkanImageType::DepthStencil);
if (new_layout == vk::ImageLayout::eUndefined ||
new_layout == vk::ImageLayout::ePreinitialized) {
EXIT("invalid destination depth/stencil image layout: %s\n",
VulkanToString(new_layout).c_str());
}
if (image->layout == new_layout) {
if (image.layout == new_layout) {
return;
}
vk::ImageMemoryBarrier barrier {};
barrier.sType = vk::StructureType::eImageMemoryBarrier;
barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
barrier.oldLayout = image->layout;
barrier.oldLayout = image.layout;
barrier.newLayout = new_layout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image->image;
barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image->format), 0,
VK_REMAINING_MIP_LEVELS, 0, image->layers};
barrier.image = image.image;
barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image.format), 0,
VK_REMAINING_MIP_LEVELS, 0, image.layers};
const auto stages = static_cast<vk::PipelineStageFlags>(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
vk::PipelineStageFlagBits::eTransfer);
vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1,
&barrier);
image->layout = new_layout;
image.layout = new_layout;
}
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image) {
EXIT_IF(image == nullptr);
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) {
EXIT_IF(image.type != VulkanImageType::DepthStencil);
EXIT_IF(image->type != VulkanImageType::DepthStencil);
auto* depth = static_cast<DepthStencilVulkanImage*>(image);
if (depth->compressed) {
auto& depth = static_cast<DepthStencilVulkanImage&>(image);
if (depth.compressed) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) {
LOGF(
"DepthTexture: decompressing depth target for shader read format=%s extent=%ux%u\n",
VulkanToString(depth->format).c_str(), depth->extent.width, depth->extent.height);
VulkanToString(depth.format).c_str(), depth.extent.width, depth.extent.height);
}
depth->compressed = false;
depth.compressed = false;
}
if (image->layout != vk::ImageLayout::eDepthStencilReadOnlyOptimal) {
if (image.layout != vk::ImageLayout::eDepthStencilReadOnlyOptimal) {
vk::ImageMemoryBarrier image_memory_barrier {};
image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier;
image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask =
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
image_memory_barrier.oldLayout = image->layout;
image_memory_barrier.oldLayout = image.layout;
image_memory_barrier.newLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image->image;
image_memory_barrier.image = image.image;
image_memory_barrier.subresourceRange.aspectMask =
ImageViewOps::DepthAspectMask(image->format);
ImageViewOps::DepthAspectMask(image.format);
image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers;
image_memory_barrier.subresourceRange.layerCount = image.layers;
vk_buffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
@@ -194,37 +187,35 @@ void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage*
vk::PipelineStageFlagBits::eComputeShader,
vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
image->layout = image_memory_barrier.newLayout;
image.layout = image_memory_barrier.newLayout;
}
}
void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer.IsInvalid());
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
auto vk_buffer = buffer->Handle();
auto vk_buffer = buffer.Handle();
auto* native = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(buffer, vaddr, size);
auto* native = GetRenderContext().GetTextureCache().FindRenderTargetByRange(buffer, vaddr, size);
if (native == nullptr) {
EXIT("render-target barrier range has no cached image\n");
}
GraphicsRenderTextureBarrier(vk_buffer, native);
GraphicsRenderTextureBarrier(vk_buffer, *native);
}
void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) {
EXIT_IF(buffer.IsInvalid());
Common::LockGuard lock(g_render_ctx->GetMutex());
Common::LockGuard lock(GetRenderContext().GetMutex());
auto vk_buffer = buffer->Handle();
auto* native = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(buffer, vaddr, size);
auto vk_buffer = buffer.Handle();
auto* native = GetRenderContext().GetTextureCache().FindDepthTargetByRange(buffer, vaddr, size);
if (native == nullptr) {
EXIT("depth-target barrier range has no cached image\n");
}
GraphicsRenderDepthStencilBarrier(vk_buffer, native);
GraphicsRenderDepthStencilBarrier(vk_buffer, *native);
}
} // namespace Libs::Graphics
@@ -7,12 +7,12 @@ namespace Libs::Graphics {
struct VulkanImage;
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image);
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image);
void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout);
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image,
vk::ImageLayout new_layout);
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image);
void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image);
} // namespace Libs::Graphics
@@ -143,8 +143,7 @@ vk::Sampler SamplerCache::GetSampler(const ShaderSamplerResource& r) {
}
vk::Sampler vk_sampler = nullptr;
const auto result =
g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler);
const auto result = m_graphics.device.createSampler(&sampler_info, nullptr, &vk_sampler);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || vk_sampler == nullptr);
m_samplers.emplace(key, vk_sampler);
@@ -14,9 +14,13 @@
namespace Libs::Graphics {
struct GraphicContext;
class SamplerCache {
public:
SamplerCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
explicit SamplerCache(GraphicContext& graphics): m_graphics(graphics) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
}
~SamplerCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(SamplerCache);
@@ -37,6 +41,7 @@ private:
}
};
GraphicContext& m_graphics;
Common::Mutex m_mutex;
std::unordered_map<SamplerKey, vk::Sampler, SamplerKeyHash> m_samplers;
};
@@ -4,8 +4,13 @@
namespace Libs::Graphics {
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context,
uint32_t guest_wave_size) {
ShaderSubgroupCapabilities::ShaderSubgroupCapabilities(const GraphicContext& graphics)
: subgroup_size(graphics.subgroup_size), min_subgroup_size(graphics.min_subgroup_size),
max_subgroup_size(graphics.max_subgroup_size),
required_subgroup_size_stages(graphics.required_subgroup_size_stages),
subgroup_size_control_enabled(graphics.subgroup_size_control_enabled) {}
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(uint32_t guest_wave_size) {
// A 64-wide guest wave can't assume the host GPU's lane layout matches
// GCN's. AMD RDNA also reports a 64-wide subgroup but uses a different
// lane/pixel layout, which corrupted rendering under "native wave" mode.
@@ -16,7 +21,7 @@ ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context,
return ShaderLaneMaskMode::NativeWave;
}
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& context,
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabilities& capabilities,
vk::ShaderStageFlagBits stage,
const ShaderRecompiler::IR::Program& program) {
const auto guest_wave_size = program.wave_size;
@@ -24,8 +29,8 @@ ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext&
return {};
}
if (stage != vk::ShaderStageFlagBits::eCompute) {
const auto expected = SelectGraphicsLaneMaskMode(context, guest_wave_size);
if (program.lane_mask_mode != expected || (context.subgroup_size != guest_wave_size &&
const auto expected = SelectGraphicsLaneMaskMode(guest_wave_size);
if (program.lane_mask_mode != expected || (capabilities.subgroup_size != guest_wave_size &&
expected != ShaderLaneMaskMode::PerInvocation)) {
return {};
}
@@ -37,12 +42,13 @@ ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext&
if (program.lane_mask_mode != ShaderLaneMaskMode::NativeWave) {
return {};
}
if (context.subgroup_size == guest_wave_size) {
if (capabilities.subgroup_size == guest_wave_size) {
return {ShaderSubgroupMode::Natural, 0};
}
if (context.subgroup_size_control_enabled && (context.required_subgroup_size_stages & stage) &&
guest_wave_size >= context.min_subgroup_size &&
guest_wave_size <= context.max_subgroup_size) {
if (capabilities.subgroup_size_control_enabled &&
(capabilities.required_subgroup_size_stages & stage) &&
guest_wave_size >= capabilities.min_subgroup_size &&
guest_wave_size <= capabilities.max_subgroup_size) {
return {ShaderSubgroupMode::Controlled, guest_wave_size};
}
if (!ShaderRecompiler::Spirv::ProgramRequiresExactSubgroupSize(program)) {
@@ -19,10 +19,19 @@ struct ShaderSubgroupConfiguration {
uint32_t required_size = 0;
};
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(const GraphicContext& context,
uint32_t guest_wave_size);
struct ShaderSubgroupCapabilities {
explicit ShaderSubgroupCapabilities(const GraphicContext& graphics);
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const GraphicContext& context,
uint32_t subgroup_size = 0;
uint32_t min_subgroup_size = 0;
uint32_t max_subgroup_size = 0;
vk::ShaderStageFlags required_subgroup_size_stages;
bool subgroup_size_control_enabled = false;
};
ShaderLaneMaskMode SelectGraphicsLaneMaskMode(uint32_t guest_wave_size);
ShaderSubgroupConfiguration ConfigureShaderSubgroup(const ShaderSubgroupCapabilities& capabilities,
vk::ShaderStageFlagBits stage,
const ShaderRecompiler::IR::Program& program);
+227 -246
View File
@@ -25,62 +25,59 @@ namespace Libs::Graphics {
// IDK: maybe we can remove it?
constexpr uint32_t kTemporaryPs5BufferFormat121 = 121u;
static bool NarrowInputFormat(vk::Format* format, uint32_t* size, uint32_t used_components) {
EXIT_IF(format == nullptr);
EXIT_IF(size == nullptr);
if (used_components == 0 || used_components >= *size) {
static bool NarrowInputFormat(vk::Format& format, uint32_t& size, uint32_t used_components) {
if (used_components == 0 || used_components >= size) {
return false;
}
switch (*format) {
switch (format) {
case vk::Format::eR32G32B32A32Sfloat:
switch (used_components) {
case 1: *format = vk::Format::eR32Sfloat; break;
case 2: *format = vk::Format::eR32G32Sfloat; break;
case 3: *format = vk::Format::eR32G32B32Sfloat; break;
case 1: format = vk::Format::eR32Sfloat; break;
case 2: format = vk::Format::eR32G32Sfloat; break;
case 3: format = vk::Format::eR32G32B32Sfloat; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
case vk::Format::eR32G32B32Sfloat:
switch (used_components) {
case 1: *format = vk::Format::eR32Sfloat; break;
case 2: *format = vk::Format::eR32G32Sfloat; break;
case 1: format = vk::Format::eR32Sfloat; break;
case 2: format = vk::Format::eR32G32Sfloat; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
case vk::Format::eR16G16B16A16Sfloat:
switch (used_components) {
case 1: *format = vk::Format::eR16Sfloat; break;
case 2: *format = vk::Format::eR16G16Sfloat; break;
case 1: format = vk::Format::eR16Sfloat; break;
case 2: format = vk::Format::eR16G16Sfloat; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
case vk::Format::eR8G8B8A8Unorm:
switch (used_components) {
case 1: *format = vk::Format::eR8Unorm; break;
case 2: *format = vk::Format::eR8G8Unorm; break;
case 1: format = vk::Format::eR8Unorm; break;
case 2: format = vk::Format::eR8G8Unorm; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
case vk::Format::eR8G8B8A8Snorm:
if (used_components != 2) {
return false;
}
*format = vk::Format::eR8G8Snorm;
*size = 2;
format = vk::Format::eR8G8Snorm;
size = 2;
return true;
case vk::Format::eR8G8B8A8Uint:
switch (used_components) {
case 1: *format = vk::Format::eR8Uint; break;
case 2: *format = vk::Format::eR8G8Uint; break;
case 1: format = vk::Format::eR8Uint; break;
case 2: format = vk::Format::eR8G8Uint; break;
default: return false;
}
*size = used_components;
size = used_components;
return true;
default: break;
}
@@ -88,11 +85,8 @@ static bool NarrowInputFormat(vk::Format* format, uint32_t* size, uint32_t used_
return false;
}
static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format, uint32_t* size,
static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format, uint32_t& size,
uint32_t used_components) {
EXIT_IF(format == nullptr);
EXIT_IF(size == nullptr);
auto fmt = res.Format();
if (fmt == Prospero::GpuEnumValue(Prospero::VertexAttribFormat::k16_16SInt)) {
static bool logged_113 = false;
@@ -101,11 +95,11 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format,
"vk::Format::eR32G32B32A32Sfloat\n");
logged_113 = true;
}
*format = vk::Format::eR32G32B32A32Sfloat;
*size = 4;
format = vk::Format::eR32G32B32A32Sfloat;
size = 4;
if (NarrowInputFormat(format, size, used_components)) {
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt,
VulkanToString(*format).c_str(), used_components);
VulkanToString(format).c_str(), used_components);
}
return;
}
@@ -115,228 +109,228 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format* format,
LOGF("InputFormat: accepting PS5 buffer format 121 as vk::Format::eR16G16Sfloat\n");
logged_121 = true;
}
*format = vk::Format::eR16G16Sfloat;
*size = 2;
format = vk::Format::eR16G16Sfloat;
size = 2;
if (NarrowInputFormat(format, size, used_components)) {
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", fmt,
VulkanToString(*format).c_str(), used_components);
VulkanToString(format).c_str(), used_components);
}
return;
}
switch (static_cast<Prospero::BufferFormat>(fmt)) {
case Prospero::BufferFormat::k32_32_32_32Float:
*format = vk::Format::eR32G32B32A32Sfloat;
*size = 4;
format = vk::Format::eR32G32B32A32Sfloat;
size = 4;
break;
case Prospero::BufferFormat::k32_32_32_32SInt:
*format = vk::Format::eR32G32B32A32Sint;
*size = 4;
format = vk::Format::eR32G32B32A32Sint;
size = 4;
break;
case Prospero::BufferFormat::k32_32_32_32UInt:
*format = vk::Format::eR32G32B32A32Uint;
*size = 4;
format = vk::Format::eR32G32B32A32Uint;
size = 4;
break;
case Prospero::BufferFormat::k32_32_32Float:
*format = vk::Format::eR32G32B32Sfloat;
*size = 3;
format = vk::Format::eR32G32B32Sfloat;
size = 3;
break;
case Prospero::BufferFormat::k32_32_32SInt:
*format = vk::Format::eR32G32B32Sint;
*size = 3;
format = vk::Format::eR32G32B32Sint;
size = 3;
break;
case Prospero::BufferFormat::k32_32_32UInt:
*format = vk::Format::eR32G32B32Uint;
*size = 3;
format = vk::Format::eR32G32B32Uint;
size = 3;
break;
case Prospero::BufferFormat::k16_16_16_16Float:
*format = vk::Format::eR16G16B16A16Sfloat;
*size = 4;
format = vk::Format::eR16G16B16A16Sfloat;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16SInt:
*format = vk::Format::eR16G16B16A16Sint;
*size = 4;
format = vk::Format::eR16G16B16A16Sint;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16UInt:
*format = vk::Format::eR16G16B16A16Uint;
*size = 4;
format = vk::Format::eR16G16B16A16Uint;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16SScaled:
*format = vk::Format::eR16G16B16A16Sscaled;
*size = 4;
format = vk::Format::eR16G16B16A16Sscaled;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16UScaled:
*format = vk::Format::eR16G16B16A16Uscaled;
*size = 4;
format = vk::Format::eR16G16B16A16Uscaled;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16SNorm:
*format = vk::Format::eR16G16B16A16Snorm;
*size = 4;
format = vk::Format::eR16G16B16A16Snorm;
size = 4;
break;
case Prospero::BufferFormat::k16_16_16_16UNorm:
*format = vk::Format::eR16G16B16A16Unorm;
*size = 4;
format = vk::Format::eR16G16B16A16Unorm;
size = 4;
break;
case Prospero::BufferFormat::k32_32Float:
*format = vk::Format::eR32G32Sfloat;
*size = 2;
format = vk::Format::eR32G32Sfloat;
size = 2;
break;
case Prospero::BufferFormat::k32_32SInt:
*format = vk::Format::eR32G32Sint;
*size = 2;
format = vk::Format::eR32G32Sint;
size = 2;
break;
case Prospero::BufferFormat::k32_32UInt:
*format = vk::Format::eR32G32Uint;
*size = 2;
format = vk::Format::eR32G32Uint;
size = 2;
break;
case Prospero::BufferFormat::k8_8_8_8UInt:
*format = vk::Format::eR8G8B8A8Uint;
*size = 4;
format = vk::Format::eR8G8B8A8Uint;
size = 4;
break;
case Prospero::BufferFormat::k8_8_8_8SScaled:
*format = vk::Format::eR8G8B8A8Sscaled;
*size = 4;
format = vk::Format::eR8G8B8A8Sscaled;
size = 4;
break;
case Prospero::BufferFormat::k8_8_8_8UScaled:
*format = vk::Format::eR8G8B8A8Uscaled;
*size = 4;
format = vk::Format::eR8G8B8A8Uscaled;
size = 4;
break;
case Prospero::BufferFormat::k8_8_8_8SNorm:
*format = vk::Format::eR8G8B8A8Snorm;
*size = 4;
format = vk::Format::eR8G8B8A8Snorm;
size = 4;
break;
case Prospero::BufferFormat::k8_8_8_8UNorm:
*format = vk::Format::eR8G8B8A8Unorm;
*size = 4;
format = vk::Format::eR8G8B8A8Unorm;
size = 4;
break;
case Prospero::BufferFormat::k10_10_10_2UNorm:
*format = vk::Format::eA2B10G10R10UnormPack32;
*size = 4;
format = vk::Format::eA2B10G10R10UnormPack32;
size = 4;
break;
case Prospero::BufferFormat::k10_10_10_2SNorm:
*format = vk::Format::eA2B10G10R10SnormPack32;
*size = 4;
format = vk::Format::eA2B10G10R10SnormPack32;
size = 4;
break;
case Prospero::BufferFormat::k16_16Float:
*format = vk::Format::eR16G16Sfloat;
*size = 2;
format = vk::Format::eR16G16Sfloat;
size = 2;
break;
case Prospero::BufferFormat::k16_16SInt:
*format = vk::Format::eR16G16Sint;
*size = 2;
format = vk::Format::eR16G16Sint;
size = 2;
break;
case Prospero::BufferFormat::k16_16UInt:
*format = vk::Format::eR16G16Uint;
*size = 2;
format = vk::Format::eR16G16Uint;
size = 2;
break;
case Prospero::BufferFormat::k16_16SScaled:
*format = vk::Format::eR16G16Sscaled;
*size = 2;
format = vk::Format::eR16G16Sscaled;
size = 2;
break;
case Prospero::BufferFormat::k16_16UScaled:
*format = vk::Format::eR16G16Uscaled;
*size = 2;
format = vk::Format::eR16G16Uscaled;
size = 2;
break;
case Prospero::BufferFormat::k16_16SNorm:
*format = vk::Format::eR16G16Snorm;
*size = 2;
format = vk::Format::eR16G16Snorm;
size = 2;
break;
case Prospero::BufferFormat::k16_16UNorm:
*format = vk::Format::eR16G16Unorm;
*size = 2;
format = vk::Format::eR16G16Unorm;
size = 2;
break;
case Prospero::BufferFormat::k32Float:
*format = vk::Format::eR32Sfloat;
*size = 1;
format = vk::Format::eR32Sfloat;
size = 1;
break;
case Prospero::BufferFormat::k32SInt:
*format = vk::Format::eR32Sint;
*size = 1;
format = vk::Format::eR32Sint;
size = 1;
break;
case Prospero::BufferFormat::k32UInt:
*format = vk::Format::eR32Uint;
*size = 1;
format = vk::Format::eR32Uint;
size = 1;
break;
case Prospero::BufferFormat::k8_8SInt:
*format = vk::Format::eR8G8Sint;
*size = 2;
format = vk::Format::eR8G8Sint;
size = 2;
break;
case Prospero::BufferFormat::k8_8UInt:
*format = vk::Format::eR8G8Uint;
*size = 2;
format = vk::Format::eR8G8Uint;
size = 2;
break;
case Prospero::BufferFormat::k8_8SScaled:
*format = vk::Format::eR8G8Sscaled;
*size = 2;
format = vk::Format::eR8G8Sscaled;
size = 2;
break;
case Prospero::BufferFormat::k8_8UScaled:
*format = vk::Format::eR8G8Uscaled;
*size = 2;
format = vk::Format::eR8G8Uscaled;
size = 2;
break;
case Prospero::BufferFormat::k8_8SNorm:
*format = vk::Format::eR8G8Snorm;
*size = 2;
format = vk::Format::eR8G8Snorm;
size = 2;
break;
case Prospero::BufferFormat::k8_8UNorm:
*format = vk::Format::eR8G8Unorm;
*size = 2;
format = vk::Format::eR8G8Unorm;
size = 2;
break;
case Prospero::BufferFormat::k16Float:
*format = vk::Format::eR16Sfloat;
*size = 1;
format = vk::Format::eR16Sfloat;
size = 1;
break;
case Prospero::BufferFormat::k16SInt:
*format = vk::Format::eR16Sint;
*size = 1;
format = vk::Format::eR16Sint;
size = 1;
break;
case Prospero::BufferFormat::k16UInt:
*format = vk::Format::eR16Uint;
*size = 1;
format = vk::Format::eR16Uint;
size = 1;
break;
case Prospero::BufferFormat::k16SScaled:
*format = vk::Format::eR16Sscaled;
*size = 1;
format = vk::Format::eR16Sscaled;
size = 1;
break;
case Prospero::BufferFormat::k16UScaled:
*format = vk::Format::eR16Uscaled;
*size = 1;
format = vk::Format::eR16Uscaled;
size = 1;
break;
case Prospero::BufferFormat::k16SNorm:
*format = vk::Format::eR16Snorm;
*size = 1;
format = vk::Format::eR16Snorm;
size = 1;
break;
case Prospero::BufferFormat::k16UNorm:
*format = vk::Format::eR16Unorm;
*size = 1;
format = vk::Format::eR16Unorm;
size = 1;
break;
case Prospero::BufferFormat::k8SInt:
*format = vk::Format::eR8Sint;
*size = 1;
format = vk::Format::eR8Sint;
size = 1;
break;
case Prospero::BufferFormat::k8UInt:
*format = vk::Format::eR8Uint;
*size = 1;
format = vk::Format::eR8Uint;
size = 1;
break;
case Prospero::BufferFormat::k8SScaled:
*format = vk::Format::eR8Sscaled;
*size = 1;
format = vk::Format::eR8Sscaled;
size = 1;
break;
case Prospero::BufferFormat::k8UScaled:
*format = vk::Format::eR8Uscaled;
*size = 1;
format = vk::Format::eR8Uscaled;
size = 1;
break;
case Prospero::BufferFormat::k8SNorm:
*format = vk::Format::eR8Snorm;
*size = 1;
format = vk::Format::eR8Snorm;
size = 1;
break;
case Prospero::BufferFormat::k8UNorm:
*format = vk::Format::eR8Unorm;
*size = 1;
format = vk::Format::eR8Unorm;
size = 1;
break;
default:
EXIT("unknown format: fmt = %u\n", fmt);
*format = vk::Format::eUndefined;
*size = 4;
format = vk::Format::eUndefined;
size = 4;
break;
}
@@ -391,43 +385,39 @@ static vk::BlendOp GetBlendOp(uint32_t op) {
return vk::BlendOp::eAdd;
}
static void CreateLayout(vk::DescriptorSetLayout* set_layouts, uint32_t* set_layouts_num,
vk::PushConstantRange* push_constant_info,
uint32_t* push_constant_info_num,
static void CreateLayout(std::span<vk::DescriptorSetLayout> set_layouts, uint32_t& set_layouts_num,
std::span<vk::PushConstantRange> push_constant_info,
uint32_t& push_constant_info_num,
const ShaderRecompiler::IR::Program& program,
vk::ShaderStageFlags vk_stage, DescriptorCache::Stage stage) {
EXIT_IF(set_layouts == nullptr);
EXIT_IF(set_layouts_num == nullptr);
EXIT_IF(push_constant_info == nullptr);
EXIT_IF(push_constant_info_num == nullptr);
const auto& bindings = program.bindings;
const bool need_descriptor = !bindings.descriptors.empty();
if (bindings.push_constant_size != 0) {
auto index = *push_constant_info_num;
auto index = push_constant_info_num;
push_constant_info[index].stageFlags = vk_stage;
push_constant_info[index].offset = bindings.push_constant_offset;
push_constant_info[index].size = bindings.push_constant_size;
(*push_constant_info_num)++;
push_constant_info_num++;
}
if (need_descriptor) {
EXIT_IF(bindings.descriptor_set != *set_layouts_num);
EXIT_IF(bindings.descriptor_set != set_layouts_num);
set_layouts[*set_layouts_num] =
g_render_ctx->GetDescriptorCache()->GetDescriptorSetLayout(stage, program);
(*set_layouts_num)++;
set_layouts[set_layouts_num] =
GetRenderContext().GetDescriptorCache().GetDescriptorSetLayout(stage, program);
set_layouts_num++;
}
}
static void ConfigureSubgroupSize(const GraphicContext* gctx, vk::ShaderStageFlagBits vk_stage,
static void ConfigureSubgroupSize(vk::ShaderStageFlagBits vk_stage,
const ShaderRecompiler::IR::Program& program,
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo* required,
vk::PipelineShaderStageCreateInfo* stage) {
EXIT_IF(gctx == nullptr || required == nullptr || stage == nullptr);
const auto config = ConfigureShaderSubgroup(*gctx, vk_stage, program);
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo& required,
vk::PipelineShaderStageCreateInfo& stage) {
const auto& graphics = GetRenderContext().GetGraphics();
const auto config =
ConfigureShaderSubgroup(ShaderSubgroupCapabilities {graphics}, vk_stage, program);
switch (config.mode) {
case ShaderSubgroupMode::Natural: return;
case ShaderSubgroupMode::PerInvocationGraphics: {
@@ -453,33 +443,30 @@ static void ConfigureSubgroupSize(const GraphicContext* gctx, vk::ShaderStageFla
default:
EXIT("Vulkan cannot run %u-lane shader stage 0x%08x: default=%u min=%u max=%u "
"controlled_stages=0x%08x\n",
program.wave_size, static_cast<uint32_t>(vk_stage), gctx->subgroup_size,
gctx->min_subgroup_size, gctx->max_subgroup_size,
static_cast<vk::ShaderStageFlags::MaskType>(gctx->required_subgroup_size_stages));
program.wave_size, static_cast<uint32_t>(vk_stage), graphics.subgroup_size,
graphics.min_subgroup_size, graphics.max_subgroup_size,
static_cast<vk::ShaderStageFlags::MaskType>(
graphics.required_subgroup_size_stages));
}
required->sType = vk::StructureType::ePipelineShaderStageRequiredSubgroupSizeCreateInfo;
required->requiredSubgroupSize = config.required_size;
stage->pNext = required;
required.sType = vk::StructureType::ePipelineShaderStageRequiredSubgroupSizeCreateInfo;
required.requiredSubgroupSize = config.required_size;
stage.pNext = &required;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo* vs_input_info,
void CreatePipelineInternal(PipelineCache::GraphicsPipeline& pipeline, vk::RenderPass render_pass,
const ShaderVertexInputInfo& vs_input_info,
std::span<const uint32_t> vs_shader,
const ShaderPixelInputInfo* ps_input_info,
std::span<const uint32_t> ps_shader,
const PipelineStaticParameters& static_params, uint32_t vs_hash0,
uint32_t vs_crc32, uint32_t ps_hash0, uint32_t ps_crc32,
bool ps_active) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(pipeline == nullptr);
EXIT_IF(render_pass == nullptr);
EXIT_IF(ps_active && ps_input_info == nullptr);
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
auto& graphics = GetRenderContext().GetGraphics();
vk::ShaderModule vert_shader_module = nullptr;
vk::ShaderModule frag_shader_module = nullptr;
@@ -492,7 +479,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
create_info.codeSize = vs_shader.size() * 4;
create_info.pCode = vs_shader.data();
auto result = gctx->device.createShaderModule(&create_info, nullptr, &vert_shader_module);
auto result = graphics.device.createShaderModule(&create_info, nullptr, &vert_shader_module);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateShaderModule VS done result=%s module=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(vert_shader_module));
@@ -502,7 +489,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
if (ps_active) {
create_info.codeSize = ps_shader.size() * 4;
create_info.pCode = ps_shader.data();
result = gctx->device.createShaderModule(&create_info, nullptr, &frag_shader_module);
result = graphics.device.createShaderModule(&create_info, nullptr, &frag_shader_module);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateShaderModule PS done result=%s module=%p\n",
VulkanToString(result).c_str(), static_cast<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.pName = "main";
vert_shader_stage_info.pSpecializationInfo = nullptr;
EXIT_IF(!vs_input_info->stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eVertex, *vs_input_info->stage.program,
&vert_subgroup_size, &vert_shader_stage_info);
EXIT_IF(!vs_input_info.stage);
ConfigureSubgroupSize(vk::ShaderStageFlagBits::eVertex, *vs_input_info.stage.program,
vert_subgroup_size, vert_shader_stage_info);
vk::PipelineShaderStageCreateInfo frag_shader_stage_info {};
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo frag_subgroup_size {};
@@ -538,9 +525,8 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
frag_shader_stage_info.pSpecializationInfo = nullptr;
if (ps_active) {
EXIT_IF(!ps_input_info->stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eFragment,
*ps_input_info->stage.program, &frag_subgroup_size,
&frag_shader_stage_info);
ConfigureSubgroupSize(vk::ShaderStageFlagBits::eFragment, *ps_input_info->stage.program,
frag_subgroup_size, frag_shader_stage_info);
}
vk::PipelineShaderStageCreateInfo shader_stages[] = {vert_shader_stage_info,
@@ -550,8 +536,8 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vk::VertexInputAttributeDescription input_attr[ShaderVertexInputInfo::RES_MAX];
vk::VertexInputBindingDescription input_desc[ShaderVertexInputInfo::RES_MAX];
for (int bi = 0; bi < vs_input_info->buffers_num; bi++) {
const auto& b = vs_input_info->buffers[bi];
for (int bi = 0; bi < vs_input_info.buffers_num; bi++) {
const auto& b = vs_input_info.buffers[bi];
input_desc[bi].binding = bi;
input_desc[bi].stride = b.stride;
input_desc[bi].inputRate =
@@ -564,11 +550,11 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
input_attr[index].offset = b.attr_offsets[ai];
uint32_t attr_size = 4;
auto registers_num = vs_input_info->resources_dst[index].registers_num;
auto used_components = (vs_input_info->resource_fetch_components[index] > 0
? vs_input_info->resource_fetch_components[index]
auto registers_num = vs_input_info.resources_dst[index].registers_num;
auto used_components = (vs_input_info.resource_fetch_components[index] > 0
? vs_input_info.resource_fetch_components[index]
: registers_num);
GetInputFormat(vs_input_info->resources[index], &input_attr[index].format, &attr_size,
GetInputFormat(vs_input_info.resources[index], input_attr[index].format, attr_size,
static_cast<uint32_t>(used_components));
if (graphics_debug_dump_enabled()) {
@@ -580,29 +566,29 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
" fetched_components=%u attr_size=%u swizzle=%u,%u,%u,%u\n",
log_id, index, input_attr[index].binding, input_attr[index].offset,
input_desc[bi].stride, static_cast<int>(input_attr[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[index].Format()),
static_cast<uint32_t>(vs_input_info.resources_dst[index].register_start),
static_cast<uint32_t>(registers_num),
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].DstSelY()),
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].DstSelX()),
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].DstSelW()));
}
}
if (vs_input_info->resources[index].OutOfBounds() != 0) {
if (vs_input_info.resources[index].OutOfBounds() != 0) {
static bool logged = false;
if (!logged) {
LOGF("VertexInput: temporary: accepting PS5 out-of-bounds behavior %" PRIu8
"\n",
vs_input_info->resources[index].OutOfBounds());
vs_input_info.resources[index].OutOfBounds());
logged = true;
}
}
EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].AddTid());
EXIT_NOT_IMPLEMENTED(vs_input_info->resources[index].SwizzleEnabled());
EXIT_NOT_IMPLEMENTED(vs_input_info.resources[index].AddTid());
EXIT_NOT_IMPLEMENTED(vs_input_info.resources[index].SwizzleEnabled());
auto log_unsupported_vertex_swizzle = [index, attr_size, registers_num](
uint32_t swizzle, uint32_t expected) {
@@ -619,14 +605,14 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
switch (registers_num) {
case 1: {
auto swizzle = vs_input_info->resources[index].DstSelX();
auto swizzle = vs_input_info.resources[index].DstSelX();
if (swizzle != DstSel(4)) {
log_unsupported_vertex_swizzle(swizzle, DstSel(4));
}
break;
}
case 2: {
auto swizzle = vs_input_info->resources[index].DstSelXY();
auto swizzle = vs_input_info.resources[index].DstSelXY();
auto expected = (attr_size == 1 ? DstSel(4, 0) : DstSel(4, 5));
if (swizzle != expected) {
log_unsupported_vertex_swizzle(swizzle, expected);
@@ -634,7 +620,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
break;
}
case 3: {
auto swizzle = vs_input_info->resources[index].DstSelXYZ();
auto swizzle = vs_input_info.resources[index].DstSelXYZ();
auto expected =
(attr_size == 1 ? DstSel(4, 0, 0)
: (attr_size == 2 ? DstSel(4, 5, 0) : DstSel(4, 5, 6)));
@@ -644,7 +630,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
break;
}
case 4: {
auto swizzle = vs_input_info->resources[index].DstSelXYZW();
auto swizzle = vs_input_info.resources[index].DstSelXYZW();
auto expected = DstSel(4, 5, 6, 7);
bool supported = false;
switch (attr_size) {
@@ -679,9 +665,9 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vertex_input_info.sType = vk::StructureType::ePipelineVertexInputStateCreateInfo;
vertex_input_info.pNext = nullptr;
vertex_input_info.flags = {};
vertex_input_info.vertexBindingDescriptionCount = vs_input_info->buffers_num;
vertex_input_info.vertexBindingDescriptionCount = vs_input_info.buffers_num;
vertex_input_info.pVertexBindingDescriptions = input_desc;
vertex_input_info.vertexAttributeDescriptionCount = vs_input_info->resources_num;
vertex_input_info.vertexAttributeDescriptionCount = vs_input_info.resources_num;
vertex_input_info.pVertexAttributeDescriptions = input_attr;
vk::PipelineInputAssemblyStateCreateInfo input_assembly {};
@@ -833,13 +819,13 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
vk::PushConstantRange push_constant_info[2];
uint32_t push_constant_info_num = 0;
EXIT_IF(!vs_input_info->stage);
CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num,
*vs_input_info->stage.program, vk::ShaderStageFlagBits::eVertex,
EXIT_IF(!vs_input_info.stage);
CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num,
*vs_input_info.stage.program, vk::ShaderStageFlagBits::eVertex,
DescriptorCache::Stage::Vertex);
if (ps_active) {
EXIT_IF(!ps_input_info->stage);
CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num,
CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num,
*ps_input_info->stage.program, vk::ShaderStageFlagBits::eFragment,
DescriptorCache::Stage::Pixel);
}
@@ -854,7 +840,7 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
pipeline_layout_info.pPushConstantRanges =
push_constant_info_num > 0 ? push_constant_info : nullptr;
EXIT_IF(pipeline->pipeline_layout != nullptr);
EXIT_IF(pipeline.pipeline_layout != nullptr);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=0x%08" PRIx32 "/0x%08" PRIx32
@@ -862,15 +848,15 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
"\n",
vs_hash0, vs_crc32, ps_hash0, ps_crc32, set_layouts_num, push_constant_info_num);
}
result = gctx->device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline->pipeline_layout);
result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline.pipeline_layout);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreatePipelineLayout done result=%s layout=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline_layout));
VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline_layout));
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline_layout == nullptr);
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
vk::PipelineDepthStencilStateCreateInfo depth_stencil_info {};
depth_stencil_info.sType = vk::StructureType::ePipelineDepthStencilStateCreateInfo;
@@ -927,13 +913,13 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
pipeline_info.pDepthStencilState = (static_params.with_depth ? &depth_stencil_info : nullptr);
pipeline_info.pColorBlendState = &color_blending;
pipeline_info.pDynamicState = &dynamic_state;
pipeline_info.layout = pipeline->pipeline_layout;
pipeline_info.layout = pipeline.pipeline_layout;
pipeline_info.renderPass = render_pass;
pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = nullptr;
pipeline_info.basePipelineIndex = -1;
EXIT_IF(pipeline->pipeline != nullptr);
EXIT_IF(pipeline.pipeline != nullptr);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=0x%08" PRIx32 "/0x%08" PRIx32
@@ -946,32 +932,27 @@ void CreatePipelineInternal(PipelineCache::GraphicsPipeline* pipeline, vk::Rende
viewport.y, viewport.width, viewport.height, scissor.offset.x, scissor.offset.y,
scissor.extent.width, scissor.extent.height);
}
result = gctx->device.createGraphicsPipelines(nullptr, 1, &pipeline_info, nullptr,
&pipeline->pipeline);
result = graphics.device.createGraphicsPipelines(nullptr, 1, &pipeline_info, nullptr,
&pipeline.pipeline);
if (graphics_debug_dump_enabled()) {
LOGF("PipelineTrace: vkCreateGraphicsPipelines done result=%s pipeline=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline));
VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline));
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline == nullptr);
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
if (frag_shader_module != nullptr) {
gctx->device.destroyShaderModule(frag_shader_module, nullptr);
graphics.device.destroyShaderModule(frag_shader_module, nullptr);
}
gctx->device.destroyShaderModule(vert_shader_module, nullptr);
graphics.device.destroyShaderModule(vert_shader_module, nullptr);
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
const ShaderComputeInputInfo* input_info,
void CreatePipelineInternal(PipelineCache::ComputePipeline& pipeline,
const ShaderComputeInputInfo& input_info,
std::span<const uint32_t> cs_shader) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(pipeline == nullptr);
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
auto& graphics = GetRenderContext().GetGraphics();
vk::ShaderModule comp_shader_module = nullptr;
@@ -984,7 +965,7 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
create_info.pCode = cs_shader.data();
LOGF("PipelineTrace: vkCreateShaderModule CS begin words=%" PRIu64 "\n",
static_cast<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",
VulkanToString(result).c_str(), static_cast<void*>(comp_shader_module));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
@@ -1000,9 +981,9 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
comp_shader_stage_info.module = comp_shader_module;
comp_shader_stage_info.pName = "main";
comp_shader_stage_info.pSpecializationInfo = nullptr;
EXIT_IF(!input_info->stage);
ConfigureSubgroupSize(gctx, vk::ShaderStageFlagBits::eCompute, *input_info->stage.program,
&comp_subgroup_size, &comp_shader_stage_info);
EXIT_IF(!input_info.stage);
ConfigureSubgroupSize(vk::ShaderStageFlagBits::eCompute, *input_info.stage.program,
comp_subgroup_size, comp_shader_stage_info);
vk::DescriptorSetLayout set_layouts[1] = {};
uint32_t set_layouts_num = 0;
@@ -1010,9 +991,9 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
vk::PushConstantRange push_constant_info[1];
uint32_t push_constant_info_num = 0;
EXIT_IF(!input_info->stage);
CreateLayout(set_layouts, &set_layouts_num, push_constant_info, &push_constant_info_num,
*input_info->stage.program, vk::ShaderStageFlagBits::eCompute,
EXIT_IF(!input_info.stage);
CreateLayout(set_layouts, set_layouts_num, push_constant_info, push_constant_info_num,
*input_info.stage.program, vk::ShaderStageFlagBits::eCompute,
DescriptorCache::Stage::Compute);
vk::PipelineLayoutCreateInfo pipeline_layout_info {};
@@ -1025,39 +1006,39 @@ void CreatePipelineInternal(PipelineCache::ComputePipeline* pipeline,
pipeline_layout_info.pPushConstantRanges =
push_constant_info_num > 0 ? push_constant_info : nullptr;
EXIT_IF(pipeline->pipeline_layout != nullptr);
EXIT_IF(pipeline.pipeline_layout != nullptr);
LOGF("PipelineTrace: vkCreatePipelineLayout CS begin set_layouts=%u push_constants=%u\n",
set_layouts_num, push_constant_info_num);
result = gctx->device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline->pipeline_layout);
result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
&pipeline.pipeline_layout);
LOGF("PipelineTrace: vkCreatePipelineLayout CS done result=%s layout=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline_layout));
VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline_layout));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline_layout == nullptr);
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
vk::ComputePipelineCreateInfo info {};
info.sType = vk::StructureType::eComputePipelineCreateInfo;
info.pNext = nullptr;
info.flags = {};
info.stage = comp_shader_stage_info;
info.layout = pipeline->pipeline_layout;
info.layout = pipeline.pipeline_layout;
info.basePipelineHandle = nullptr;
info.basePipelineIndex = -1;
EXIT_IF(pipeline->pipeline != nullptr);
EXIT_IF(pipeline.pipeline != nullptr);
LOGF("PipelineTrace: vkCreateComputePipelines begin layout=%p\n",
static_cast<void*>(pipeline->pipeline_layout));
result = gctx->device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline->pipeline);
static_cast<void*>(pipeline.pipeline_layout));
result = graphics.device.createComputePipelines(nullptr, 1, &info, nullptr, &pipeline.pipeline);
LOGF("PipelineTrace: vkCreateComputePipelines done result=%s pipeline=%p\n",
VulkanToString(result).c_str(), static_cast<void*>(pipeline->pipeline));
VulkanToString(result).c_str(), static_cast<void*>(pipeline.pipeline));
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
EXIT_NOT_IMPLEMENTED(pipeline->pipeline == nullptr);
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
gctx->device.destroyShaderModule(comp_shader_module, nullptr);
graphics.device.destroyShaderModule(comp_shader_module, nullptr);
}
} // namespace Libs::Graphics
+16 -19
View File
@@ -16,21 +16,20 @@ namespace {
std::atomic<uint64_t> g_stream_buffer_count {0};
} // namespace
HostStreamBuffer::HostStreamBuffer() = default;
HostStreamBuffer::HostStreamBuffer(GraphicContext& graphics): m_graphics(graphics) {}
HostStreamBuffer::~HostStreamBuffer() {
Release();
}
void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) {
void HostStreamBuffer::EnsureBuffer() {
if (m_buffer != nullptr) {
if (m_ctx != ctx || m_mapped == nullptr) {
EXIT("host stream buffer changed graphics context\n");
if (m_mapped == nullptr) {
EXIT("host stream buffer lost its mapped storage\n");
}
return;
}
KYTY_PROFILER_BLOCK("HostStreamBuffer::create");
m_ctx = ctx;
m_buffer = std::make_unique<VulkanBuffer>();
m_buffer->usage = vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eVertexBuffer |
@@ -39,17 +38,16 @@ void HostStreamBuffer::EnsureBuffer(GraphicContext* ctx) {
m_buffer->memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, CAPACITY, m_buffer.get());
VulkanMapMemory(ctx, &m_buffer->memory, &m_mapped);
m_graphics.CreateBuffer(CAPACITY, *m_buffer);
m_graphics.MapMemory(m_buffer->memory, m_mapped);
const auto count = g_stream_buffer_count.fetch_add(1, std::memory_order_relaxed) + 1;
LOGF("HostStreamBuffer: created serial=%" PRIu64 " capacity=%" PRIu64 "\n", count, CAPACITY);
}
bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range) {
bool HostStreamBuffer::Copy(const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer*& out_buffer, uint64_t& out_offset, uint64_t& out_range) {
KYTY_PROFILER_FUNCTION();
if (ctx == nullptr || src == nullptr || out_buffer == nullptr || out_offset == nullptr ||
out_range == nullptr) {
if (src == nullptr) {
EXIT("invalid host stream upload\n");
}
std::lock_guard lock(m_mutex);
@@ -66,12 +64,12 @@ bool HostStreamBuffer::Copy(GraphicContext* ctx, const void* src, uint64_t size,
if (offset > CAPACITY || size > CAPACITY - offset) {
return false;
}
EnsureBuffer(ctx);
EnsureBuffer();
std::memcpy(static_cast<uint8_t*>(m_mapped) + offset, src, static_cast<size_t>(size));
m_offset = offset + size;
*out_buffer = m_buffer.get();
*out_offset = offset;
*out_range = size;
out_buffer = m_buffer.get();
out_offset = offset;
out_range = size;
return true;
}
@@ -83,14 +81,13 @@ void HostStreamBuffer::Reset() noexcept {
void HostStreamBuffer::Release() noexcept {
std::lock_guard lock(m_mutex);
if (m_buffer != nullptr) {
if (m_ctx == nullptr || m_mapped == nullptr) {
if (m_mapped == nullptr) {
EXIT("invalid host stream buffer release state\n");
}
VulkanUnmapMemory(m_ctx, &m_buffer->memory);
VulkanDeleteBuffer(m_ctx, m_buffer.get());
m_graphics.UnmapMemory(m_buffer->memory);
m_graphics.DeleteBuffer(*m_buffer);
m_buffer.reset();
}
m_ctx = nullptr;
m_mapped = nullptr;
m_offset = 0;
}
@@ -18,17 +18,17 @@ struct VulkanBuffer;
// backend with scheduler watches will not change descriptor/render call sites.
class HostStreamBuffer final {
public:
HostStreamBuffer();
explicit HostStreamBuffer(GraphicContext& graphics);
~HostStreamBuffer();
KYTY_CLASS_NO_COPY(HostStreamBuffer);
[[nodiscard]] bool Copy(GraphicContext* ctx, const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer** out_buffer, uint64_t* out_offset, uint64_t* out_range);
[[nodiscard]] bool Copy(const void* src, uint64_t size, uint64_t alignment,
VulkanBuffer*& out_buffer, uint64_t& out_offset, uint64_t& out_range);
void Reset() noexcept;
void Release() noexcept;
private:
void EnsureBuffer(GraphicContext* ctx);
void EnsureBuffer();
// Interim fence-scoped backend: one command processor's eight live command buffers reserve up
// to 128 MiB lazily. Additional active processors scale that aggregate until this backend is
@@ -36,7 +36,7 @@ private:
static constexpr uint64_t CAPACITY = 16ull * 1024ull * 1024ull;
mutable std::mutex m_mutex;
GraphicContext* m_ctx = nullptr;
GraphicContext& m_graphics;
std::unique_ptr<VulkanBuffer> m_buffer;
void* m_mapped = nullptr;
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 uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000;
bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t* value) {
if (host_frequency == 0 || value == nullptr) {
bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t& value) {
if (host_frequency == 0) {
return false;
}
@@ -42,7 +42,7 @@ bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t*
if (whole_value > MAX_VALUE - fractional_value) {
return false;
}
*value = whole_value + fractional_value;
value = whole_value + fractional_value;
return true;
}
@@ -50,25 +50,22 @@ uint64_t ReadReferenceClock() {
const auto host_frequency = LibKernel::KernelGetTscFrequency();
const auto host_ticks = LibKernel::KernelReadTsc();
uint64_t value = 0;
if (!ScaleReferenceClock(host_ticks, host_frequency, &value)) {
if (!ScaleReferenceClock(host_ticks, host_frequency, value)) {
EXIT("cannot scale host clock, ticks=0x%016" PRIx64 " frequency=%" PRIu64 "\n", host_ticks,
host_frequency);
}
return value;
}
static void SubmitLabel(CommandBuffer* buffer, LabelCallback callback_1 = nullptr,
static void SubmitLabel(CommandBuffer& buffer, LabelCallback callback_1 = nullptr,
LabelCallback callback_2 = nullptr, const uint64_t* args = nullptr) {
auto* label = LabelCreate(g_render_ctx->GetGraphicCtx(), callback_1, callback_2, args);
LabelSet(buffer, label);
LabelDelete(label);
auto* label = LabelCreate(callback_1, callback_2, args);
LabelSet(buffer, *label);
LabelDelete(*label);
}
static bool CompleteDisplayBufferFlip(const uint64_t* args) {
if (g_render_ctx == nullptr || args == nullptr) {
EXIT("GPU flip completion has invalid state, render_ctx=%p args=%p\n",
static_cast<const void*>(g_render_ctx), static_cast<const void*>(args));
}
EXIT_IF(args == nullptr);
Presentation::DisplayBufferCompleteFlipFromGpu(args[0]);
return true;
}
@@ -90,20 +87,17 @@ enum class EndOfPipeWriteSize : uint32_t { Dword = 4, Qword = 8 };
enum class EndOfPipeWriteAction { Write, WriteBack, Interrupt, InterruptWriteBack };
static bool TriggerEopEventCallback(const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(args == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
GetRenderContext().TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true;
}
static bool TriggerDefaultEopEventCallback(const uint64_t* /*args*/) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(0);
GetRenderContext().TriggerEopEvent(0);
return true;
}
static void ValidateEndOfPipeSignal(const EndOfPipeSignal& signal) {
EXIT_IF(g_render_ctx == nullptr);
if (signal.destination.has_value()) {
EXIT_IF(*signal.destination == 0);
}
@@ -121,13 +115,13 @@ static void RecordEndOfPipeSignal(const EndOfPipeSignal& signal) {
switch (signal.completion) {
case EndOfPipeCompletion::None: return;
case EndOfPipeCompletion::Interrupt:
SubmitLabel(signal.buffer, nullptr, TriggerEopEventCallback, args);
SubmitLabel(*signal.buffer, nullptr, TriggerEopEventCallback, args);
return;
case EndOfPipeCompletion::Flip:
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, nullptr, args);
SubmitLabel(*signal.buffer, CompleteDisplayBufferFlip, nullptr, args);
return;
case EndOfPipeCompletion::FlipAndInterrupt:
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback,
SubmitLabel(*signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback,
args);
return;
}
@@ -149,7 +143,7 @@ static bool TriggersInterrupt(EndOfPipeWriteAction action) {
action == EndOfPipeWriteAction::InterruptWriteBack;
}
static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer* buffer, uint64_t destination,
static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer& buffer, uint64_t destination,
uint64_t value, EndOfPipeWriteSize size,
EndOfPipeWriteAction action, uint32_t context_id = 0) {
const auto width = static_cast<uint32_t>(size);
@@ -158,7 +152,7 @@ static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer* buffer, uint
const bool interrupt = TriggersInterrupt(action);
EndOfPipeSignal signal {
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = DebugOperation(action),
.debug_args = interrupt ? std::array {width, context_id, value_low, value_high}
@@ -179,21 +173,20 @@ void TriggerAgcUserInterrupt() {
}
void TriggerEopEvent(uint32_t context_id) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(context_id);
GetRenderContext().TriggerEopEvent(context_id);
}
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Write);
}
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t dw_offset, uint32_t dw_num) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopWrite,
.debug_args = {dw_offset, dw_num, 0, 0},
@@ -202,13 +195,13 @@ void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t*
});
}
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr,
uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write);
}
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr,
uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
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);
}
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
@@ -228,19 +221,19 @@ void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer
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) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
}
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::WriteBack);
}
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
@@ -248,7 +241,7 @@ void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer*
context_id);
}
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
@@ -256,24 +249,24 @@ void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer*
context_id);
}
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Interrupt, context_id);
}
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) {
RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Interrupt, context_id);
}
uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index, int flip_mode,
uint64_t PrepareDisplayBufferFlip(CommandBuffer& buffer, int handle, int index, int flip_mode,
int64_t flip_arg) {
for (;;) {
uint64_t request_id = 0;
const auto result = Presentation::DisplayBufferSubmitFlipFromGpu(
buffer, handle, index, flip_mode, flip_arg, &request_id);
buffer, handle, index, flip_mode, flip_arg, request_id);
if (result == OK) {
EXIT_IF(request_id == 0);
return request_id;
@@ -287,13 +280,13 @@ uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index,
}
}
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopWriteBackFlip,
.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,
int64_t flip_arg, uint64_t request_id) {
const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
RecordEndOfPipeSignal({
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopFlip,
.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) {
RecordEndOfPipeSignal({
.buffer = buffer,
.buffer = &buffer,
.submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopOnlyFlip,
.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) {
ValidateEndOfPipeSignal({.buffer = buffer});
void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id) {
ValidateEndOfPipeSignal({.buffer = &buffer});
uint64_t args[LABEL_ARGS_MAX] = {static_cast<uint64_t>(context_id)};
SubmitLabel(buffer, nullptr, TriggerEopEventCallback, args);
@@ -353,11 +346,10 @@ static void EopEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) {
static void EopEventDeleteFunc(LibKernel::EventQueue::KernelEqueue eq,
LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
EXIT_IF(g_render_ctx == nullptr);
EXIT_NOT_IMPLEMENTED(event->event.filter != LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS);
if (event->event.ident == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT ||
event->event.ident == GRAPHICS_EVENT_EOP) {
g_render_ctx->DeleteEopEq(eq, static_cast<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) {
EXIT_IF(g_render_ctx == nullptr);
LibKernel::EventQueue::KernelEqueueEvent event;
event.triggered = false;
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 &&
(id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP)) {
g_render_ctx->AddEopEq(eq, id);
GetRenderContext().AddEopEq(eq, id);
}
return result;
}
int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) {
EXIT_IF(g_render_ctx == nullptr);
int result = LibKernel::EventQueue::KernelDeleteEvent(
eq, static_cast<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) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->GetGdsBuffer()->Read(g_render_ctx->GetGraphicCtx(), dst, dw_offset, dw_size);
GetRenderContext().GetGdsBuffer().Read(dst, dw_offset, dw_size);
}
void DeleteBuffers() {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->GetBufferCache()->ResetNullBuffer();
GetRenderContext().GetBufferCache().ResetNullBuffer();
}
} // namespace Libs::Graphics::Sync
+17 -17
View File
@@ -12,48 +12,48 @@ class CommandBuffer;
namespace Sync {
[[nodiscard]] bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency,
uint64_t* value);
uint64_t& value);
[[nodiscard]] uint64_t ReadReferenceClock();
void TriggerAgcUserInterrupt();
void TriggerEopEvent(uint32_t context_id);
void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id);
void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id);
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t value);
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr,
uint64_t value);
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t dw_offset, uint32_t dw_num);
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr,
uint64_t value);
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value);
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value);
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value);
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
uint32_t context_id = 0);
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id = 0);
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
uint32_t context_id = 0);
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer& buffer,
uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id = 0);
[[nodiscard]] uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index,
[[nodiscard]] uint64_t PrepareDisplayBufferFlip(CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg);
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index,
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t request_id);
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr,
uint32_t value, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id);
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer* buffer,
void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer& buffer,
uint32_t* dst_gpu_addr, uint32_t value,
int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id);
File diff suppressed because it is too large. Load diff
+41 -48
View File
@@ -53,66 +53,60 @@ public:
bool full = false;
};
TextureCache(PageManager& page_manager, BufferCache& buffer_cache,
TextureCache(GraphicContext& graphics, PageManager& page_manager, BufferCache& buffer_cache,
ResourceMutex& resource_mutex);
~TextureCache();
KYTY_CLASS_NO_COPY(TextureCache);
[[nodiscard]] VulkanImage* FindTexture(CommandBuffer* command, GraphicContext* ctx,
const ImageInfo& info, bool metadata_read);
[[nodiscard]] StorageTextureVulkanImage*
FindStorageTexture(CommandBuffer* command, GraphicContext* ctx, const ImageInfo& info);
[[nodiscard]] RenderTextureVulkanImage*
FindRenderTarget(CommandBuffer* command, GraphicContext* ctx, const RenderTargetInfo& info);
[[nodiscard]] DepthStencilVulkanImage*
FindDepthTarget(CommandBuffer* command, GraphicContext* ctx, const DepthTargetInfo& info);
[[nodiscard]] VulkanImage& FindTexture(CommandBuffer& command, const ImageInfo& info,
bool metadata_read);
[[nodiscard]] StorageTextureVulkanImage& FindStorageTexture(CommandBuffer& command,
const ImageInfo& info);
[[nodiscard]] RenderTextureVulkanImage& FindRenderTarget(CommandBuffer& command,
const RenderTargetInfo& info);
[[nodiscard]] DepthStencilVulkanImage& FindDepthTarget(CommandBuffer& command,
const DepthTargetInfo& info);
[[nodiscard]] std::vector<VideoOutVulkanImage*>
RegisterVideoOutSurfaces(GraphicContext* ctx, const std::vector<VideoOutInfo>& infos);
void RefreshVideoOut(VideoOutVulkanImage* image, bool render_target = false);
RegisterVideoOutSurfaces(const std::vector<VideoOutInfo>& infos);
void RefreshVideoOut(VideoOutVulkanImage& image, bool render_target = false);
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);
void MarkGpuWritten(VulkanImage* image);
void MarkGpuWritten(VulkanImage& image);
void PrepareHostWrite(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size,
bool formatted_buffer_write = false);
[[nodiscard]] RenderTextureVulkanImage* FindRenderTargetByRange(CommandBuffer* command,
[[nodiscard]] RenderTextureVulkanImage* FindRenderTargetByRange(CommandBuffer& command,
uint64_t vaddr, uint64_t size);
[[nodiscard]] vk::ImageView GetRenderTargetAttachmentView(GraphicContext* ctx,
RenderTextureVulkanImage* image,
[[nodiscard]] vk::ImageView GetRenderTargetAttachmentView(RenderTextureVulkanImage& image,
vk::Format format, uint32_t level,
uint32_t base_layer,
uint32_t layer_count);
[[nodiscard]] vk::ImageView GetDepthTargetAttachmentView(GraphicContext* ctx,
DepthStencilVulkanImage* image,
[[nodiscard]] vk::ImageView GetDepthTargetAttachmentView(DepthStencilVulkanImage& image,
uint32_t base_layer,
uint32_t layer_count);
[[nodiscard]] vk::ImageView
GetDepthTargetSampledView(GraphicContext* ctx, DepthStencilVulkanImage* image,
vk::Format view_format, uint32_t swizzle, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count);
[[nodiscard]] vk::ImageView GetSampledColorView(GraphicContext* ctx, VulkanImage* image,
vk::Format view_format, uint32_t swizzle,
uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer,
uint32_t layer_count);
[[nodiscard]] vk::ImageView
GetRenderTargetStorageView(GraphicContext* ctx, RenderTextureVulkanImage* image,
vk::Format view_format, uint32_t base_level, uint32_t level_count,
GetDepthTargetSampledView(DepthStencilVulkanImage& image, vk::Format view_format,
uint32_t swizzle, uint32_t base_level, uint32_t level_count,
vk::ImageViewType type, uint32_t base_layer, uint32_t layer_count);
[[nodiscard]] vk::ImageView GetStorageTextureSampledView(GraphicContext* ctx,
StorageTextureVulkanImage* image,
[[nodiscard]] vk::ImageView GetSampledColorView(VulkanImage& image, vk::Format view_format,
uint32_t swizzle, uint32_t base_level,
uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count);
[[nodiscard]] vk::ImageView
GetRenderTargetStorageView(RenderTextureVulkanImage& image, vk::Format view_format,
uint32_t base_level, uint32_t level_count, vk::ImageViewType type,
uint32_t base_layer, uint32_t layer_count);
[[nodiscard]] vk::ImageView GetStorageTextureSampledView(StorageTextureVulkanImage& image,
const ImageInfo& info);
[[nodiscard]] vk::ImageView GetStorageTextureStorageView(GraphicContext* ctx,
StorageTextureVulkanImage* image,
[[nodiscard]] vk::ImageView GetStorageTextureStorageView(StorageTextureVulkanImage& image,
uint32_t base_level);
[[nodiscard]] DepthStencilVulkanImage*
FindDepthTargetByRange(CommandBuffer* command, uint64_t vaddr, uint64_t size,
FindDepthTargetByRange(CommandBuffer& command, uint64_t vaddr, uint64_t size,
bool allow_containing_sampled = false);
[[nodiscard]] RegionInfo QueryRegion(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo* info);
void RegisterMeta(GraphicContext* ctx, uint64_t vaddr, uint64_t size, uint32_t layers = 1);
[[nodiscard]] bool ResolveMetaRange(uint64_t vaddr, uint64_t size, MetaRangeInfo& info);
void RegisterMeta(uint64_t vaddr, uint64_t size, uint32_t layers = 1);
[[nodiscard]] bool IsMeta(uint64_t vaddr);
[[nodiscard]] bool IsMetaRange(uint64_t vaddr, uint64_t size);
[[nodiscard]] bool IsMetaCleared(uint64_t vaddr, uint32_t slice);
@@ -122,8 +116,8 @@ public:
PageFaultPhase phase) noexcept;
void UnmapMemory(uint64_t vaddr, uint64_t size);
VulkanImage* GetDummySampledTexture(bool uint_format, bool image_3d);
VulkanImage* GetDummyStorageTexture(bool uint_format, bool image_3d);
VulkanImage& GetDummySampledTexture(bool uint_format, bool image_3d);
VulkanImage& GetDummyStorageTexture(bool uint_format, bool image_3d);
private:
struct CachedImage;
@@ -135,19 +129,18 @@ private:
uint32_t clear_mask = 0;
bool gpu_modified = false;
};
[[nodiscard]] vk::ImageView GetImageView(GraphicContext* ctx, VulkanImage* image,
const ImageViewInfo& info);
[[nodiscard]] vk::ImageView GetImageView(VulkanImage& image, const ImageViewInfo& info);
[[nodiscard]] bool HasMetaOverlapLocked(uint64_t vaddr, uint64_t size) const;
[[nodiscard]] CachedImage* FindGpuReadbackPageCandidateLocked(uint64_t vaddr, uint64_t size);
void RequireNoMetaOverlapLocked(uint64_t vaddr, uint64_t size) const;
void ResolveImageMetadataOverlapsLocked(GraphicContext* ctx, uint64_t vaddr, uint64_t size);
void ResolveImageMetadataOverlapsLocked(uint64_t vaddr, uint64_t size);
void MarkSampledAliasesCpuDirtyLocked(uint64_t vaddr, uint64_t size);
void RetireSampledTargetAliases(GraphicContext* ctx, const ImageInfo& requested);
void ResolveStorageImageOverlaps(GraphicContext* ctx, const ImageInfo& requested);
void RetireStorageDepthAliasLocked(GraphicContext* ctx, const ImageInfo& requested);
void RetireSampledTargetAliases(const ImageInfo& requested);
void ResolveStorageImageOverlaps(const ImageInfo& requested);
void RetireStorageDepthAliasLocked(const ImageInfo& requested);
void RegisterImageLocked(CachedImage& image);
void UnregisterImageLocked(CachedImage& image, bool release_tracking);
[[nodiscard]] VulkanImage* PublishImage(CommandBuffer* command,
[[nodiscard]] VulkanImage& PublishImage(CommandBuffer& command,
std::shared_ptr<CachedImage> image);
[[nodiscard]] std::vector<CachedImage*> FindImagesInRegionLocked(uint64_t vaddr, uint64_t size,
bool page_overlap);
@@ -157,13 +150,13 @@ private:
const CachedImage* native_image_source = nullptr);
void RetireDepthMetadataLocked(const std::vector<CachedImage*>& retire,
uint64_t preserve_address = 0);
void MaterializeImagesToGuestLocked(GraphicContext* ctx,
const std::vector<std::shared_ptr<CachedImage>>& images);
void MaterializeImagesToGuestLocked(const std::vector<std::shared_ptr<CachedImage>>& images);
void SynchronizeColorImageToBufferLocked(CachedImage& cached, uint64_t write_address,
uint64_t write_size);
void SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint64_t write_address,
uint64_t write_size);
GraphicContext& m_graphics;
std::unique_ptr<DummyTextureCache> m_dummy_textures;
TrackingSpinLock m_lock;
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);
TileBlockLayout block {};
EXIT_NOT_IMPLEMENTED(
!TileGetBlockLayout(TileBlockFamily::Depth64KB, bytes_per_element, &block) ||
!TileGetBlockLayout(TileBlockFamily::Depth64KB, bytes_per_element, block) ||
Prospero::NumBytesPerElement(format) != bytes_per_element);
const uint64_t slice_size = size / layers;
@@ -61,21 +61,20 @@ DepthTransfer MakeDepthTransfer(uint64_t size, uint32_t layers, uint32_t format,
return transfer;
}
void UploadDepth(GraphicContext* ctx, DepthStencilVulkanImage* image, uint64_t source_address,
uint64_t size, uint32_t layers, uint32_t format, uint32_t bytes_per_element,
uint32_t width, uint32_t height, uint32_t pitch, uint32_t base_layer,
void UploadDepth(DepthStencilVulkanImage& image, uint64_t source_address, uint64_t size,
uint32_t layers, uint32_t format, uint32_t bytes_per_element, uint32_t width,
uint32_t height, uint32_t pitch, uint32_t base_layer,
vk::ImageAspectFlags aspect) {
auto transfer = MakeDepthTransfer(size, layers, format, bytes_per_element, width, height, pitch,
base_layer, aspect);
Transfer::UploadTiledImage(ctx, image, reinterpret_cast<const void*>(source_address), size,
size, transfer.infos, transfer.regions,
Transfer::UploadTiledImage(image, reinterpret_cast<const void*>(source_address), size, size,
transfer.infos, transfer.regions,
vk::ImageLayout::eDepthStencilAttachmentOptimal);
}
template <uint32_t (*Encode)(uint16_t)>
void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
uint32_t base_layer) {
void UploadPromotedD16Depth(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, uint32_t base_layer) {
const uint64_t guest_slice_size = info.size / info.layers;
const uint64_t texels = static_cast<uint64_t>(info.pitch) * info.height;
const uint64_t host_slice_size = texels * sizeof(uint32_t);
@@ -86,7 +85,7 @@ void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image,
info.bytes_per_element, info.width, info.height, info.pitch,
base_layer, vk::ImageAspectFlagBits::eDepth);
std::vector<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);
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::UploadImage(ctx, image, host_linear.Data(), host_upload_size, transfer.regions,
Transfer::UploadImage(image, host_linear.Data(), host_upload_size, transfer.regions,
vk::ImageLayout::eDepthStencilAttachmentOptimal);
}
} // namespace
void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
void Tiler::DetileImage(GpuTextureVulkanImage& image, const ImageInfo& info,
const BufferImageCopySource& source, bool refresh, bool storage) const {
if (refresh) Transfer::WaitForGraphicsIdle(ctx);
if (refresh) Transfer::WaitForGraphicsIdle();
const bool array_texture = TextureIsLayeredTexture(info.type);
const bool volume_texture = TextureIs3DTexture(info.type);
auto layout = TextureCalcUploadLayout(
info.format, info.width, info.height, info.levels, info.depth, info.pitch, info.tile,
info.size, true, volume_texture, storage ? "StorageTextureCache" : "TextureCache");
auto regions = TextureBuildUploadRegions(layout, image->format, info.width, info.height,
auto regions = TextureBuildUploadRegions(layout, image.format, info.width, info.height,
info.depth, info.levels, array_texture, volume_texture,
TextureUploadDestination::MipLevels);
TextureUploadGuestImage(ctx, image, reinterpret_cast<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,
info.levels, storage ? "StorageTextureCache" : "TextureCache",
storage ? vk::ImageLayout::eGeneral
: vk::ImageLayout::eShaderReadOnlyOptimal);
}
void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh, uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image->samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle(ctx);
void Tiler::DetileImage(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, bool refresh,
uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image.samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle();
if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) {
switch (info.format) {
case vk::Format::eD24UnormS8Uint:
UploadPromotedD16Depth<EncodeD16AsD24>(ctx, image, info, source, base_layer);
UploadPromotedD16Depth<EncodeD16AsD24>(image, info, source, base_layer);
return;
case vk::Format::eD32SfloatS8Uint:
UploadPromotedD16Depth<EncodeD16AsD32>(ctx, image, info, source, base_layer);
UploadPromotedD16Depth<EncodeD16AsD32>(image, info, source, base_layer);
return;
default: EXIT_NOT_IMPLEMENTED(true);
}
}
UploadDepth(ctx, image, source.address, info.size, info.layers, info.guest_format,
UploadDepth(image, source.address, info.size, info.layers, info.guest_format,
info.bytes_per_element, info.width, info.height, info.pitch, base_layer,
vk::ImageAspectFlagBits::eDepth);
}
void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh, uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image->samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle(ctx);
void Tiler::DetileStencil(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, bool refresh,
uint32_t base_layer) const {
EXIT_NOT_IMPLEMENTED(info.samples != 1 || image.samples != 1);
if (refresh) Transfer::WaitForGraphicsIdle();
const auto format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt);
const auto pitch = TileGetTexturePitch(format, info.width, 1,
Prospero::GpuEnumValue(Prospero::TileMode::kDepth));
UploadDepth(ctx, image, source.address, info.stencil_size, info.layers, format, 1, info.width,
UploadDepth(image, source.address, info.stencil_size, info.layers, format, 1, info.width,
info.height, pitch, base_layer, vk::ImageAspectFlagBits::eStencil);
}
+6 -8
View File
@@ -9,21 +9,19 @@ namespace Libs::Graphics {
struct DepthStencilVulkanImage;
struct GpuTextureVulkanImage;
struct GraphicContext;
class Tiler final {
public:
Tiler() = default;
KYTY_CLASS_NO_COPY(Tiler);
void DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
void DetileImage(GpuTextureVulkanImage& image, const ImageInfo& info,
const BufferImageCopySource& source, bool refresh, bool storage) const;
void DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source, bool refresh,
void DetileImage(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, bool refresh,
uint32_t base_layer = 0) const;
void DetileStencil(DepthStencilVulkanImage& image, const DepthTargetInfo& info,
const BufferImageCopySource& source, bool refresh,
uint32_t base_layer = 0) const;
void DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh, uint32_t base_layer = 0) const;
};
} // namespace Libs::Graphics
+244 -235
View File
@@ -82,13 +82,14 @@ bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size) {
return true;
}
void WaitForGraphicsIdle(GraphicContext* ctx) {
void WaitForGraphicsIdle() {
auto& graphics = GetRenderContext().GetGraphics();
Common::Mutex* locked[GraphicContext::QUEUES_NUM] {};
int locked_num = 0;
for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) {
auto* mutex = ctx->queues[id].mutex;
if (mutex == nullptr || ctx->queues[id].vk_queue == nullptr) {
auto* mutex = graphics.queues[id].mutex;
if (mutex == nullptr || graphics.queues[id].vk_queue == nullptr) {
continue;
}
@@ -106,7 +107,7 @@ void WaitForGraphicsIdle(GraphicContext* ctx) {
}
}
auto result = ctx->device.waitIdle();
auto result = graphics.device.waitIdle();
for (int i = locked_num - 1; i >= 0; i--) {
locked[i]->Unlock();
@@ -119,7 +120,7 @@ void WaitForGraphicsIdle(GraphicContext* ctx) {
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
}
static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level,
static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage& dst_image, uint32_t base_level,
uint32_t levels, vk::ImageAspectFlags aspect_mask,
vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout);
@@ -129,7 +130,7 @@ static void ExecuteImmediateCommands(const Recorder& recorder) {
// not touch every caller.
CommandBuffer command(GraphicContext::QUEUE_UTIL);
command.Begin();
recorder(&command, command.Handle());
recorder(command, command.Handle());
command.End();
command.Execute();
command.WaitForFence();
@@ -205,12 +206,12 @@ static void RecordBufferToImageCopy(CommandBuffer& command, VulkanBuffer& src_bu
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer);
SetImageLayout(vk_command, &dst_image, 0, VK_REMAINING_MIP_LEVELS, transition_aspects,
SetImageLayout(vk_command, dst_image, 0, VK_REMAINING_MIP_LEVELS, transition_aspects,
initial_layout, vk::ImageLayout::eTransferDstOptimal);
vk_command.copyBufferToImage(src_buffer.buffer, dst_image.image,
vk::ImageLayout::eTransferDstOptimal,
static_cast<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);
}
@@ -251,7 +252,7 @@ RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image, VulkanBuffer
for (const auto& region: regions) {
aspects |= GetTransferAspects(src_image, region.aspect);
}
SetImageLayout(vk_command, &src_image, 0, VK_REMAINING_MIP_LEVELS, aspects, src_image.layout,
SetImageLayout(vk_command, src_image, 0, VK_REMAINING_MIP_LEVELS, aspects, src_image.layout,
vk::ImageLayout::eTransferSrcOptimal);
SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite,
@@ -264,7 +265,7 @@ RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image, VulkanBuffer
SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eTransferWrite, final_access,
vk::PipelineStageFlagBits::eTransfer, final_stage);
SetImageLayout(vk_command, &src_image, 0, VK_REMAINING_MIP_LEVELS, aspects,
SetImageLayout(vk_command, src_image, 0, VK_REMAINING_MIP_LEVELS, aspects,
vk::ImageLayout::eTransferSrcOptimal, final_layout);
}
@@ -279,28 +280,27 @@ static void RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image,
class ReusableStagingBuffer {
public:
ReusableStagingBuffer() = default;
explicit ReusableStagingBuffer(GraphicContext& graphics): m_graphics(graphics) {}
~ReusableStagingBuffer() = default;
KYTY_CLASS_NO_COPY(ReusableStagingBuffer);
void UploadToBuffer(GraphicContext* ctx, VulkanBuffer* dst_buffer, const void* src_data,
uint64_t size, uint64_t dst_offset) {
RecordUpload<true>(ctx, src_data, size, [&](CommandBuffer*, vk::CommandBuffer vk_command) {
void UploadToBuffer(VulkanBuffer& dst_buffer, const void* src_data, uint64_t size,
uint64_t dst_offset) {
RecordUpload<true>(src_data, size, [&](CommandBuffer&, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(
vk_command, m_buffer.buffer, 0, size, vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer);
SetBufferMemoryBarrier(
vk_command, dst_buffer->buffer, dst_offset, size,
vk_command, dst_buffer.buffer, dst_offset, size,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer);
const vk::BufferCopy copy_region {
.srcOffset = 0, .dstOffset = dst_offset, .size = size};
vk_command.copyBuffer(m_buffer.buffer, dst_buffer->buffer, 1, &copy_region);
vk_command.copyBuffer(m_buffer.buffer, dst_buffer.buffer, 1, &copy_region);
SetBufferMemoryBarrier(
vk_command, dst_buffer->buffer, dst_offset, size,
vk::AccessFlagBits::eTransferWrite,
vk_command, dst_buffer.buffer, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndexRead |
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
vk::PipelineStageFlagBits::eTransfer,
@@ -310,61 +310,57 @@ public:
});
}
void UploadToImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageAspectFlags copy_aspect,
vk::ImageLayout initial_layout, vk::ImageLayout final_layout) {
const auto transition_aspects = GetTransferAspects(*image, copy_aspect);
RecordUpload<false>(ctx, src_data, size, [&](CommandBuffer* command, vk::CommandBuffer) {
void UploadToImage(VulkanImage& image, const void* src_data, uint64_t size, uint32_t src_pitch,
vk::ImageAspectFlags copy_aspect, vk::ImageLayout initial_layout,
vk::ImageLayout final_layout) {
const auto transition_aspects = GetTransferAspects(image, copy_aspect);
RecordUpload<false>(src_data, size, [&](CommandBuffer& command, vk::CommandBuffer) {
const auto region = MakeBufferImageCopy(0, src_pitch, copy_aspect, 0, 0, {0, 0, 0},
{image->extent.width, image->extent.height, 1});
RecordBufferToImageCopy(*command, m_buffer, *image,
{image.extent.width, image.extent.height, 1});
RecordBufferToImageCopy(command, m_buffer, image,
std::span<const vk::BufferImageCopy>(&region, 1),
transition_aspects, initial_layout, final_layout);
});
}
void UploadToImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data,
uint64_t size, std::span<const BufferImageCopy> regions,
vk::ImageLayout dst_layout) {
RecordUpload<false>(ctx, src_data, size, [&](CommandBuffer* command, vk::CommandBuffer) {
void UploadToImage(VulkanImage& dst_image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
RecordUpload<false>(src_data, size, [&](CommandBuffer& command, vk::CommandBuffer) {
vk::ImageAspectFlags transition_aspects = {};
for (const auto& region: regions) {
transition_aspects |= GetTransferAspects(*dst_image, region.aspect);
transition_aspects |= GetTransferAspects(dst_image, region.aspect);
}
RecordBufferToImageCopy(*command, m_buffer, *dst_image,
ConvertBufferImageCopies(regions), transition_aspects,
dst_image->layout, dst_layout);
RecordBufferToImageCopy(command, m_buffer, dst_image, ConvertBufferImageCopies(regions),
transition_aspects, dst_image.layout, dst_layout);
});
}
void DownloadFromImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
void DownloadFromImage(void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage& src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect) {
Common::LockGuard lock(m_mutex);
EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst);
EnsureBuffer(size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
RecordImageToBuffer(*command, *src_image, m_buffer, dst_pitch, src_layout, aspect);
ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) {
RecordImageToBuffer(command, src_image, m_buffer, dst_pitch, src_layout, aspect);
});
std::memcpy(dst_data, m_mapped_data, size);
}
void DownloadFromImage(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout) {
WithDownloadedImage(ctx, size, regions, src_image, src_layout,
void DownloadFromImage(void* dst_data, uint64_t size, std::span<const ImageBufferCopy> regions,
VulkanImage& src_image, vk::ImageLayout src_layout) {
WithDownloadedImage(size, regions, src_image, src_layout,
[&](std::span<const uint8_t> data) {
std::memcpy(dst_data, data.data(), data.size());
});
}
void ProcessDownloadedImage(GraphicContext* ctx, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout,
void ProcessDownloadedImage(uint64_t size, std::span<const ImageBufferCopy> regions,
VulkanImage& src_image, vk::ImageLayout src_layout,
const DownloadedImageConsumer& consumer) {
WithDownloadedImage(ctx, size, regions, src_image, src_layout,
WithDownloadedImage(size, regions, src_image, src_layout,
[&](std::span<const uint8_t> data) {
if (m_host_cached) {
consumer(data);
@@ -378,12 +374,12 @@ public:
});
}
void Release(GraphicContext* ctx) {
void Release() {
Common::LockGuard lock(m_mutex);
if (m_buffer.buffer != nullptr) {
EXIT_IF(ctx == nullptr || m_mapped_data == nullptr);
VulkanUnmapMemory(ctx, &m_buffer.memory);
VulkanDeleteBuffer(ctx, &m_buffer);
EXIT_IF(m_mapped_data == nullptr);
m_graphics.UnmapMemory(m_buffer.memory);
m_graphics.DeleteBuffer(m_buffer);
}
m_capacity = 0;
m_mapped_data = nullptr;
@@ -392,42 +388,40 @@ public:
private:
template <typename Consumer>
void WithDownloadedImage(GraphicContext* ctx, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout, const Consumer& consumer) {
void WithDownloadedImage(uint64_t size, std::span<const ImageBufferCopy> regions,
VulkanImage& src_image, vk::ImageLayout src_layout,
const Consumer& consumer) {
Common::LockGuard lock(m_mutex);
EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
RecordImageToBuffer(*command, *src_image, m_buffer, regions, src_layout);
EnsureBuffer(size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) {
RecordImageToBuffer(command, src_image, m_buffer, regions, src_layout);
});
consumer(std::span<const uint8_t>(static_cast<const uint8_t*>(m_mapped_data),
static_cast<size_t>(size)));
}
template <bool WaitIdle, typename Recorder>
void RecordUpload(GraphicContext* ctx, const void* src_data, uint64_t size,
const Recorder& recorder) {
void RecordUpload(const void* src_data, uint64_t size, const Recorder& recorder) {
Common::LockGuard lock(m_mutex);
CopyFromHost(ctx, src_data, size, vk::BufferUsageFlagBits::eTransferSrc);
CopyFromHost(src_data, size, vk::BufferUsageFlagBits::eTransferSrc);
if constexpr (WaitIdle) {
WaitForGraphicsIdle(ctx);
WaitForGraphicsIdle();
}
ExecuteImmediateCommands(recorder);
}
void CopyFromHost(GraphicContext* ctx, const void* src_data, uint64_t size,
vk::BufferUsageFlags usage) {
EnsureBuffer(ctx, size, usage);
void CopyFromHost(const void* src_data, uint64_t size, vk::BufferUsageFlags usage) {
EnsureBuffer(size, usage);
std::memcpy(m_mapped_data, src_data, size);
}
void EnsureBuffer(GraphicContext* ctx, uint64_t size, vk::BufferUsageFlags usage) {
void EnsureBuffer(uint64_t size, vk::BufferUsageFlags usage) {
if (m_capacity < size || m_buffer.usage != usage) {
if (m_buffer.buffer != nullptr) {
VulkanUnmapMemory(ctx, &m_buffer.memory);
m_graphics.UnmapMemory(m_buffer.memory);
m_mapped_data = nullptr;
VulkanDeleteBuffer(ctx, &m_buffer);
m_graphics.DeleteBuffer(m_buffer);
}
m_buffer.usage = usage;
@@ -439,18 +433,19 @@ private:
usage & vk::BufferUsageFlagBits::eTransferDst
? vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eHostCached)
: vk::MemoryPropertyFlags {};
VulkanCreateBuffer(ctx, size, &m_buffer);
m_graphics.CreateBuffer(size, m_buffer);
m_capacity = size;
const auto& properties = ctx->GetPhysicalDeviceMemoryProperties();
const auto& properties = m_graphics.GetPhysicalDeviceMemoryProperties();
EXIT_IF(m_buffer.memory.type >= properties.memoryTypeCount);
m_host_cached =
static_cast<bool>(properties.memoryTypes[m_buffer.memory.type].propertyFlags &
vk::MemoryPropertyFlagBits::eHostCached);
VulkanMapMemory(ctx, &m_buffer.memory, &m_mapped_data);
m_graphics.MapMemory(m_buffer.memory, m_mapped_data);
}
}
GraphicContext& m_graphics;
Common::Mutex m_mutex;
VulkanBuffer m_buffer;
uint64_t m_capacity = 0;
@@ -459,10 +454,26 @@ private:
std::vector<uint8_t> m_cached_readback;
};
// Do not replace with one
static ReusableStagingBuffer g_texture_staging_buffer;
static ReusableStagingBuffer g_vertex_staging_buffer;
static ReusableStagingBuffer g_readback_staging_buffer;
struct TransferResources {
explicit TransferResources(GraphicContext& graphics)
: graphics(graphics), texture(graphics), vertex(graphics), readback(graphics) {}
GraphicContext& graphics;
ReusableStagingBuffer texture;
ReusableStagingBuffer vertex;
ReusableStagingBuffer readback;
};
static Common::Mutex g_resources_mutex;
static std::unique_ptr<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) {
return format == vk::Format::eBc1RgbUnormBlock || format == vk::Format::eBc1RgbSrgbBlock ||
@@ -507,55 +518,57 @@ static uint32_t GetFormatTexelSize(vk::Format format) {
}
}
static ReusableStagingBuffer* GetStagingBuffer(StagingBufferType type) {
static ReusableStagingBuffer& GetStagingBuffer(StagingBufferType type) {
auto& resources = GetResources();
switch (type) {
case StagingBufferType::Texture: return &g_texture_staging_buffer;
case StagingBufferType::Vertex: return &g_vertex_staging_buffer;
case StagingBufferType::ReadBack: return &g_readback_staging_buffer;
case StagingBufferType::Texture: return resources.texture;
case StagingBufferType::Vertex: return resources.vertex;
case StagingBufferType::ReadBack: return resources.readback;
default: EXIT("unknown staging buffer type\n");
}
return nullptr;
return resources.texture;
}
void ReleaseCachedResources(GraphicContext* ctx) {
EXIT_IF(ctx == nullptr);
GpuTileRelease(ctx);
g_texture_staging_buffer.Release(ctx);
g_vertex_staging_buffer.Release(ctx);
g_readback_staging_buffer.Release(ctx);
void ReleaseCachedResources() {
GpuTileRelease();
Common::LockGuard lock(g_resources_mutex);
if (g_resources) {
g_resources->texture.Release();
g_resources->vertex.Release();
g_resources->readback.Release();
}
}
void UploadTiledImage(GraphicContext* ctx, VulkanImage* dst_image, const void* tiled_data,
uint64_t tiled_size, uint64_t linear_size, std::span<const GpuTileInfo> infos,
void UploadTiledImage(VulkanImage& dst_image, const void* tiled_data, uint64_t tiled_size,
uint64_t linear_size, std::span<const GpuTileInfo> infos,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
EXIT_IF(ctx == nullptr || dst_image == nullptr || tiled_data == nullptr || regions.empty());
GpuDetile(ctx, tiled_data, nullptr, tiled_size, linear_size, infos,
[&](CommandBuffer* command, VulkanBuffer* linear) {
EXIT_IF(tiled_data == nullptr || regions.empty());
GpuDetile(tiled_data, nullptr, tiled_size, linear_size, infos,
[&](CommandBuffer& command, VulkanBuffer& linear) {
vk::ImageAspectFlags aspects {};
for (const auto& region: regions) {
aspects |= GetTransferAspects(*dst_image, region.aspect);
aspects |= GetTransferAspects(dst_image, region.aspect);
}
RecordBufferToImageCopy(*command, *linear, *dst_image,
RecordBufferToImageCopy(command, linear, dst_image,
ConvertBufferImageCopies(regions), aspects,
dst_image->layout, dst_layout);
dst_image.layout, dst_layout);
});
}
void DownloadTiledImage(GraphicContext* ctx, void* tiled_data, uint64_t tiled_size,
uint64_t linear_size, std::span<const GpuTileInfo> infos,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
void DownloadTiledImage(void* tiled_data, uint64_t tiled_size, uint64_t linear_size,
std::span<const GpuTileInfo> infos,
std::span<const ImageBufferCopy> regions, VulkanImage& src_image,
vk::ImageLayout src_layout) {
EXIT_IF(ctx == nullptr || tiled_data == nullptr || src_image == nullptr || regions.empty());
GpuTile(ctx, nullptr, tiled_data, tiled_size, linear_size, infos,
[&](CommandBuffer* command, VulkanBuffer* linear) {
RecordImageToBuffer(*command, *src_image, *linear, regions, src_layout,
EXIT_IF(tiled_data == nullptr || regions.empty());
GpuTile(nullptr, tiled_data, tiled_size, linear_size, infos,
[&](CommandBuffer& command, VulkanBuffer& linear) {
RecordImageToBuffer(command, src_image, linear, regions, src_layout,
vk::AccessFlagBits::eShaderRead,
vk::PipelineStageFlagBits::eComputeShader);
});
}
static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level,
static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage& dst_image, uint32_t base_level,
uint32_t levels, vk::ImageAspectFlags aspect_mask,
vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout) {
if ((old_image_layout == vk::ImageLayout::eTransferDstOptimal &&
@@ -568,14 +581,14 @@ static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uin
if (log_count.fetch_add(1, std::memory_order_relaxed) < 64) {
LOGF("set_image_layout: image=%p type=%d tracked=%d requested=%d->%d base=%u "
"levels=%u\n",
VulkanHandleToPointer(dst_image->image), static_cast<int>(dst_image->type),
static_cast<int>(dst_image->layout), static_cast<int>(old_image_layout),
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>(new_image_layout), base_level, levels);
}
}
if (old_image_layout == new_image_layout) {
dst_image->layout = new_image_layout;
dst_image.layout = new_image_layout;
return;
}
@@ -588,12 +601,12 @@ static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uin
image_memory_barrier.newLayout = new_image_layout;
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = dst_image->image;
image_memory_barrier.image = dst_image.image;
image_memory_barrier.subresourceRange.aspectMask = aspect_mask;
image_memory_barrier.subresourceRange.baseMipLevel = base_level;
image_memory_barrier.subresourceRange.levelCount = levels;
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = dst_image->layers;
image_memory_barrier.subresourceRange.layerCount = dst_image.layers;
switch (old_image_layout) {
case vk::ImageLayout::eColorAttachmentOptimal:
@@ -663,7 +676,7 @@ static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uin
buffer.pipelineBarrier(src_stages, dest_stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr,
1, &image_memory_barrier);
dst_image->layout = new_image_layout;
dst_image.layout = new_image_layout;
}
static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r,
@@ -674,7 +687,7 @@ static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r,
return 0;
}
auto src_texel_size = GetFormatTexelSize(r.src_image->format);
auto src_texel_size = GetFormatTexelSize(r.src_image.format);
auto dst_block_size = BlockCompressedBytesPerBlock(dst_image.format);
if (src_texel_size == 0 || src_texel_size != dst_block_size) {
return 0;
@@ -682,16 +695,16 @@ static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r,
auto block_width = (r.width + 3u) / 4u;
auto block_height = (r.height + 3u) / 4u;
if (block_width > r.src_image->extent.width || block_height > r.src_image->extent.height) {
if (block_width > r.src_image.extent.width || block_height > r.src_image.extent.height) {
return 0;
}
return static_cast<uint64_t>(block_width) * block_height * dst_block_size;
}
static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r,
VulkanImage* dst_image, VulkanBuffer* copy_buffer) {
const auto copy_size = CompressedImageCopyBufferSize(r, *dst_image);
EXIT_IF(copy_size == 0 || copy_buffer == nullptr || copy_buffer->buffer_size < copy_size);
VulkanImage& dst_image, VulkanBuffer& copy_buffer) {
const auto copy_size = CompressedImageCopyBufferSize(r, dst_image);
EXIT_IF(copy_size == 0 || copy_buffer.buffer_size < copy_size);
const auto block_width = (r.width + 3u) / 4u;
const auto block_height = (r.height + 3u) / 4u;
@@ -700,17 +713,17 @@ static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const I
MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.src_level, r.src_layer,
{r.src_x, r.src_y, 0}, {block_width, block_height, 1});
auto src_layout = r.src_image->layout;
auto src_layout = r.src_image.layout;
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor,
src_layout, vk::ImageLayout::eTransferSrcOptimal);
SetBufferMemoryBarrier(vk_buffer, copy_buffer->buffer, 0, VK_WHOLE_SIZE,
SetBufferMemoryBarrier(vk_buffer, copy_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite,
vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer);
vk_buffer.copyImageToBuffer(r.src_image->image, vk::ImageLayout::eTransferSrcOptimal,
copy_buffer->buffer, 1, &src_region);
SetBufferMemoryBarrier(vk_buffer, copy_buffer->buffer, 0, VK_WHOLE_SIZE,
vk_buffer.copyImageToBuffer(r.src_image.image, vk::ImageLayout::eTransferSrcOptimal,
copy_buffer.buffer, 1, &src_region);
SetBufferMemoryBarrier(vk_buffer, copy_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer);
@@ -719,22 +732,22 @@ static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const I
MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.dst_level, r.dst_layer,
{r.dst_x, r.dst_y, 0}, {r.width, r.height, 1});
vk_buffer.copyBufferToImage(copy_buffer->buffer, dst_image->image,
vk_buffer.copyBufferToImage(copy_buffer.buffer, dst_image.image,
vk::ImageLayout::eTransferDstOptimal, 1, &dst_region);
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eTransferSrcOptimal, src_layout);
}
void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) {
auto vk_buffer = buffer->Handle();
void CopyImage(CommandBuffer& buffer, std::span<const ImageImageCopy> regions,
VulkanImage& dst_image, vk::ImageLayout dst_layout) {
auto vk_buffer = buffer.Handle();
bool same_image_copy = false;
vk::ImageAspectFlags dst_transition_aspects = {};
for (const auto& r: regions) {
dst_transition_aspects |= GetTransferAspects(*dst_image, r.dst_aspect);
if (r.src_image == dst_image) {
dst_transition_aspects |= GetTransferAspects(dst_image, r.dst_aspect);
if (&r.src_image == &dst_image) {
same_image_copy = true;
break;
}
@@ -742,7 +755,7 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
if (same_image_copy) {
SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects,
dst_image->layout, vk::ImageLayout::eGeneral);
dst_image.layout, vk::ImageLayout::eGeneral);
for (const auto& r: regions) {
vk::ImageCopy region;
@@ -761,20 +774,20 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
auto src_layout = vk::ImageLayout::eGeneral;
auto restore_layout = vk::ImageLayout::eGeneral;
if (r.src_image != dst_image) {
restore_layout = r.src_image->layout;
if (&r.src_image != &dst_image) {
restore_layout = r.src_image.layout;
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1,
GetTransferAspects(*r.src_image, r.src_aspect), restore_layout,
GetTransferAspects(r.src_image, r.src_aspect), restore_layout,
vk::ImageLayout::eTransferSrcOptimal);
src_layout = vk::ImageLayout::eTransferSrcOptimal;
}
vk_buffer.copyImage(r.src_image->image, src_layout, dst_image->image,
vk_buffer.copyImage(r.src_image.image, src_layout, dst_image.image,
vk::ImageLayout::eGeneral, 1, &region);
if (r.src_image != dst_image) {
if (&r.src_image != &dst_image) {
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1,
GetTransferAspects(*r.src_image, r.src_aspect),
GetTransferAspects(r.src_image, r.src_aspect),
vk::ImageLayout::eTransferSrcOptimal, restore_layout);
}
}
@@ -785,11 +798,11 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
}
SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects,
dst_image->layout, vk::ImageLayout::eTransferDstOptimal);
dst_image.layout, vk::ImageLayout::eTransferDstOptimal);
uint64_t compressed_copy_size = 0;
for (const auto& r: regions) {
compressed_copy_size =
std::max(compressed_copy_size, CompressedImageCopyBufferSize(r, *dst_image));
std::max(compressed_copy_size, CompressedImageCopyBufferSize(r, dst_image));
}
VulkanBuffer* compressed_copy_buffer = nullptr;
if (compressed_copy_size != 0) {
@@ -797,17 +810,17 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
compressed_copy_buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
compressed_copy_buffer->memory.property = {};
VulkanCreateBuffer(WindowGetGraphicContext(), compressed_copy_size, compressed_copy_buffer);
buffer->DeleteAfterFence(compressed_copy_buffer);
buffer.GetGraphics().CreateBuffer(compressed_copy_size, *compressed_copy_buffer);
buffer.DeleteAfterFence(*compressed_copy_buffer);
}
for (const auto& r: regions) {
vk::ImageCopy region;
auto src_layout = r.src_image->layout;
auto src_layout = r.src_image.layout;
if (CompressedImageCopyBufferSize(r, *dst_image) != 0) {
CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, compressed_copy_buffer);
if (CompressedImageCopyBufferSize(r, dst_image) != 0) {
CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, *compressed_copy_buffer);
continue;
}
@@ -824,14 +837,14 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
region.extent = {r.width, r.height, 1};
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1,
GetTransferAspects(*r.src_image, r.src_aspect), src_layout,
GetTransferAspects(r.src_image, r.src_aspect), src_layout,
vk::ImageLayout::eTransferSrcOptimal);
vk_buffer.copyImage(r.src_image->image, vk::ImageLayout::eTransferSrcOptimal,
dst_image->image, vk::ImageLayout::eTransferDstOptimal, 1, &region);
vk_buffer.copyImage(r.src_image.image, vk::ImageLayout::eTransferSrcOptimal,
dst_image.image, vk::ImageLayout::eTransferDstOptimal, 1, &region);
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1,
GetTransferAspects(*r.src_image, r.src_aspect),
GetTransferAspects(r.src_image, r.src_aspect),
vk::ImageLayout::eTransferSrcOptimal, src_layout);
}
@@ -839,59 +852,60 @@ void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
vk::ImageLayout::eTransferDstOptimal, dst_layout);
}
void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
void CopyImageViaBuffer(CommandBuffer& buffer, VulkanImage& src_image,
vk::ImageAspectFlags src_aspect, VulkanImage& dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout) {
if (!IsSingleImageAspect(src_aspect) || !IsSingleImageAspect(dst_aspect) ||
(bytes_per_element != 2 && bytes_per_element != 4) || src_image->layers != 1 ||
dst_image->layers != 1 || src_image->mip_levels != 1 || dst_image->mip_levels != 1 ||
src_image->extent.width == 0 || src_image->extent.height == 0 ||
src_image->extent.width != dst_image->extent.width ||
src_image->extent.height != dst_image->extent.height) {
(bytes_per_element != 2 && bytes_per_element != 4) || src_image.layers != 1 ||
dst_image.layers != 1 || src_image.mip_levels != 1 || dst_image.mip_levels != 1 ||
src_image.extent.width == 0 || src_image.extent.height == 0 ||
src_image.extent.width != dst_image.extent.width ||
src_image.extent.height != dst_image.extent.height) {
EXIT("unsupported image-buffer-image copy, src_aspect=0x%x dst_aspect=0x%x bpe=%u "
"src=%ux%u/%u/%u dst=%ux%u/%u/%u\n",
static_cast<vk::ImageAspectFlags::MaskType>(src_aspect),
static_cast<vk::ImageAspectFlags::MaskType>(dst_aspect), bytes_per_element,
src_image->extent.width, src_image->extent.height, src_image->layers,
src_image->mip_levels, dst_image->extent.width, dst_image->extent.height,
dst_image->layers, dst_image->mip_levels);
src_image.extent.width, src_image.extent.height, src_image.layers,
src_image.mip_levels, dst_image.extent.width, dst_image.extent.height,
dst_image.layers, dst_image.mip_levels);
}
const uint64_t row_bytes = static_cast<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;
if (row_bytes == 0 || row_bytes > MAX_COPY_BUFFER_SIZE) {
EXIT("unsupported image-buffer-image row size: 0x%016" PRIx64 "\n", row_bytes);
}
const auto rows_per_chunk = static_cast<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;
// Kyty does not yet have a cross-queue scheduler. Drain submitted work once before
// recording the recreate copy; commands already recorded on this buffer remain ordered by the
// barriers below. The preservation policy stays isolated here so a future scheduler can replace
// this synchronization without changing texture-cache ownership logic.
WaitForGraphicsIdle(ctx);
auto& graphics = buffer.GetGraphics();
WaitForGraphicsIdle();
auto* copy_buffer = new VulkanBuffer;
copy_buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
copy_buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
VulkanCreateBuffer(ctx, copy_buffer_size, copy_buffer);
buffer->DeleteAfterFence(copy_buffer);
graphics.CreateBuffer(copy_buffer_size, *copy_buffer);
buffer.DeleteAfterFence(*copy_buffer);
auto vk_buffer = buffer->Handle();
const auto src_layout = src_image->layout;
auto vk_buffer = buffer.Handle();
const auto src_layout = src_image.layout;
const auto final_layout = dst_layout;
SetImageLayout(vk_buffer, src_image, 0, 1, src_aspect, src_layout,
vk::ImageLayout::eTransferSrcOptimal);
SetImageLayout(vk_buffer, dst_image, 0, 1, dst_aspect, dst_image->layout,
SetImageLayout(vk_buffer, dst_image, 0, 1, dst_aspect, dst_image.layout,
vk::ImageLayout::eTransferDstOptimal);
for (uint32_t row = 0; row < src_image->extent.height; row += rows_per_chunk) {
const auto rows = std::min(rows_per_chunk, src_image->extent.height - row);
for (uint32_t row = 0; row < src_image.extent.height; row += rows_per_chunk) {
const auto rows = std::min(rows_per_chunk, src_image.extent.height - row);
auto copy = MakeBufferImageCopy(0, 0, src_aspect, 0, 0, {0, static_cast<int32_t>(row), 0},
{src_image->extent.width, rows, 1});
vk_buffer.copyImageToBuffer(src_image->image, vk::ImageLayout::eTransferSrcOptimal,
{src_image.extent.width, rows, 1});
vk_buffer.copyImageToBuffer(src_image.image, vk::ImageLayout::eTransferSrcOptimal,
copy_buffer->buffer, 1, &copy);
SetBufferMemoryBarrier(
@@ -900,9 +914,9 @@ void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage*
vk::PipelineStageFlagBits::eTransfer);
copy.imageSubresource.aspectMask = dst_aspect;
vk_buffer.copyBufferToImage(copy_buffer->buffer, dst_image->image,
vk_buffer.copyBufferToImage(copy_buffer->buffer, dst_image.image,
vk::ImageLayout::eTransferDstOptimal, 1, &copy);
if (row + rows < src_image->extent.height) {
if (row + rows < src_image.extent.height) {
SetBufferMemoryBarrier(
vk_buffer, copy_buffer->buffer, 0, copy_buffer_size,
vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite,
@@ -916,22 +930,20 @@ void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage*
final_layout);
}
void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image,
VulkanSwapchain* dst_swapchain) {
auto vk_buffer = buffer->Handle();
if (src_image->layout != vk::ImageLayout::eTransferSrcOptimal) {
EXIT("invalid prepared presentation image, image=%p vk_image=%p layout=%d\n",
static_cast<const void*>(src_image),
src_image != nullptr ? static_cast<void*>(src_image->image) : nullptr,
src_image != nullptr ? static_cast<int>(src_image->layout) : -1);
void BlitToSwapchain(CommandBuffer& buffer, VulkanImage& src_image,
VulkanSwapchain& dst_swapchain) {
auto vk_buffer = buffer.Handle();
if (src_image.layout != vk::ImageLayout::eTransferSrcOptimal) {
EXIT("invalid prepared presentation image, vk_image=%p layout=%d\n",
static_cast<void*>(src_image.image), static_cast<int>(src_image.layout));
}
VulkanImage swapchain_image(VulkanImageType::Unknown);
swapchain_image.image = dst_swapchain->swapchain_images[dst_swapchain->current_index];
swapchain_image.image = dst_swapchain.swapchain_images[dst_swapchain.current_index];
swapchain_image.layout = vk::ImageLayout::eUndefined;
SetImageLayout(vk_buffer, &swapchain_image, 0, 1, vk::ImageAspectFlagBits::eColor,
SetImageLayout(vk_buffer, swapchain_image, 0, 1, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
vk::ImageBlit region {};
@@ -942,8 +954,8 @@ void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image,
region.srcOffsets[0].x = 0;
region.srcOffsets[0].y = 0;
region.srcOffsets[0].z = 0;
region.srcOffsets[1].x = static_cast<int>(src_image->extent.width);
region.srcOffsets[1].y = static_cast<int>(src_image->extent.height);
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].z = 1;
region.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
region.dstSubresource.mipLevel = 0;
@@ -952,135 +964,132 @@ void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image,
region.dstOffsets[0].x = 0;
region.dstOffsets[0].y = 0;
region.dstOffsets[0].z = 0;
region.dstOffsets[1].x = static_cast<int>(dst_swapchain->swapchain_extent.width);
region.dstOffsets[1].y = static_cast<int>(dst_swapchain->swapchain_extent.height);
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].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,
vk::Filter::eLinear);
}
void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color) {
auto vk_buffer = buffer->Handle();
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image->layout,
void ClearColorImage(CommandBuffer& buffer, VulkanImage& image, const vk::ClearColorValue& color) {
auto vk_buffer = buffer.Handle();
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image.layout,
vk::ImageLayout::eTransferDstOptimal);
const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
vk_buffer.clearColorImage(image->image, vk::ImageLayout::eTransferDstOptimal, &color, 1,
&range);
vk_buffer.clearColorImage(image.image, vk::ImageLayout::eTransferDstOptimal, &color, 1, &range);
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal);
}
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout) {
void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size, uint32_t src_pitch,
vk::ImageLayout dst_layout) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0);
GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, dst_image, src_data, size, src_pitch, vk::ImageAspectFlagBits::eColor,
.UploadToImage(dst_image, src_data, size, src_pitch, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eUndefined, dst_layout);
}
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect) {
void DownloadImage(void* dst_data, uint64_t size, uint32_t dst_pitch, VulkanImage& src_image,
vk::ImageLayout src_layout, vk::ImageAspectFlags aspect) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0);
GetStagingBuffer(StagingBufferType::ReadBack)
->DownloadFromImage(ctx, dst_data, size, dst_pitch, src_image, src_layout, aspect);
.DownloadFromImage(dst_data, size, dst_pitch, src_image, src_layout, aspect);
}
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout) {
void DownloadImage(void* dst_data, uint64_t size, std::span<const ImageBufferCopy> regions,
VulkanImage& src_image, vk::ImageLayout src_layout) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0 || regions.empty());
GetStagingBuffer(StagingBufferType::ReadBack)
->DownloadFromImage(ctx, dst_data, size, regions, src_image, src_layout);
.DownloadFromImage(dst_data, size, regions, src_image, src_layout);
}
void ProcessDownloadedImage(GraphicContext* ctx, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout, const DownloadedImageConsumer& consumer) {
void ProcessDownloadedImage(uint64_t size, std::span<const ImageBufferCopy> regions,
VulkanImage& src_image, vk::ImageLayout src_layout,
const DownloadedImageConsumer& consumer) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0 || regions.empty() || !consumer);
GetStagingBuffer(StagingBufferType::ReadBack)
->ProcessDownloadedImage(ctx, size, regions, src_image, src_layout, consumer);
.ProcessDownloadedImage(size, regions, src_image, src_layout, consumer);
}
void UploadImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size,
void UploadImage(VulkanImage& image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
EXIT_IF(size == 0 || regions.empty());
GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, image, src_data, size, regions, dst_layout);
.UploadToImage(image, src_data, size, regions, dst_layout);
}
void CopyImageImmediate(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) {
ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
void CopyImageImmediate(std::span<const ImageImageCopy> regions, VulkanImage& dst_image,
vk::ImageLayout dst_layout) {
ExecuteImmediateCommands([&](CommandBuffer& command, vk::CommandBuffer) {
CopyImage(command, regions, dst_image, dst_layout);
});
}
void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) {
void UploadImage(DepthStencilVulkanImage& image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageAspectFlags aspect) {
EXIT_IF(size == 0);
GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, image, src_data, size, src_pitch, aspect, image->layout,
.UploadToImage(image, src_data, size, src_pitch, aspect, image.layout,
vk::ImageLayout::eDepthStencilAttachmentOptimal);
}
void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size) {
void UploadBuffer(StagingBufferType type, VulkanBuffer& dst_buffer, uint64_t dst_offset,
const void* src_data, uint64_t size) {
EXIT_IF(size == 0);
EXIT_IF(dst_offset > dst_buffer->buffer_size || size > dst_buffer->buffer_size - dst_offset);
GetStagingBuffer(type)->UploadToBuffer(ctx, dst_buffer, src_data, size, dst_offset);
EXIT_IF(dst_offset > dst_buffer.buffer_size || size > dst_buffer.buffer_size - dst_offset);
GetStagingBuffer(type).UploadToBuffer(dst_buffer, src_data, size, dst_offset);
}
void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size) {
EXIT_IF(size == 0 || size > src_buffer->buffer_size || size > dst_buffer->buffer_size);
void CopyBuffer(VulkanBuffer& src_buffer, VulkanBuffer& dst_buffer, uint64_t size) {
EXIT_IF(size == 0 || size > src_buffer.buffer_size || size > dst_buffer.buffer_size);
ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer->buffer, 0, size,
ExecuteImmediateCommands([&](CommandBuffer&, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer.buffer, 0, size,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer);
SetBufferMemoryBarrier(vk_command, dst_buffer->buffer, 0, size,
SetBufferMemoryBarrier(vk_command, dst_buffer.buffer, 0, size,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::AccessFlagBits::eTransferWrite,
vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer);
const vk::BufferCopy copy_region {.srcOffset = 0, .dstOffset = 0, .size = size};
vk_command.copyBuffer(src_buffer->buffer, dst_buffer->buffer, 1, &copy_region);
vk_command.copyBuffer(src_buffer.buffer, dst_buffer.buffer, 1, &copy_region);
SetBufferMemoryBarrier(
vk_command, dst_buffer->buffer, 0, size, vk::AccessFlagBits::eTransferWrite,
vk_command, dst_buffer.buffer, 0, size, vk::AccessFlagBits::eTransferWrite,
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands);
});
}
void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size) {
void DownloadBuffer(VulkanBuffer& src_buffer, uint64_t src_offset, void* dst_data, uint64_t size) {
auto& graphics = GetRenderContext().GetGraphics();
EXIT_IF(size == 0);
EXIT_IF(src_offset > src_buffer->buffer_size || size > src_buffer->buffer_size - src_offset);
const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family;
EXIT_IF(src_offset > src_buffer.buffer_size || size > src_buffer.buffer_size - src_offset);
const auto family = graphics.queues[GraphicContext::QUEUE_UTIL].family;
EXIT_IF(family == static_cast<uint32_t>(-1));
for (int i = GraphicContext::QUEUE_COMPUTE_START;
i < GraphicContext::QUEUE_COMPUTE_START + GraphicContext::QUEUE_COMPUTE_NUM; i++) {
EXIT_IF(ctx->queues[i].family != family);
EXIT_IF(graphics.queues[i].family != family);
}
EXIT_IF(ctx->queues[GraphicContext::QUEUE_GFX].family != family);
EXIT_IF(graphics.queues[GraphicContext::QUEUE_GFX].family != family);
if (src_buffer->memory.property & vk::MemoryPropertyFlagBits::eHostVisible) {
if (src_buffer.memory.property & vk::MemoryPropertyFlagBits::eHostVisible) {
void* mapped = nullptr;
VulkanMapMemory(ctx, &src_buffer->memory, &mapped);
graphics.MapMemory(src_buffer.memory, mapped);
std::memcpy(dst_data, static_cast<const uint8_t*>(mapped) + src_offset, size);
VulkanUnmapMemory(ctx, &src_buffer->memory);
graphics.UnmapMemory(src_buffer.memory);
return;
}
@@ -1089,15 +1098,15 @@ void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_
readback.memory.property = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, size, &readback);
graphics.CreateBuffer(size, readback);
ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer->buffer, src_offset, size,
ExecuteImmediateCommands([&](CommandBuffer&, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer.buffer, src_offset, size,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer);
const vk::BufferCopy copy {.srcOffset = src_offset, .dstOffset = 0, .size = size};
vk_command.copyBuffer(src_buffer->buffer, readback.buffer, 1, &copy);
vk_command.copyBuffer(src_buffer.buffer, readback.buffer, 1, &copy);
SetBufferMemoryBarrier(vk_command, readback.buffer, 0, size,
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eHostRead,
vk::PipelineStageFlagBits::eTransfer,
@@ -1105,10 +1114,10 @@ void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_
});
void* mapped = nullptr;
VulkanMapMemory(ctx, &readback.memory, &mapped);
graphics.MapMemory(readback.memory, mapped);
std::memcpy(dst_data, mapped, size);
VulkanUnmapMemory(ctx, &readback.memory);
VulkanDeleteBuffer(ctx, &readback);
graphics.UnmapMemory(readback.memory);
graphics.DeleteBuffer(readback);
}
} // namespace Libs::Graphics::Transfer
+34 -34
View File
@@ -49,7 +49,9 @@ struct ImageBufferCopy {
};
struct ImageImageCopy {
VulkanImage* src_image;
explicit ImageImageCopy(VulkanImage& source): src_image(source) {}
VulkanImage& src_image;
uint32_t src_level;
uint32_t dst_level;
uint32_t width;
@@ -89,52 +91,50 @@ private:
void* m_data = nullptr;
};
void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
void CopyImage(CommandBuffer& buffer, std::span<const ImageImageCopy> regions,
VulkanImage& dst_image, vk::ImageLayout dst_layout);
void CopyImageViaBuffer(CommandBuffer& buffer, VulkanImage& src_image,
vk::ImageAspectFlags src_aspect, VulkanImage& dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout);
void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchain* dst_swapchain);
void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color);
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout);
void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* dst_image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect);
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
void BlitToSwapchain(CommandBuffer& buffer, VulkanImage& src_image, VulkanSwapchain& dst_swapchain);
void ClearColorImage(CommandBuffer& buffer, VulkanImage& image, const vk::ClearColorValue& color);
void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size, uint32_t src_pitch,
vk::ImageLayout dst_layout);
void UploadImage(DepthStencilVulkanImage& dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageAspectFlags aspect);
void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout);
void UploadTiledImage(GraphicContext* ctx, VulkanImage* dst_image, const void* tiled_data,
uint64_t tiled_size, uint64_t linear_size, std::span<const GpuTileInfo> infos,
void UploadTiledImage(VulkanImage& dst_image, const void* tiled_data, uint64_t tiled_size,
uint64_t linear_size, std::span<const GpuTileInfo> infos,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout);
void CopyImageImmediate(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
void CopyImageImmediate(std::span<const ImageImageCopy> regions, VulkanImage& dst_image,
vk::ImageLayout dst_layout);
void DownloadImage(void* dst_data, uint64_t size, uint32_t dst_pitch, VulkanImage& src_image,
vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout);
void DownloadImage(void* dst_data, uint64_t size, std::span<const ImageBufferCopy> regions,
VulkanImage& src_image, vk::ImageLayout src_layout);
// Invokes consumer synchronously after the image copy fence while the readback staging buffer is
// reserved. The supplied span is valid only for the call; the consumer must not retain it or
// re-enter Transfer.
void ProcessDownloadedImage(GraphicContext* ctx, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout, const DownloadedImageConsumer& consumer);
void DownloadTiledImage(GraphicContext* ctx, void* tiled_data, uint64_t tiled_size,
uint64_t linear_size, std::span<const GpuTileInfo> infos,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
void ProcessDownloadedImage(uint64_t size, std::span<const ImageBufferCopy> regions,
VulkanImage& src_image, vk::ImageLayout src_layout,
const DownloadedImageConsumer& consumer);
void DownloadTiledImage(void* tiled_data, uint64_t tiled_size, uint64_t linear_size,
std::span<const GpuTileInfo> infos,
std::span<const ImageBufferCopy> regions, VulkanImage& src_image,
vk::ImageLayout src_layout);
void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size);
void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size);
void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size);
void ReleaseCachedResources(GraphicContext* ctx);
void UploadBuffer(StagingBufferType type, VulkanBuffer& dst_buffer, uint64_t dst_offset,
const void* src_data, uint64_t size);
void CopyBuffer(VulkanBuffer& src_buffer, VulkanBuffer& dst_buffer, uint64_t size);
void DownloadBuffer(VulkanBuffer& src_buffer, uint64_t src_offset, void* dst_data, uint64_t size);
void ReleaseCachedResources();
bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size);
bool IsBlockCompressedFormat(vk::Format format);
uint32_t BlockCompressedBytesPerBlock(vk::Format format);
void WaitForGraphicsIdle(GraphicContext* ctx);
void WaitForGraphicsIdle();
inline std::pair<int, int> MipmapAtlasOffset(uint32_t lod, uint32_t width, uint32_t height) {
uint32_t mip_width = width;
+69 -76
View File
@@ -48,34 +48,32 @@ void UntrackAllocationImpl(const VulkanMemory& memory) {
} // namespace
void VulkanTrackAllocation(const VulkanMemory* memory) {
EXIT_IF(memory == nullptr);
TrackAllocationImpl(*memory);
void VulkanTrackAllocation(const VulkanMemory& memory) {
TrackAllocationImpl(memory);
}
void VulkanUntrackAllocation(const VulkanMemory* memory) {
EXIT_IF(memory == nullptr);
UntrackAllocationImpl(*memory);
void VulkanUntrackAllocation(const VulkanMemory& memory) {
UntrackAllocationImpl(memory);
}
bool VulkanCreateAllocator(GraphicContext* ctx) {
bool GraphicContext::CreateAllocator() {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->instance == nullptr || ctx->physical_device == nullptr ||
ctx->device == nullptr || ctx->allocator != nullptr);
EXIT_IF(instance == nullptr || physical_device == nullptr || device == nullptr ||
allocator != nullptr);
VmaVulkanFunctions functions {};
functions.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr;
functions.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr;
VmaAllocatorCreateInfo info {};
info.instance = ctx->instance;
info.physicalDevice = ctx->physical_device;
info.device = ctx->device;
info.instance = instance;
info.physicalDevice = physical_device;
info.device = device;
info.pVulkanFunctions = &functions;
info.vulkanApiVersion = VULKAN_TARGET_API_VERSION;
info.flags = ctx->memory_budget_ext_enabled ? VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT : 0;
info.flags = memory_budget_ext_enabled ? VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT : 0;
const auto result = static_cast<vk::Result>(vmaCreateAllocator(&info, &ctx->allocator));
const auto result = static_cast<vk::Result>(vmaCreateAllocator(&info, &allocator));
if (result != vk::Result::eSuccess) {
LOGF("vmaCreateAllocator failed: %s\n", VulkanToString(result).c_str());
return false;
@@ -83,12 +81,12 @@ bool VulkanCreateAllocator(GraphicContext* ctx) {
return true;
}
void VulkanDestroyAllocator(GraphicContext* ctx) {
if (ctx == nullptr || ctx->allocator == nullptr) {
void GraphicContext::DestroyAllocator() {
if (allocator == nullptr) {
return;
}
vmaDestroyAllocator(ctx->allocator);
ctx->allocator = nullptr;
vmaDestroyAllocator(allocator);
allocator = nullptr;
}
uint64_t VulkanNextMemoryUniqueId() {
@@ -96,14 +94,14 @@ uint64_t VulkanNextMemoryUniqueId() {
return ++sequence;
}
void VulkanLogMemoryBudget(GraphicContext* ctx) {
if (ctx == nullptr || ctx->allocator == nullptr || ctx->physical_device == nullptr) {
void GraphicContext::LogMemoryBudget() const {
if (allocator == nullptr || physical_device == nullptr) {
return;
}
const auto& properties = ctx->GetPhysicalDeviceMemoryProperties();
const auto& properties = GetPhysicalDeviceMemoryProperties();
VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {};
vmaGetHeapBudgets(ctx->allocator, budgets);
vmaGetHeapBudgets(allocator, budgets);
for (uint32_t i = 0; i < properties.memoryHeapCount; i++) {
LOGF("VMA heap %u: usage=%" PRIu64 ", budget=%" PRIu64 ", allocation=%" PRIu64
", blocks=%" PRIu64 "\n",
@@ -113,115 +111,110 @@ void VulkanLogMemoryBudget(GraphicContext* ctx) {
}
}
void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer) {
void GraphicContext::CreateBuffer(uint64_t size, VulkanBuffer& buffer) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr ||
buffer->buffer != nullptr || buffer->memory.allocation != nullptr || size == 0);
EXIT_IF(allocator == nullptr || buffer.buffer != nullptr ||
buffer.memory.allocation != nullptr || size == 0);
vk::BufferCreateInfo buffer_info {};
buffer_info.sType = vk::StructureType::eBufferCreateInfo;
buffer_info.size = size;
buffer_info.usage = buffer->usage;
buffer_info.usage = buffer.usage;
buffer_info.sharingMode = vk::SharingMode::eExclusive;
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(buffer->memory.property);
static_cast<vk::MemoryPropertyFlags::MaskType>(buffer.memory.property);
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;
const auto result = static_cast<vk::Result>(vmaCreateBuffer(
ctx->allocator, static_cast<const vk::BufferCreateInfo::NativeType*>(buffer_info),
&alloc_info, &native_buffer, &buffer->memory.allocation, &buffer->memory.allocation_info));
buffer->buffer = native_buffer;
allocator, static_cast<const vk::BufferCreateInfo::NativeType*>(buffer_info), &alloc_info,
&native_buffer, &buffer.memory.allocation, &buffer.memory.allocation_info));
buffer.buffer = native_buffer;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(ctx);
LogMemoryBudget();
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
ctx->device.getBufferMemoryRequirements(buffer->buffer, &buffer->memory.requirements);
buffer->memory.type = buffer->memory.allocation_info.memoryType;
buffer->memory.memory = buffer->memory.allocation_info.deviceMemory;
buffer->memory.offset = buffer->memory.allocation_info.offset;
buffer->memory.unique_id = VulkanNextMemoryUniqueId();
buffer->buffer_size = size;
VulkanTrackAllocation(&buffer->memory);
device.getBufferMemoryRequirements(buffer.buffer, &buffer.memory.requirements);
buffer.memory.type = buffer.memory.allocation_info.memoryType;
buffer.memory.memory = buffer.memory.allocation_info.deviceMemory;
buffer.memory.offset = buffer.memory.allocation_info.offset;
buffer.memory.unique_id = VulkanNextMemoryUniqueId();
buffer.buffer_size = size;
VulkanTrackAllocation(buffer.memory);
}
void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer) {
void GraphicContext::DeleteBuffer(VulkanBuffer& buffer) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr ||
buffer->buffer == nullptr || buffer->memory.allocation == nullptr);
EXIT_IF(allocator == nullptr || buffer.buffer == nullptr ||
buffer.memory.allocation == nullptr);
VulkanUntrackAllocation(&buffer->memory);
vmaDestroyBuffer(ctx->allocator, buffer->buffer, buffer->memory.allocation);
buffer->buffer = nullptr;
buffer->memory.memory = nullptr;
buffer->memory.allocation = nullptr;
buffer->memory.allocation_info = {};
buffer->memory.offset = 0;
VulkanUntrackAllocation(buffer.memory);
vmaDestroyBuffer(allocator, buffer.buffer, buffer.memory.allocation);
buffer.buffer = nullptr;
buffer.memory.memory = nullptr;
buffer.memory.allocation = nullptr;
buffer.memory.allocation_info = {};
buffer.memory.offset = 0;
}
bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info,
VulkanImage* image) {
bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanImage& image) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr ||
image->image != nullptr || image->memory.allocation != nullptr);
EXIT_IF(allocator == nullptr || image.image != nullptr || image.memory.allocation != nullptr);
auto& memory = image->memory;
auto& memory = image.memory;
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory.property);
alloc_info.preferredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(memory.preferred_property);
vk::Image::CType native_image = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateImage(
ctx->allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info),
const auto result = static_cast<vk::Result>(
vmaCreateImage(allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info),
&alloc_info, &native_image, &memory.allocation, &memory.allocation_info));
image->image = native_image;
image.image = native_image;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(ctx);
LogMemoryBudget();
return false;
}
ctx->device.getImageMemoryRequirements(image->image, &memory.requirements);
device.getImageMemoryRequirements(image.image, &memory.requirements);
memory.type = memory.allocation_info.memoryType;
memory.memory = memory.allocation_info.deviceMemory;
memory.offset = memory.allocation_info.offset;
memory.unique_id = VulkanNextMemoryUniqueId();
VulkanTrackAllocation(&memory);
VulkanTrackAllocation(memory);
return true;
}
void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image) {
void GraphicContext::DeleteImage(VulkanImage& image) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr ||
image->image == nullptr || image->memory.allocation == nullptr);
EXIT_IF(allocator == nullptr || image.image == nullptr || image.memory.allocation == nullptr);
auto& memory = image->memory;
VulkanUntrackAllocation(&memory);
vmaDestroyImage(ctx->allocator, image->image, memory.allocation);
image->image = nullptr;
auto& memory = image.memory;
VulkanUntrackAllocation(memory);
vmaDestroyImage(allocator, image.image, memory.allocation);
image.image = nullptr;
memory.memory = nullptr;
memory.allocation = nullptr;
memory.allocation_info = {};
memory.offset = 0;
}
void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data) {
void GraphicContext::MapMemory(VulkanMemory& memory, void*& data) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || memory == nullptr || data == nullptr || ctx->allocator == nullptr ||
memory->allocation == nullptr);
EXIT_NOT_IMPLEMENTED(static_cast<vk::Result>(vmaMapMemory(ctx->allocator, memory->allocation,
data)) != vk::Result::eSuccess);
EXIT_IF(allocator == nullptr || memory.allocation == nullptr);
EXIT_NOT_IMPLEMENTED(static_cast<vk::Result>(vmaMapMemory(allocator, memory.allocation,
&data)) != vk::Result::eSuccess);
}
void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory) {
void GraphicContext::UnmapMemory(VulkanMemory& memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || memory == nullptr || ctx->allocator == nullptr ||
memory->allocation == nullptr);
vmaUnmapMemory(ctx->allocator, memory->allocation);
EXIT_IF(allocator == nullptr || memory.allocation == nullptr);
vmaUnmapMemory(allocator, memory.allocation);
}
} // namespace Libs::Graphics
+3 -18
View File
@@ -2,28 +2,13 @@
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_VMA_H_
#include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/host_gpu/graphicContext.h"
namespace Libs::Graphics {
struct GraphicContext;
struct VulkanBuffer;
struct VulkanImage;
struct VulkanMemory;
bool VulkanCreateAllocator(GraphicContext* ctx);
void VulkanDestroyAllocator(GraphicContext* ctx);
uint64_t VulkanNextMemoryUniqueId();
void VulkanTrackAllocation(const VulkanMemory* memory);
void VulkanUntrackAllocation(const VulkanMemory* memory);
void VulkanLogMemoryBudget(GraphicContext* ctx);
void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer);
void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer);
bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info,
VulkanImage* image);
void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image);
void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data);
void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory);
void VulkanTrackAllocation(const VulkanMemory& memory);
void VulkanUntrackAllocation(const VulkanMemory& memory);
} // namespace Libs::Graphics
+3 -3
View File
@@ -18,9 +18,9 @@ struct DisplayBufferImage {
};
DisplayBufferImage DisplayBufferFind(uint64_t addr, bool render_target = false);
int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer* buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t* request_id);
uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer* buffer);
int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t& request_id);
uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer& buffer);
void DisplayBufferCompleteFlipFromGpu(uint64_t request_id);
void DisplayBufferWaitForFlipQueueSlot();
+67 -92
View File
@@ -172,16 +172,16 @@ public:
~FlipQueue() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FlipQueue);
bool Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRequestSource source,
uint64_t* request_id);
void Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer);
uint64_t PrepareNextCpu(Graphics::CommandBuffer* buffer);
bool Reserve(VideoOutConfig& cfg, int index, int64_t flip_arg, FlipRequestSource source,
uint64_t& request_id);
void Prepare(uint64_t request_id, Graphics::CommandBuffer& buffer);
uint64_t PrepareNextCpu(Graphics::CommandBuffer& buffer);
void Complete(uint64_t request_id);
void WaitForSubmitSlot();
bool Flip(uint32_t micros);
bool HasPending(VideoOutConfig* cfg, int start_index, int count);
void GetFlipStatus(VideoOutConfig* cfg, VideoOutFlipStatus* out);
void Wait(VideoOutConfig* cfg, int index);
bool HasPending(VideoOutConfig& cfg, int start_index, int count);
void GetFlipStatus(VideoOutConfig& cfg, VideoOutFlipStatus& out);
void Wait(VideoOutConfig& cfg, int index);
private:
enum class RequestState { Reserved, Recording, Ready, Presenting };
@@ -225,16 +225,6 @@ public:
void Init(uint32_t width, uint32_t height);
Graphics::GraphicContext* GetGraphicCtx() {
Common::LockGuard lock(m_mutex);
if (m_graphic_ctx == nullptr) {
m_graphic_ctx = Graphics::WindowGetGraphicContext();
}
return m_graphic_ctx;
}
FlipQueue& GetFlipQueue() { return m_flip_queue; }
void VblankBegin();
@@ -243,7 +233,6 @@ public:
private:
Common::Mutex m_mutex;
VideoOutConfig m_video_out_ctx[VIDEO_OUT_NUM_MAX];
Graphics::GraphicContext* m_graphic_ctx = nullptr;
FlipQueue m_flip_queue;
};
@@ -438,14 +427,12 @@ static void WaitForNextVblank() {
} while (next_vblank_ticks <= now);
}
static bool IsFlipDue(VideoOutConfig* cfg) {
EXIT_IF(cfg == nullptr);
static bool IsFlipDue(VideoOutConfig& cfg) {
Common::LockGuard lock(cfg.mutex);
Common::LockGuard lock(cfg->mutex);
const int interval = cfg.flip_rate + 1;
const int interval = cfg->flip_rate + 1;
return interval <= 1 || (cfg->vblank_status.count % static_cast<uint64_t>(interval)) == 0;
return interval <= 1 || (cfg.vblank_status.count % static_cast<uint64_t>(interval)) == 0;
}
static bool IsValidBufferIndex(int index) {
@@ -461,8 +448,8 @@ static bool IsValidFlipMode(int mode) {
}
static int ReserveFlipRequest(int handle, int index, int flip_mode, int64_t flip_arg,
FlipRequestSource source, uint64_t* request_id) {
EXIT_IF(g_video_out_context == nullptr || request_id == nullptr);
FlipRequestSource source, uint64_t& request_id) {
EXIT_IF(g_video_out_context == nullptr);
auto* video_out = g_video_out_context->Get(handle);
if (video_out == nullptr) {
@@ -481,7 +468,7 @@ static int ReserveFlipRequest(int handle, int index, int flip_mode, int64_t flip
(video_out->unregistering[index] || video_out->buffers[index].buffer_vulkan == nullptr))) {
return VIDEO_OUT_ERROR_INVALID_INDEX;
}
if (!g_video_out_context->GetFlipQueue().Reserve(video_out, index, flip_arg, source,
if (!g_video_out_context->GetFlipQueue().Reserve(*video_out, index, flip_arg, source,
request_id)) {
return VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
}
@@ -502,7 +489,7 @@ static Graphics::VideoOutInfo MakeVideoOutInfo(const VideoOutBufferAttribute2& a
EXIT("unsupported or invalid video-out surface attributes\n");
}
Graphics::VideoOutPixelFormatInfo pixel_format {};
if (!Graphics::DecodeVideoOutPixelFormat(attribute.pixel_format, &pixel_format)) {
if (!Graphics::DecodeVideoOutPixelFormat(attribute.pixel_format, pixel_format)) {
EXIT("unsupported video-out pixel format: 0x%016" PRIx64 "\n", attribute.pixel_format);
}
const auto tile_mode =
@@ -511,7 +498,7 @@ static Graphics::VideoOutInfo MakeVideoOutInfo(const VideoOutBufferAttribute2& a
Graphics::TileGetTexturePitch(pixel_format.guest_format, attribute.width, 1, tile_mode);
Graphics::TileSizeAlign total {};
Graphics::TileGetTextureTotalSize(pixel_format.guest_format, attribute.width, attribute.height,
1, pitch, 1, tile_mode, false, &total);
1, pitch, 1, tile_mode, false, total);
if (total.size == 0 || total.align != 65536 || (address & (total.align - 1u)) != 0) {
EXIT("invalid video-out surface footprint or alignment\n");
}
@@ -606,7 +593,7 @@ void VideoOutContext::Close(int handle) {
EXIT("video-out handle is already closing\n");
}
config.closing = true;
if (m_flip_queue.HasPending(&config, VIDEO_OUT_BUFFER_INDEX_BLACK,
if (m_flip_queue.HasPending(config, VIDEO_OUT_BUFFER_INDEX_BLACK,
VIDEO_OUT_BUFFER_NUM_MAX - VIDEO_OUT_BUFFER_INDEX_BLACK)) {
EXIT("cannot close video-out handle with pending flips\n");
}
@@ -629,10 +616,7 @@ void VideoOutContext::Close(int handle) {
}
}
if (!images.empty()) {
if (Graphics::g_render_ctx == nullptr) {
EXIT("cannot unregister video-out surfaces without a render context\n");
}
Graphics::g_render_ctx->GetTextureCache()->UnregisterVideoOutSurfaces(images);
Graphics::GetRenderContext().GetTextureCache().UnregisterVideoOutSurfaces(images);
}
for (auto& buffer: config.buffers) {
buffer = VideoOutBufferInfo {};
@@ -722,7 +706,7 @@ Presentation::DisplayBufferImage VideoOutContext::FindImage(const void* buffer,
ret.size = ctx.buffers[j].buffer_size;
ret.pitch = ctx.buffers[j].buffer_pitch;
ret.index = j - set.start_index;
Graphics::g_render_ctx->GetTextureCache()->RefreshVideoOut(ret.image,
Graphics::GetRenderContext().GetTextureCache().RefreshVideoOut(*ret.image,
render_target);
return ret;
}
@@ -732,9 +716,8 @@ Presentation::DisplayBufferImage VideoOutContext::FindImage(const void* buffer,
return ret;
}
bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRequestSource source,
uint64_t* request_id) {
EXIT_IF(cfg == nullptr || request_id == nullptr);
bool FlipQueue::Reserve(VideoOutConfig& cfg, int index, int64_t flip_arg, FlipRequestSource source,
uint64_t& request_id) {
Common::LockGuard lock(m_mutex);
if (m_requests.size() + m_cpu_requests.size() >= VIDEO_OUT_FLIP_QUEUE_CAPACITY) {
@@ -744,7 +727,7 @@ bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRe
Request r {};
r.id = m_next_request_id++;
r.cfg = cfg;
r.cfg = &cfg;
r.index = index;
r.flip_arg = flip_arg;
r.submit_ptc = LibKernel::KernelGetProcessTimeCounter();
@@ -752,20 +735,18 @@ bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRe
r.state = RequestState::Reserved;
pending.push_back(r);
*request_id = r.id;
request_id = r.id;
cfg->flip_status.flipPendingNum = static_cast<int>(m_requests.size() + m_cpu_requests.size());
cfg->flip_status.submitProcessTimeCounter = r.submit_ptc;
cfg.flip_status.flipPendingNum = static_cast<int>(m_requests.size() + m_cpu_requests.size());
cfg.flip_status.submitProcessTimeCounter = r.submit_ptc;
if (source == FlipRequestSource::GpuEop) {
cfg->flip_status.gcQueueNum++;
cfg.flip_status.gcQueueNum++;
}
return true;
}
void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer) {
EXIT_IF(buffer == nullptr);
void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer& buffer) {
VideoOutConfig* cfg = nullptr;
int index = 0;
{
@@ -813,9 +794,9 @@ void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer) {
}
}
}
auto* frame = special ? Graphics::WindowPrepareBlankFrame(buffer, width, height,
auto& frame = special ? Graphics::WindowPrepareBlankFrame(buffer, width, height,
index == VIDEO_OUT_BUFFER_INDEX_BLACK)
: Graphics::WindowPrepareFrame(buffer, source);
: Graphics::WindowPrepareFrame(buffer, *source);
Common::LockGuard lock(m_mutex);
auto request = std::find_if(m_requests.begin(), m_requests.end(),
@@ -824,10 +805,10 @@ void FlipQueue::Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer) {
request->frame != nullptr) {
EXIT("video-out request changed while recording, id=%" PRIu64 "\n", request_id);
}
request->frame = frame;
request->frame = &frame;
}
uint64_t FlipQueue::PrepareNextCpu(Graphics::CommandBuffer* buffer) {
uint64_t FlipQueue::PrepareNextCpu(Graphics::CommandBuffer& buffer) {
uint64_t request_id = 0;
{
Common::LockGuard lock(m_mutex);
@@ -862,11 +843,11 @@ void FlipQueue::WaitForSubmitSlot() {
}
}
void FlipQueue::Wait(VideoOutConfig* cfg, int index) {
void FlipQueue::Wait(VideoOutConfig& cfg, int index) {
Common::LockGuard lock(m_mutex);
auto has_request = [this, cfg, index] {
auto matches = [cfg, index](const auto& r) { return r.cfg == cfg && r.index == index; };
auto has_request = [this, &cfg, index] {
auto matches = [&cfg, index](const auto& r) { return r.cfg == &cfg && r.index == index; };
return std::any_of(m_requests.begin(), m_requests.end(), matches) ||
std::any_of(m_cpu_requests.begin(), m_cpu_requests.end(), matches);
};
@@ -875,13 +856,13 @@ void FlipQueue::Wait(VideoOutConfig* cfg, int index) {
}
}
bool FlipQueue::HasPending(VideoOutConfig* cfg, int start_index, int count) {
if (cfg == nullptr || count <= 0 || start_index > INT_MAX - count) {
bool FlipQueue::HasPending(VideoOutConfig& cfg, int start_index, int count) {
if (count <= 0 || start_index > INT_MAX - count) {
EXIT("invalid video-out pending-flip query range\n");
}
Common::LockGuard lock(m_mutex);
auto matches = [&](const auto& request) {
return request.cfg == cfg && request.index >= start_index &&
return request.cfg == &cfg && request.index >= start_index &&
request.index < start_index + count;
};
return std::any_of(m_requests.begin(), m_requests.end(), matches) ||
@@ -910,7 +891,7 @@ bool FlipQueue::Flip(uint32_t micros) {
m_processing = true;
auto r = m_requests.front();
m_mutex.Unlock();
if (!IsFlipDue(r.cfg)) {
if (!IsFlipDue(*r.cfg)) {
Common::LockGuard lock(m_mutex);
m_processing = false;
return false;
@@ -924,7 +905,7 @@ bool FlipQueue::Flip(uint32_t micros) {
m_requests.front().state = RequestState::Presenting;
m_mutex.Unlock();
Graphics::WindowPresentFrame(r.frame);
Graphics::WindowPresentFrame(*r.frame);
m_mutex.Lock();
if (m_requests.empty() || m_requests.front().id != r.id ||
@@ -962,13 +943,10 @@ bool FlipQueue::Flip(uint32_t micros) {
return true;
}
void FlipQueue::GetFlipStatus(VideoOutConfig* cfg, VideoOutFlipStatus* out) {
EXIT_IF(cfg == nullptr);
EXIT_IF(out == nullptr);
void FlipQueue::GetFlipStatus(VideoOutConfig& cfg, VideoOutFlipStatus& out) {
Common::LockGuard lock(m_mutex);
*out = cfg->flip_status;
out = cfg.flip_status;
}
bool VideoOutFlipWindow(uint32_t micros) {
@@ -1116,10 +1094,10 @@ KYTY_SYSV_ABI int VideoOutAddOutputModeEvent(LibKernel::EventQueue::KernelEqueue
return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::OutputMode, udata);
}
static int RegisterBuffersInternal(VideoOutConfig* ctx, int set_id, int start_index,
static int RegisterBuffersInternal(VideoOutConfig& ctx, int set_id, int start_index,
const void* const* addresses, int buffer_num,
const std::vector<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)) {
EXIT("invalid internal video-out buffer registration arguments\n");
}
@@ -1128,31 +1106,29 @@ static int RegisterBuffersInternal(VideoOutConfig* ctx, int set_id, int start_in
}
Graphics::WindowWaitForGraphicInitialized();
Graphics::GraphicsRenderCreateContext();
auto* graphic_ctx = g_video_out_context->GetGraphicCtx();
Common::LockGuard lock(ctx->mutex);
if (ctx->closing) {
Common::LockGuard lock(ctx.mutex);
if (ctx.closing) {
EXIT("cannot register buffers on a closing video-out handle\n");
}
if (std::any_of(ctx->buffers_sets.begin(), ctx->buffers_sets.end(),
if (std::any_of(ctx.buffers_sets.begin(), ctx.buffers_sets.end(),
[set_id](const auto& set) { return set.set_id == set_id; })) {
return VIDEO_OUT_ERROR_INVALID_INDEX;
}
for (int i = 0; i < buffer_num; i++) {
if (ctx->unregistering[start_index + i]) {
if (ctx.unregistering[start_index + i]) {
EXIT("video-out buffer registration raced with unregistration\n");
}
if (ctx->buffers[start_index + i].buffer != nullptr) {
if (ctx.buffers[start_index + i].buffer != nullptr) {
return VIDEO_OUT_ERROR_SLOT_OCCUPIED;
}
}
auto images =
Graphics::g_render_ctx->GetTextureCache()->RegisterVideoOutSurfaces(graphic_ctx, infos);
auto images = Graphics::GetRenderContext().GetTextureCache().RegisterVideoOutSurfaces(infos);
if (images.size() != infos.size()) {
EXIT("video-out texture cache returned an incomplete surface set\n");
}
ctx->buffers_sets.push_back({start_index, buffer_num, set_id});
ctx.buffers_sets.push_back({start_index, buffer_num, set_id});
for (int i = 0; i < buffer_num; i++) {
auto& dst = ctx->buffers[i + start_index];
auto& dst = ctx.buffers[i + start_index];
dst.set_id = set_id;
dst.buffer = addresses[i];
dst.buffer_size = infos[i].size;
@@ -1243,8 +1219,8 @@ KYTY_SYSV_ABI int VideoOutRegisterBuffers2(int handle, int set_index, int buffer
infos.push_back(MakeVideoOutInfo(*attribute, data_address, metadata_address, compression));
}
return RegisterBuffersInternal(ctx, set_index, buffer_index_start, addresses.data(), buffer_num,
infos);
return RegisterBuffersInternal(*ctx, set_index, buffer_index_start, addresses.data(),
buffer_num, infos);
}
KYTY_SYSV_ABI int VideoOutSubmitChangeBufferAttribute2(int handle, int set_index,
@@ -1309,10 +1285,10 @@ KYTY_SYSV_ABI int VideoOutUnregisterBuffers(int handle, int set_index) {
}
images.push_back(ctx->buffers[i].buffer_vulkan);
}
if (g_video_out_context->GetFlipQueue().HasPending(ctx, set_it->start_index, set_it->num)) {
if (g_video_out_context->GetFlipQueue().HasPending(*ctx, set_it->start_index, set_it->num)) {
EXIT("cannot unregister video-out buffers with pending flips\n");
}
Graphics::g_render_ctx->GetTextureCache()->UnregisterVideoOutSurfaces(images);
Graphics::GetRenderContext().GetTextureCache().UnregisterVideoOutSurfaces(images);
for (int i = set_it->start_index; i < set_it->start_index + set_it->num; i++) {
ctx->buffers[i] = VideoOutBufferInfo {};
ctx->unregistering[i] = false;
@@ -1341,7 +1317,7 @@ KYTY_SYSV_ABI int VideoOutSubmitFlip(int handle, int index, int flip_mode, int64
uint64_t request_id = 0;
const int result =
ReserveFlipRequest(handle, index, flip_mode, flip_arg, FlipRequestSource::Cpu, &request_id);
ReserveFlipRequest(handle, index, flip_mode, flip_arg, FlipRequestSource::Cpu, request_id);
if (result == VIDEO_OUT_ERROR_INVALID_VALUE) {
LOGF("\t unsupported flip_mode = %d\n", flip_mode);
}
@@ -1357,33 +1333,32 @@ KYTY_SYSV_ABI int VideoOutSubmitFlip(int handle, int index, int flip_mode, int64
namespace Libs::Presentation {
int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer* buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t* request_id) {
EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr ||
buffer == nullptr || request_id == nullptr);
int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer& buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t& request_id) {
EXIT_IF(VideoOut::g_video_out_context == nullptr || buffer.IsInvalid());
const int result = VideoOut::ReserveFlipRequest(
handle, index, flip_mode, flip_arg, VideoOut::FlipRequestSource::GpuEop, request_id);
if (result != OK) {
return result;
}
VideoOut::g_video_out_context->GetFlipQueue().Prepare(*request_id, buffer);
VideoOut::g_video_out_context->GetFlipQueue().Prepare(request_id, buffer);
return OK;
}
uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer* buffer) {
EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr);
uint64_t DisplayBufferPrepareNextFlipOnGpu(Graphics::CommandBuffer& buffer) {
EXIT_IF(VideoOut::g_video_out_context == nullptr);
return VideoOut::g_video_out_context->GetFlipQueue().PrepareNextCpu(buffer);
}
void DisplayBufferCompleteFlipFromGpu(uint64_t request_id) {
EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr);
EXIT_IF(VideoOut::g_video_out_context == nullptr);
VideoOut::g_video_out_context->GetFlipQueue().Complete(request_id);
}
void DisplayBufferWaitForFlipQueueSlot() {
EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr);
EXIT_IF(VideoOut::g_video_out_context == nullptr);
VideoOut::g_video_out_context->GetFlipQueue().WaitForSubmitSlot();
}
@@ -1398,7 +1373,7 @@ void VideoOutWaitFlipDone(int handle, int index) {
EXIT_IF(ctx == nullptr);
EXIT_NOT_IMPLEMENTED(!IsValidBufferIndex(index));
g_video_out_context->GetFlipQueue().Wait(ctx, index);
g_video_out_context->GetFlipQueue().Wait(*ctx, index);
}
KYTY_SYSV_ABI int VideoOutGetFlipStatus(int handle, VideoOutFlipStatus* status) {
@@ -1415,7 +1390,7 @@ KYTY_SYSV_ABI int VideoOutGetFlipStatus(int handle, VideoOutFlipStatus* status)
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
g_video_out_context->GetFlipQueue().GetFlipStatus(ctx, status);
g_video_out_context->GetFlipQueue().GetFlipStatus(*ctx, *status);
LOGF("\t count = %" PRIu64 "\n"
"\t processTime = %" PRIu64 "\n"
@@ -1443,7 +1418,7 @@ KYTY_SYSV_ABI int VideoOutIsFlipPending(int handle) {
}
VideoOutFlipStatus status {};
g_video_out_context->GetFlipQueue().GetFlipStatus(ctx, &status);
g_video_out_context->GetFlipQueue().GetFlipStatus(*ctx, status);
LOGF("\t flipPendingNum = %d\n", status.flipPendingNum);
+4 -4
View File
@@ -14,15 +14,15 @@ struct PreparedFrame;
vk::SurfaceCapabilitiesKHR* VulkanGetSurfaceCapabilities();
GraphicContext* WindowGetGraphicContext();
GraphicContext& WindowGetGraphicContext();
void WindowInit(uint32_t width, uint32_t height);
void WindowRun();
void WindowWaitForGraphicInitialized();
PreparedFrame* WindowPrepareFrame(CommandBuffer* buffer, VideoOutVulkanImage* image);
PreparedFrame* WindowPrepareBlankFrame(CommandBuffer* buffer, uint32_t width, uint32_t height,
PreparedFrame& WindowPrepareFrame(CommandBuffer& buffer, VideoOutVulkanImage& image);
PreparedFrame& WindowPrepareBlankFrame(CommandBuffer& buffer, uint32_t width, uint32_t height,
bool opaque);
void WindowPresentFrame(PreparedFrame* frame);
void WindowPresentFrame(PreparedFrame& frame);
} // namespace Libs::Graphics
+76 -83
View File
@@ -138,16 +138,15 @@ static PreparedFramePool* GetPreparedFramePool() {
return pool;
}
static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk::Format format) {
EXIT_IF(frame == nullptr);
static void ConfigurePreparedFrame(PreparedFrame& frame, vk::Extent2D extent, vk::Format format) {
EXIT_IF(g_window_ctx == nullptr);
if (extent.width == 0 || extent.height == 0 || format == vk::Format::eUndefined) {
EXIT("unsupported prepared frame, extent=%ux%u format=%d\n", extent.width, extent.height,
static_cast<int>(format));
}
auto* ctx = &g_window_ctx->graphic_ctx;
auto& dst = frame->image;
auto& graphics = g_window_ctx->graphic_ctx;
auto& dst = frame.image;
const bool compatible = dst.image != nullptr && dst.extent.width == extent.width &&
dst.extent.height == extent.height && dst.format == format;
if (compatible) {
@@ -155,7 +154,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk
}
if (dst.image != nullptr) {
EXIT_IF(!dst.view_cache.views.empty());
VulkanDeleteImage(ctx, &dst);
graphics.DeleteImage(dst);
dst.memory = {};
}
@@ -178,7 +177,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk
create.usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vk::SampleCountFlagBits::e1;
if (!VulkanCreateImage(ctx, create, &dst)) {
if (!graphics.CreateImage(create, dst)) {
EXIT("failed to allocate prepared presentation image, extent=%ux%u format=%d\n",
dst.extent.width, dst.extent.height, static_cast<int>(dst.format));
}
@@ -188,28 +187,22 @@ VulkanSwapchain::~VulkanSwapchain() = default;
[[maybe_unused]] static vk::SwapchainKHR VulkanCreateSwapchainInternal(
vk::Device device, vk::SurfaceKHR surface, uint32_t width, uint32_t height,
uint32_t image_count, SurfaceCapabilities* r, vk::Format* swapchain_format,
vk::Extent2D* swapchain_extent, std::unique_ptr<vk::Image[]>* swapchain_images,
std::unique_ptr<vk::ImageView[]>* swapchain_image_views, uint32_t* swapchain_images_count) {
uint32_t image_count, SurfaceCapabilities& r, vk::Format& swapchain_format,
vk::Extent2D& swapchain_extent, std::unique_ptr<vk::Image[]>& swapchain_images,
std::unique_ptr<vk::ImageView[]>& swapchain_image_views, uint32_t& swapchain_images_count) {
EXIT_IF(device == nullptr);
EXIT_IF(surface == nullptr);
EXIT_IF(r == nullptr);
EXIT_IF(swapchain_format == nullptr);
EXIT_IF(swapchain_extent == nullptr);
EXIT_IF(swapchain_images == nullptr);
EXIT_IF(swapchain_image_views == nullptr);
EXIT_IF(swapchain_images_count == nullptr);
EXIT_NOT_IMPLEMENTED(r->formats.empty());
EXIT_NOT_IMPLEMENTED(r.formats.empty());
vk::Extent2D extent {};
extent.width = std::clamp(width, r->capabilities.minImageExtent.width,
r->capabilities.maxImageExtent.width);
extent.height = std::clamp(height, r->capabilities.minImageExtent.height,
r->capabilities.maxImageExtent.height);
extent.width =
std::clamp(width, r.capabilities.minImageExtent.width, r.capabilities.maxImageExtent.width);
extent.height = std::clamp(height, r.capabilities.minImageExtent.height,
r.capabilities.maxImageExtent.height);
image_count =
std::clamp(image_count, r->capabilities.minImageCount, r->capabilities.maxImageCount);
std::clamp(image_count, r.capabilities.minImageCount, r.capabilities.maxImageCount);
vk::SwapchainCreateInfoKHR create_info {};
create_info.sType = vk::StructureType::eSwapchainCreateInfoKHR;
@@ -218,14 +211,14 @@ VulkanSwapchain::~VulkanSwapchain() = default;
create_info.surface = surface;
create_info.minImageCount = image_count;
if (r->format_unorm_bgra32) {
if (r.format_unorm_bgra32) {
create_info.imageFormat = vk::Format::eB8G8R8A8Unorm;
create_info.imageColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
} else if (r->format_srgb_bgra32) {
} else if (r.format_srgb_bgra32) {
create_info.imageFormat = vk::Format::eB8G8R8A8Srgb;
create_info.imageColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
} else {
const auto& format = r->formats[0];
const auto& format = r.formats[0];
create_info.imageFormat = format.format;
create_info.imageColorSpace = format.colorSpace;
}
@@ -237,14 +230,14 @@ VulkanSwapchain::~VulkanSwapchain() = default;
create_info.imageSharingMode = vk::SharingMode::eExclusive;
create_info.queueFamilyIndexCount = 0;
create_info.pQueueFamilyIndices = nullptr;
create_info.preTransform = r->capabilities.currentTransform;
create_info.preTransform = r.capabilities.currentTransform;
create_info.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
create_info.presentMode = vk::PresentModeKHR::eFifo;
create_info.clipped = VK_TRUE;
create_info.oldSwapchain = nullptr;
*swapchain_format = create_info.imageFormat;
*swapchain_extent = extent;
swapchain_format = create_info.imageFormat;
swapchain_extent = extent;
vk::SwapchainKHR swapchain = nullptr;
@@ -258,19 +251,19 @@ VulkanSwapchain::~VulkanSwapchain() = default;
});
EXIT_NOT_IMPLEMENTED(images.empty());
*swapchain_images_count = static_cast<uint32_t>(images.size());
*swapchain_images = std::make_unique<vk::Image[]>(images.size());
std::copy(images.begin(), images.end(), swapchain_images->get());
swapchain_images_count = static_cast<uint32_t>(images.size());
swapchain_images = std::make_unique<vk::Image[]>(images.size());
std::copy(images.begin(), images.end(), swapchain_images.get());
*swapchain_image_views = std::make_unique<vk::ImageView[]>(*swapchain_images_count);
for (uint32_t i = 0; i < *swapchain_images_count; i++) {
swapchain_image_views = std::make_unique<vk::ImageView[]>(swapchain_images_count);
for (uint32_t i = 0; i < swapchain_images_count; i++) {
vk::ImageViewCreateInfo create_info {};
create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = nullptr;
create_info.flags = {};
create_info.image = (*swapchain_images)[i];
create_info.image = (swapchain_images)[i];
create_info.viewType = vk::ImageViewType::e2D;
create_info.format = *swapchain_format;
create_info.format = swapchain_format;
create_info.components.r = vk::ComponentSwizzle::eIdentity;
create_info.components.g = vk::ComponentSwizzle::eIdentity;
create_info.components.b = vk::ComponentSwizzle::eIdentity;
@@ -282,19 +275,19 @@ VulkanSwapchain::~VulkanSwapchain() = default;
create_info.subresourceRange.levelCount = 1;
RequireVulkanSuccess(
device.createImageView(&create_info, nullptr, &((*swapchain_image_views)[i])),
device.createImageView(&create_info, nullptr, &((swapchain_image_views)[i])),
"vkCreateImageView");
EXIT_IF((*swapchain_image_views)[i] == nullptr);
EXIT_IF((swapchain_image_views)[i] == nullptr);
}
return swapchain;
}
VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count) {
VulkanSwapchain* VulkanCreateSwapchain(uint32_t image_count) {
EXIT_IF(g_window_ctx == nullptr);
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->screen_width == 0);
EXIT_IF(ctx->screen_height == 0);
auto& graphics = g_window_ctx->graphic_ctx;
EXIT_IF(graphics.screen_width == 0);
EXIT_IF(graphics.screen_height == 0);
Common::LockGuard lock(g_window_ctx->mutex);
@@ -302,9 +295,9 @@ VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count
auto* s = swapchain_owner.get();
s->swapchain = VulkanCreateSwapchainInternal(
ctx->device, g_window_ctx->surface, ctx->screen_width, ctx->screen_height, image_count,
g_window_ctx->surface_capabilities, &s->swapchain_format, &s->swapchain_extent,
&s->swapchain_images, &s->swapchain_image_views, &s->swapchain_images_count);
graphics.device, g_window_ctx->surface, graphics.screen_width, graphics.screen_height,
image_count, *g_window_ctx->surface_capabilities, s->swapchain_format, s->swapchain_extent,
s->swapchain_images, s->swapchain_image_views, s->swapchain_images_count);
if (s->swapchain == nullptr) {
EXIT("Could not create swapchain");
}
@@ -320,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->render_complete_semaphores = std::make_unique<vk::Semaphore[]>(s->swapchain_images_count);
for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
auto result =
ctx->device.createSemaphore(&semaphore_info, nullptr, &s->image_acquired_semaphores[i]);
auto result = graphics.device.createSemaphore(&semaphore_info, nullptr,
&s->image_acquired_semaphores[i]);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
result = ctx->device.createSemaphore(&semaphore_info, nullptr,
result = graphics.device.createSemaphore(&semaphore_info, nullptr,
&s->render_complete_semaphores[i]);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
}
@@ -333,38 +326,39 @@ VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count
return swapchain_owner.release();
}
static void VulkanDeleteSwapchain(GraphicContext* ctx, VulkanSwapchain* s) {
if (ctx == nullptr || s == nullptr) {
static void VulkanDeleteSwapchain(VulkanSwapchain* s) {
if (s == nullptr) {
return;
}
auto swapchain_owner = std::unique_ptr<VulkanSwapchain>(s);
auto& graphics = g_window_ctx->graphic_ctx;
Transfer::WaitForGraphicsIdle(ctx);
Transfer::WaitForGraphicsIdle();
if (s->image_acquired_semaphores != nullptr) {
for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
if (s->image_acquired_semaphores[i] != nullptr) {
ctx->device.destroySemaphore(s->image_acquired_semaphores[i], nullptr);
graphics.device.destroySemaphore(s->image_acquired_semaphores[i], nullptr);
}
}
}
if (s->render_complete_semaphores != nullptr) {
for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
if (s->render_complete_semaphores[i] != nullptr) {
ctx->device.destroySemaphore(s->render_complete_semaphores[i], nullptr);
graphics.device.destroySemaphore(s->render_complete_semaphores[i], nullptr);
}
}
}
if (s->swapchain_image_views != nullptr) {
for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
if (s->swapchain_image_views[i] != nullptr) {
ctx->device.destroyImageView(s->swapchain_image_views[i], nullptr);
graphics.device.destroyImageView(s->swapchain_image_views[i], nullptr);
}
}
}
if (s->swapchain != nullptr) {
ctx->device.destroySwapchainKHR(s->swapchain, nullptr);
graphics.device.destroySwapchainKHR(s->swapchain, nullptr);
}
}
@@ -382,7 +376,7 @@ static void VulkanRefreshSurfaceSize() {
}
VulkanGetSurfaceCapabilities(g_window_ctx->graphic_ctx.physical_device, g_window_ctx->surface,
g_window_ctx->surface_capabilities);
*g_window_ctx->surface_capabilities);
}
static void VulkanRecreateSwapchain() {
@@ -390,61 +384,60 @@ static void VulkanRecreateSwapchain() {
LOGF("Recreating Vulkan swapchain\n");
VulkanRefreshSurfaceSize();
VulkanDeleteSwapchain(&g_window_ctx->graphic_ctx, g_window_ctx->swapchain);
g_window_ctx->swapchain = VulkanCreateSwapchain(&g_window_ctx->graphic_ctx, 2);
VulkanDeleteSwapchain(g_window_ctx->swapchain);
g_window_ctx->swapchain = VulkanCreateSwapchain(2);
}
static void ValidatePreparedCommand(CommandBuffer* buffer) {
if (buffer == nullptr || buffer->IsInvalid() ||
buffer->GetQueue() != GraphicContext::QUEUE_GFX) {
static void ValidatePreparedCommand(CommandBuffer& buffer) {
if (buffer.IsInvalid() || buffer.GetQueue() != GraphicContext::QUEUE_GFX) {
EXIT("prepared frames must be recorded on the graphics queue\n");
}
EXIT_IF(g_render_ctx == nullptr);
}
PreparedFrame* WindowPrepareFrame(CommandBuffer* buffer, VideoOutVulkanImage* image) {
PreparedFrame& WindowPrepareFrame(CommandBuffer& buffer, VideoOutVulkanImage& image) {
KYTY_PROFILER_FUNCTION();
ValidatePreparedCommand(buffer);
if (image->format == vk::Format::eUndefined) {
EXIT("unsupported presentation source, image=%p\n", static_cast<const void*>(image));
if (image.format == vk::Format::eUndefined) {
EXIT("unsupported presentation source, image=%p\n", static_cast<const void*>(&image));
}
auto* frame = GetPreparedFramePool()->Acquire();
Common::LockGuard render_lock(g_render_ctx->GetMutex());
g_render_ctx->GetTextureCache()->RefreshVideoOut(image);
ConfigurePreparedFrame(frame, image->extent, image->format);
const std::array copies {ImageImageCopy {
.src_image = image, .width = image->extent.width, .height = image->extent.height}};
Transfer::CopyImage(buffer, copies, &frame->image, vk::ImageLayout::eTransferSrcOptimal);
return frame;
Common::LockGuard render_lock(GetRenderContext().GetMutex());
GetRenderContext().GetTextureCache().RefreshVideoOut(image);
ConfigurePreparedFrame(*frame, image.extent, image.format);
ImageImageCopy copy {image};
copy.width = image.extent.width;
copy.height = image.extent.height;
const std::array copies {copy};
Transfer::CopyImage(buffer, copies, frame->image, vk::ImageLayout::eTransferSrcOptimal);
return *frame;
}
PreparedFrame* WindowPrepareBlankFrame(CommandBuffer* buffer, uint32_t width, uint32_t height,
PreparedFrame& WindowPrepareBlankFrame(CommandBuffer& buffer, uint32_t width, uint32_t height,
bool opaque) {
KYTY_PROFILER_FUNCTION();
ValidatePreparedCommand(buffer);
auto* pool = GetPreparedFramePool();
auto format = pool->GetFormat();
auto* frame = pool->Acquire();
Common::LockGuard render_lock(g_render_ctx->GetMutex());
ConfigurePreparedFrame(frame, {width, height}, format);
Common::LockGuard render_lock(GetRenderContext().GetMutex());
ConfigurePreparedFrame(*frame, {width, height}, format);
vk::ClearColorValue clear {};
clear.float32[3] = opaque ? 1.0f : 0.0f;
Transfer::ClearColorImage(buffer, &frame->image, clear);
return frame;
Transfer::ClearColorImage(buffer, frame->image, clear);
return *frame;
}
void WindowPresentFrame(PreparedFrame* frame) {
void WindowPresentFrame(PreparedFrame& frame) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(frame == nullptr);
EXIT_IF(g_window_ctx == nullptr);
EXIT_IF(g_window_ctx->swapchain == nullptr);
struct ReleaseScope {
PreparedFrame* frame;
~ReleaseScope() { GetPreparedFramePool()->Release(frame); }
};
ReleaseScope release {frame};
ReleaseScope release {&frame};
if (g_window_ctx->window_hidden) {
WindowUpdateIcon();
@@ -478,17 +471,17 @@ void WindowPresentFrame(PreparedFrame* frame) {
default: EXIT("vkAcquireNextImageKHR failed: %s\n", VulkanToString(result).c_str());
}
EXIT_NOT_IMPLEMENTED(swapchain->current_index == static_cast<uint32_t>(-1));
if (frame->present_commands == nullptr) {
frame->present_commands = std::make_unique<CommandBuffer>(GraphicContext::QUEUE_GFX);
if (frame.present_commands == nullptr) {
frame.present_commands = std::make_unique<CommandBuffer>(GraphicContext::QUEUE_GFX);
}
frame->present_commands->WaitForFenceAndReset();
auto& buffer = *frame->present_commands;
frame.present_commands->WaitForFenceAndReset();
auto& buffer = *frame.present_commands;
auto vk_buffer = buffer.Handle();
buffer.Begin();
Transfer::BlitToSwapchain(&buffer, &frame->image, swapchain);
Transfer::BlitToSwapchain(buffer, frame.image, *swapchain);
vk::ImageMemoryBarrier pre_present_barrier {};
pre_present_barrier.sType = vk::StructureType::eImageMemoryBarrier;
+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,
SurfaceCapabilities* r) {
RequireVulkanSuccess(physical_device.getSurfaceCapabilitiesKHR(surface, &r->capabilities),
SurfaceCapabilities& r) {
RequireVulkanSuccess(physical_device.getSurfaceCapabilitiesKHR(surface, &r.capabilities),
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
r->formats = EnumerateVulkan<vk::SurfaceFormatKHR>( // @suppress("Ambiguous problem")
r.formats = EnumerateVulkan<vk::SurfaceFormatKHR>( // @suppress("Ambiguous problem")
"vkGetPhysicalDeviceSurfaceFormatsKHR", [&](uint32_t* count, vk::SurfaceFormatKHR* values) {
return physical_device.getSurfaceFormatsKHR(surface, count, values);
});
EXIT_NOT_IMPLEMENTED(r->formats.empty());
EXIT_NOT_IMPLEMENTED(r.formats.empty());
r->present_modes = EnumerateVulkan<vk::PresentModeKHR>( // @suppress("Ambiguous problem")
r.present_modes = EnumerateVulkan<vk::PresentModeKHR>( // @suppress("Ambiguous problem")
"vkGetPhysicalDeviceSurfacePresentModesKHR",
[&](uint32_t* count, vk::PresentModeKHR* values) {
return physical_device.getSurfacePresentModesKHR(surface, count, values);
});
EXIT_NOT_IMPLEMENTED(r->present_modes.empty());
EXIT_NOT_IMPLEMENTED(r.present_modes.empty());
r->format_srgb_bgra32 = false;
r->format_unorm_bgra32 = false;
for (const auto& f: r->formats) {
r.format_srgb_bgra32 = false;
r.format_unorm_bgra32 = false;
for (const auto& f: r.formats) {
if (f.format == vk::Format::eB8G8R8A8Srgb &&
f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
r->format_srgb_bgra32 = true;
r.format_srgb_bgra32 = true;
}
if (f.format == vk::Format::eB8G8R8A8Unorm &&
f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
r->format_unorm_bgra32 = true;
r.format_unorm_bgra32 = true;
}
if (r->format_srgb_bgra32 && r->format_unorm_bgra32) {
if (r.format_srgb_bgra32 && r.format_unorm_bgra32) {
break;
}
}
@@ -244,13 +244,10 @@ static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR s
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surface,
const std::vector<const char*>& device_extensions,
SurfaceCapabilities* out_capabilities,
vk::PhysicalDevice* out_device, VulkanQueues* out_queues) {
SurfaceCapabilities& out_capabilities,
vk::PhysicalDevice& out_device, VulkanQueues& out_queues) {
EXIT_IF(instance == nullptr);
EXIT_IF(surface == nullptr);
EXIT_IF(out_capabilities == nullptr);
EXIT_IF(out_device == nullptr);
EXIT_IF(out_queues == nullptr);
auto devices = EnumerateVulkan<vk::PhysicalDevice>(
"vkEnumeratePhysicalDevices", [&](uint32_t* count, vk::PhysicalDevice* values) {
@@ -408,7 +405,7 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
SurfaceCapabilities candidate_capabilities;
if (!skip_device) {
VulkanGetSurfaceCapabilities(device, surface, &candidate_capabilities);
VulkanGetSurfaceCapabilities(device, surface, candidate_capabilities);
if (!(candidate_capabilities.capabilities.supportedUsageFlags &
vk::ImageUsageFlagBits::eTransferDst)) {
@@ -512,16 +509,16 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
}
}
*out_device = best_device;
*out_queues = best_queues;
out_device = best_device;
out_queues = best_queues;
if (best_device != nullptr) {
*out_capabilities = std::move(best_capabilities);
out_capabilities = std::move(best_capabilities);
}
}
static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device, GraphicContext* ctx) {
static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device) {
EXIT_IF(physical_device == nullptr);
EXIT_IF(ctx == nullptr);
auto& graphics = g_window_ctx->graphic_ctx;
vk::PhysicalDeviceSubgroupSizeControlProperties subgroup_size_control {};
subgroup_size_control.sType = vk::StructureType::ePhysicalDeviceSubgroupSizeControlProperties;
@@ -547,28 +544,26 @@ static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device, Gr
physical_device.getFeatures2(&features2);
ctx->subgroup_size = properties11.subgroupSize;
ctx->min_subgroup_size = subgroup_size_control.minSubgroupSize;
ctx->max_subgroup_size = subgroup_size_control.maxSubgroupSize;
ctx->required_subgroup_size_stages = subgroup_size_control.requiredSubgroupSizeStages;
ctx->subgroup_size_control_enabled = features13.subgroupSizeControl == VK_TRUE &&
graphics.subgroup_size = properties11.subgroupSize;
graphics.min_subgroup_size = subgroup_size_control.minSubgroupSize;
graphics.max_subgroup_size = subgroup_size_control.maxSubgroupSize;
graphics.required_subgroup_size_stages = subgroup_size_control.requiredSubgroupSizeStages;
graphics.subgroup_size_control_enabled = features13.subgroupSizeControl == VK_TRUE &&
subgroup_size_control.minSubgroupSize <= 64 &&
subgroup_size_control.maxSubgroupSize >= 64;
LOGF("Vulkan subgroup: default=%u min=%u max=%u stages=0x%08x size_control=%s\n",
ctx->subgroup_size, ctx->min_subgroup_size, ctx->max_subgroup_size,
static_cast<vk::ShaderStageFlags::MaskType>(ctx->required_subgroup_size_stages),
ctx->subgroup_size_control_enabled ? "true" : "false");
graphics.subgroup_size, graphics.min_subgroup_size, graphics.max_subgroup_size,
static_cast<vk::ShaderStageFlags::MaskType>(graphics.required_subgroup_size_stages),
graphics.subgroup_size_control_enabled ? "true" : "false");
}
static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface,
const VulkanExtensions* r, const VulkanQueues& queues,
const std::vector<const char*>& device_extensions,
GraphicContext* ctx) {
const VulkanExtensions& r, const VulkanQueues& queues,
const std::vector<const char*>& device_extensions) {
EXIT_IF(physical_device == nullptr);
EXIT_IF(r == nullptr);
auto& graphics = g_window_ctx->graphic_ctx;
EXIT_IF(surface == nullptr);
EXIT_IF(ctx == nullptr);
std::vector<vk::DeviceQueueCreateInfo> queue_create_info(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.tessellationShader = VK_TRUE;
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 =
supported_features2.features.vertexPipelineStoresAndAtomics;
if (ctx->subgroup_size_control_enabled && supported_features13.subgroupSizeControl == VK_TRUE) {
if (graphics.subgroup_size_control_enabled &&
supported_features13.subgroupSizeControl == VK_TRUE) {
subgroup_size_control.subgroupSizeControl = VK_TRUE;
}
@@ -685,9 +681,9 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::Sur
create_info.pQueueCreateInfos = queue_create_info.data();
create_info.queueCreateInfoCount = queue_create_info_num;
create_info.enabledLayerCount =
(r->enable_validation_layers ? static_cast<uint32_t>(r->required_layers.size()) : 0);
(r.enable_validation_layers ? static_cast<uint32_t>(r.required_layers.size()) : 0);
create_info.ppEnabledLayerNames =
(r->enable_validation_layers ? r->required_layers.data() : nullptr);
(r.enable_validation_layers ? r.required_layers.data() : nullptr);
create_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions.size());
create_info.ppEnabledExtensionNames = device_extensions.data();
create_info.pEnabledFeatures = &device_features;
@@ -703,9 +699,8 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, vk::Sur
return device;
}
static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) {
static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions& r) {
EXIT_IF(window == nullptr);
EXIT_IF(r == nullptr);
uint32_t required_extensions_count = 0;
@@ -714,65 +709,65 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) {
EXIT_NOT_IMPLEMENTED(sdl_result == SDL_FALSE);
EXIT_NOT_IMPLEMENTED(required_extensions_count == 0);
r->required_extensions =
r.required_extensions =
std::vector<const char*>(required_extensions_count); // @suppress("Ambiguous problem")
std::memset(r->required_extensions.data(), 0,
sizeof(const char*) * r->required_extensions.size());
std::memset(r.required_extensions.data(), 0,
sizeof(const char*) * r.required_extensions.size());
sdl_result = SDL_Vulkan_GetInstanceExtensions(window, &required_extensions_count,
r->required_extensions.data());
r.required_extensions.data());
EXIT_NOT_IMPLEMENTED(sdl_result == SDL_FALSE);
EXIT_NOT_IMPLEMENTED(required_extensions_count == 0);
EXIT_NOT_IMPLEMENTED(required_extensions_count != r->required_extensions.size());
EXIT_NOT_IMPLEMENTED(required_extensions_count != r.required_extensions.size());
r->available_extensions =
r.available_extensions =
EnumerateVulkan<vk::ExtensionProperties>( // @suppress("Ambiguous problem")
"vkEnumerateInstanceExtensionProperties",
[](uint32_t* count, vk::ExtensionProperties* values) {
return vk::enumerateInstanceExtensionProperties(nullptr, count, values);
});
r->enable_validation_layers = Config::VulkanValidationEnabled();
r.enable_validation_layers = Config::VulkanValidationEnabled();
if (HasExtension(r->available_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
r->required_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
if (HasExtension(r.available_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
r.required_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
} else {
r->enable_validation_layers = false;
r.enable_validation_layers = false;
}
for (const char* ext: r->required_extensions) {
for (const char* ext: r.required_extensions) {
LOGF("Vulkan required extension: %s\n", ext);
}
for (const auto& ext: r->available_extensions) {
for (const auto& ext: r.available_extensions) {
LOGF("Vulkan available extension: %s, version = %u\n", ext.extensionName.data(),
ext.specVersion);
}
r->available_layers = EnumerateVulkan<vk::LayerProperties>( // @suppress("Ambiguous problem")
r.available_layers = EnumerateVulkan<vk::LayerProperties>( // @suppress("Ambiguous problem")
"vkEnumerateInstanceLayerProperties", [](uint32_t* count, vk::LayerProperties* values) {
return vk::enumerateInstanceLayerProperties(count, values);
});
for (const auto& l: r->available_layers) {
for (const auto& l: r.available_layers) {
LOGF("Vulkan available layer: %s, specVersion = %u, implVersion = %u, %s\n",
l.layerName.data(), l.specVersion, l.implementationVersion, l.description.data());
}
r->required_layers = {"VK_LAYER_KHRONOS_validation"};
r.required_layers = {"VK_LAYER_KHRONOS_validation"};
if (r->enable_validation_layers) {
for (const char* l: r->required_layers) {
if (!HasLayer(r->available_layers, l)) {
if (r.enable_validation_layers) {
for (const char* l: r.required_layers) {
if (!HasLayer(r.available_layers, l)) {
LOGF("no validation layer: %s\n", l);
r->enable_validation_layers = false;
r.enable_validation_layers = false;
break;
}
}
}
if (r->enable_validation_layers) {
if (r.enable_validation_layers) {
auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>(
"vkEnumerateInstanceExtensionProperties",
[](uint32_t* count, vk::ExtensionProperties* values) {
@@ -786,9 +781,9 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) {
}
if (HasExtension(available_extensions, VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME)) {
r->required_extensions.push_back(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME);
r.required_extensions.push_back(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME);
} else {
r->enable_validation_layers = false;
r.enable_validation_layers = false;
}
}
}
@@ -870,28 +865,30 @@ static VKAPI_ATTR vk::Result VKAPI_CALL VulkanCreateDebugUtilsMessengerEXT(
return vk::Result::eErrorExtensionNotPresent;
}
static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
static void VulkanCreateQueues(const VulkanQueues& queues) {
auto& graphics = g_window_ctx->graphic_ctx;
EXIT_IF(graphics.device == nullptr);
EXIT_IF(queues.graphics.size() != 1);
EXIT_IF(queues.present.size() != 1);
EXIT_IF(!(queues.compute.size() >= 1 &&
queues.compute.size() <= GraphicContext::QUEUE_COMPUTE_NUM));
auto get_queue = [ctx](int id, const QueueInfo& info) {
ctx->queues[id].family = info.family;
ctx->queues[id].index = info.index;
EXIT_IF(ctx->queues[id].vk_queue != nullptr);
ctx->device.getQueue(ctx->queues[id].family, ctx->queues[id].index,
&ctx->queues[id].vk_queue);
EXIT_NOT_IMPLEMENTED(ctx->queues[id].vk_queue == nullptr);
auto get_queue = [&graphics](int id, const QueueInfo& info) {
graphics.queues[id].family = info.family;
graphics.queues[id].index = info.index;
EXIT_IF(graphics.queues[id].vk_queue != nullptr);
graphics.device.getQueue(graphics.queues[id].family, graphics.queues[id].index,
&graphics.queues[id].vk_queue);
EXIT_NOT_IMPLEMENTED(graphics.queues[id].vk_queue == nullptr);
};
get_queue(GraphicContext::QUEUE_GFX, queues.graphics[0]);
ctx->queues[GraphicContext::QUEUE_UTIL].family = ctx->queues[GraphicContext::QUEUE_GFX].family;
ctx->queues[GraphicContext::QUEUE_UTIL].index = ctx->queues[GraphicContext::QUEUE_GFX].index;
ctx->queues[GraphicContext::QUEUE_UTIL].vk_queue =
ctx->queues[GraphicContext::QUEUE_GFX].vk_queue;
graphics.queues[GraphicContext::QUEUE_UTIL].family =
graphics.queues[GraphicContext::QUEUE_GFX].family;
graphics.queues[GraphicContext::QUEUE_UTIL].index =
graphics.queues[GraphicContext::QUEUE_GFX].index;
graphics.queues[GraphicContext::QUEUE_UTIL].vk_queue =
graphics.queues[GraphicContext::QUEUE_GFX].vk_queue;
LOGF("Vulkan queue: using graphics queue for utility submissions to preserve resource "
"ordering\n");
get_queue(GraphicContext::QUEUE_PRESENT, queues.present[0]);
@@ -902,14 +899,14 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues)
}
for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) {
auto& queue = ctx->queues[id];
auto& queue = graphics.queues[id];
if (queue.vk_queue == nullptr) {
continue;
}
EXIT_IF(queue.mutex != nullptr);
for (int other_id = 0; other_id < id; other_id++) {
auto& other = ctx->queues[other_id];
auto& other = graphics.queues[other_id];
if (other.vk_queue != queue.vk_queue) {
continue;
}
@@ -921,7 +918,7 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues)
}
if (queue.mutex == nullptr) {
queue.mutex = &ctx->queue_mutexes[id];
queue.mutex = &graphics.queue_mutexes[id];
}
}
}
@@ -946,12 +943,12 @@ static void VulkanCheckInstanceVersion() {
}
}
void VulkanCreate(WindowContext* ctx) {
EXIT_IF(ctx->window == nullptr);
EXIT_IF(ctx->graphic_ctx.instance != nullptr);
EXIT_IF(ctx->graphic_ctx.physical_device != nullptr);
EXIT_IF(ctx->graphic_ctx.device != nullptr);
EXIT_IF(ctx->surface_capabilities != nullptr);
void VulkanCreate(WindowContext& window) {
EXIT_IF(window.window == nullptr);
EXIT_IF(window.graphic_ctx.instance != nullptr);
EXIT_IF(window.graphic_ctx.physical_device != nullptr);
EXIT_IF(window.graphic_ctx.device != nullptr);
EXIT_IF(window.surface_capabilities != nullptr);
auto get_instance_proc_addr =
reinterpret_cast<PFN_vkGetInstanceProcAddr>(SDL_Vulkan_GetVkGetInstanceProcAddr());
@@ -961,7 +958,7 @@ void VulkanCreate(WindowContext* ctx) {
VULKAN_HPP_DEFAULT_DISPATCHER.init(get_instance_proc_addr);
VulkanExtensions r;
VulkanGetExtensions(ctx->window, &r);
VulkanGetExtensions(window.window, r);
VulkanCheckInstanceVersion();
vk::ApplicationInfo app_info {};
@@ -1025,31 +1022,31 @@ void VulkanCreate(WindowContext* ctx) {
inst_info.ppEnabledLayerNames =
(r.enable_validation_layers ? r.required_layers.data() : nullptr);
const vk::Result result = vk::createInstance(&inst_info, nullptr, &ctx->graphic_ctx.instance);
const vk::Result result = vk::createInstance(&inst_info, nullptr, &window.graphic_ctx.instance);
switch (result) {
case vk::Result::eSuccess: break;
case vk::Result::eErrorIncompatibleDriver:
EXIT("Unable to find a compatible Vulkan Driver");
default: EXIT("Could not create a Vulkan instance (for unknown reasons)");
}
VULKAN_HPP_DEFAULT_DISPATCHER.init(ctx->graphic_ctx.instance);
VULKAN_HPP_DEFAULT_DISPATCHER.init(window.graphic_ctx.instance);
if (r.enable_validation_layers) {
dbg_create_info.pNext = nullptr;
if (VulkanCreateDebugUtilsMessengerEXT(ctx->graphic_ctx.instance, &dbg_create_info, nullptr,
&ctx->graphic_ctx.debug_messenger) !=
if (VulkanCreateDebugUtilsMessengerEXT(window.graphic_ctx.instance, &dbg_create_info,
nullptr, &window.graphic_ctx.debug_messenger) !=
vk::Result::eSuccess) {
EXIT("Could not create debug messenger");
}
}
vk::SurfaceKHR::CType native_surface = VK_NULL_HANDLE;
if (SDL_Vulkan_CreateSurface(ctx->window,
static_cast<vk::Instance::CType>(ctx->graphic_ctx.instance),
if (SDL_Vulkan_CreateSurface(window.window,
static_cast<vk::Instance::CType>(window.graphic_ctx.instance),
&native_surface) == SDL_FALSE) {
EXIT("Could not create a Vulkan surface");
}
ctx->surface = native_surface;
window.surface = native_surface;
std::vector<const char*> device_extensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME,
@@ -1062,21 +1059,23 @@ void VulkanCreate(WindowContext* ctx) {
}
#endif
ctx->surface_capabilities = new SurfaceCapabilities {};
window.surface_capabilities = new SurfaceCapabilities {};
VulkanQueues queues;
VulkanFindPhysicalDevice(ctx->graphic_ctx.instance, ctx->surface, device_extensions,
ctx->surface_capabilities, &ctx->graphic_ctx.physical_device, &queues);
VulkanFindPhysicalDevice(window.graphic_ctx.instance, window.surface, device_extensions,
*window.surface_capabilities, window.graphic_ctx.physical_device,
queues);
if (ctx->graphic_ctx.physical_device == nullptr) {
if (window.graphic_ctx.physical_device == nullptr) {
EXIT("Could not find suitable device");
}
ctx->graphic_ctx.physical_device.getProperties(&ctx->graphic_ctx.physical_device_properties);
ctx->graphic_ctx.physical_device.getMemoryProperties(
&ctx->graphic_ctx.physical_device_memory_properties);
const auto& device_properties = ctx->graphic_ctx.GetPhysicalDeviceProperties();
window.graphic_ctx.physical_device.getProperties(
&window.graphic_ctx.physical_device_properties);
window.graphic_ctx.physical_device.getMemoryProperties(
&window.graphic_ctx.physical_device_memory_properties);
const auto& device_properties = window.graphic_ctx.GetPhysicalDeviceProperties();
LOGF("Select device: %s\n", device_properties.deviceName.data());
@@ -1084,40 +1083,40 @@ void VulkanCreate(WindowContext* ctx) {
auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>(
"vkEnumerateDeviceExtensionProperties",
[&](uint32_t* count, vk::ExtensionProperties* values) {
return ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties(
return window.graphic_ctx.physical_device.enumerateDeviceExtensionProperties(
nullptr, count, values);
});
if (HasExtension(available_extensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) {
device_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
ctx->graphic_ctx.memory_budget_ext_enabled = true;
window.graphic_ctx.memory_budget_ext_enabled = true;
}
if (HasExtension(available_extensions, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) {
device_extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
}
}
memcpy(ctx->device_name, device_properties.deviceName, sizeof(ctx->device_name));
std::snprintf(ctx->processor_name, sizeof(ctx->processor_name), "%s",
memcpy(window.device_name, device_properties.deviceName, sizeof(window.device_name));
std::snprintf(window.processor_name, sizeof(window.processor_name), "%s",
Common::GetSystemInfo().ProcessorName.c_str());
VulkanInitSubgroupSizeControl(ctx->graphic_ctx.physical_device, &ctx->graphic_ctx);
VulkanInitSubgroupSizeControl(window.graphic_ctx.physical_device);
ctx->graphic_ctx.device = VulkanCreateDevice(ctx->graphic_ctx.physical_device, ctx->surface, &r,
queues, device_extensions, &ctx->graphic_ctx);
if (ctx->graphic_ctx.device == nullptr) {
window.graphic_ctx.device = VulkanCreateDevice(window.graphic_ctx.physical_device,
window.surface, r, queues, device_extensions);
if (window.graphic_ctx.device == nullptr) {
EXIT("Could not create device");
}
VULKAN_HPP_DEFAULT_DISPATCHER.init(ctx->graphic_ctx.device);
VULKAN_HPP_DEFAULT_DISPATCHER.init(window.graphic_ctx.device);
if (!VulkanCreateAllocator(&ctx->graphic_ctx)) {
if (!window.graphic_ctx.CreateAllocator()) {
EXIT("Could not create Vulkan memory allocator");
}
VulkanCreateQueues(&ctx->graphic_ctx, queues);
VulkanCreateQueues(queues);
ctx->swapchain = VulkanCreateSwapchain(&ctx->graphic_ctx, 2);
RenderDocSetActiveWindow(ctx->graphic_ctx.instance, ctx->window);
window.swapchain = VulkanCreateSwapchain(2);
RenderDocSetActiveWindow(window.graphic_ctx.instance, window.window);
}
} // namespace Libs::Graphics
+159 -193
View File
@@ -234,11 +234,11 @@ struct WindowGame {
};
struct WindowGamePrivate {
WindowGamePrivate() = default;
explicit WindowGamePrivate(GraphicContext& graphics): graphics(graphics) {}
Common::Mutex mutex;
int skip_frames = 0;
GraphicContext* ctx = nullptr;
GraphicContext& graphics;
};
WindowContext* g_window_ctx = nullptr;
@@ -248,58 +248,58 @@ constexpr uint32_t KYTY_SDL_WINDOW_FLAGS =
(static_cast<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)*/
static void CalcFrameTime(WindowGame* game, double game_time_s) {
game->m_previous_time_seconds = game->m_current_time_seconds;
game->m_current_time_seconds = game_time_s;
static void CalcFrameTime(WindowGame& game, double game_time_s) {
game.m_previous_time_seconds = game.m_current_time_seconds;
game.m_current_time_seconds = game_time_s;
game->m_frame_num++;
game->m_fps_frames_num++;
game.m_frame_num++;
game.m_fps_frames_num++;
const auto fps_time = game->m_current_time_seconds - game->m_fps_start_time;
const auto fps_time = game.m_current_time_seconds - game.m_fps_start_time;
if (fps_time > FPS_UPDATE_TIME) {
game->m_current_fps = static_cast<double>(game->m_fps_frames_num) / fps_time;
game->m_fps_frames_num = 0;
game->m_fps_start_time = game->m_current_time_seconds;
game.m_current_fps = static_cast<double>(game.m_fps_frames_num) / fps_time;
game.m_fps_frames_num = 0;
game.m_fps_start_time = game.m_current_time_seconds;
}
}
static bool Init(WindowGame* /*game*/) {
static bool Init(WindowGame& /*game*/) {
return true;
}
static bool Update(WindowGame* /*game*/) {
static bool Update(WindowGame& /*game*/) {
return true;
}
static bool Render(WindowGame* /*game*/) {
static bool Render(WindowGame& /*game*/) {
return true;
}
static bool Close(WindowGame* /*game*/) {
static bool Close(WindowGame& /*game*/) {
return true;
}
static void SetPause(WindowGame* game, bool flag) {
static void SetPause(WindowGame& game, bool flag) {
LOGF("Pause: %s\n", flag ? "true" : "false");
game->m_game_is_paused = flag;
game.m_game_is_paused = flag;
}
static bool RenderAndUpdate(WindowGame* game) {
static bool RenderAndUpdate(WindowGame& game) {
static double lag = 0.0;
lag += game->m_current_time_seconds - game->m_previous_time_seconds;
lag += game.m_current_time_seconds - game.m_previous_time_seconds;
int num = 0;
bool ok = true;
while (lag >= game->m_update_fixed_time) {
if (num < game->m_max_updates_per_frame) {
while (lag >= game.m_update_fixed_time) {
if (num < game.m_max_updates_per_frame) {
ok = ok && Update(game);
game->m_update_num++;
game.m_update_num++;
num++;
game->m_update_time_seconds = game->m_update_num * game->m_update_fixed_time;
game.m_update_time_seconds = game.m_update_num * game.m_update_fixed_time;
}
lag -= game->m_update_fixed_time;
lag -= game.m_update_fixed_time;
}
ok = ok && Render(game);
@@ -307,44 +307,36 @@ static bool RenderAndUpdate(WindowGame* game) {
return ok;
}
bool GameInit(WindowGame* game, const Common::Timer& timer, void* data) {
EXIT_IF(game == nullptr);
EXIT_IF(data == nullptr);
EXIT_IF(game->private_data || game->event);
bool GameInit(WindowGame& game, const Common::Timer& timer) {
EXIT_IF(game.private_data || game.event);
auto& graphics = WindowGetGraphicContext();
auto* ctx = static_cast<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;
pdata->ctx = ctx;
game.private_data = pdata;
game.event = new SDL_Event;
game->private_data = pdata;
game->event = new SDL_Event;
game->m_screen_width = ctx->screen_width;
game->m_screen_height = ctx->screen_height;
game.m_screen_width = graphics.screen_width;
game.m_screen_height = graphics.screen_height;
CalcFrameTime(game, timer.GetTimeS());
return Init(game);
}
bool GameClose(WindowGame* game) {
EXIT_IF(!game);
bool GameClose(WindowGame& game) {
EXIT_IF(!game.private_data || !game.event);
EXIT_IF(!game->private_data || !game->event);
delete (static_cast<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);
}
void GameShowWindow(WindowGame* game, const Common::Timer& timer) {
EXIT_IF(!game);
auto* p = static_cast<WindowGamePrivate*>(game->private_data);
void GameShowWindow(WindowGame& game, const Common::Timer& timer) {
auto* p = static_cast<WindowGamePrivate*>(game.private_data);
EXIT_IF(!p);
@@ -364,33 +356,33 @@ void GameShowWindow(WindowGame* game, const Common::Timer& timer) {
p->mutex.Unlock();
}
void GameEventQuit(WindowGame* game) {
void GameEventQuit(WindowGame& game) {
LOGF("Event: quit\n");
game->m_game_need_exit = true;
game.m_game_need_exit = true;
}
void GameEventTerminate(WindowGame* game) {
void GameEventTerminate(WindowGame& game) {
LOGF("Event: terminate\n");
game->m_game_need_exit = true;
game.m_game_need_exit = true;
}
void GameEventKeyboard(WindowGame* game, const EventKeyboard* key) {
void GameEventKeyboard(WindowGame& game, const EventKeyboard& key) {
#ifdef KYTY_DBG_INPUT
LOGF("Key: time = %.04f, %s%s, %s%s, %s, scan = %d, key = %d, mod = %04" PRIx16 "\n",
key->timestamp_seconds, (key->down ? "down" : ""), (key->up ? "up" : ""),
(key->pressed ? "pressed" : ""), (key->released ? "released" : ""),
(key->repeat ? "repeat" : ""), key->scan_code, key->key_code, key->mod);
key.timestamp_seconds, (key.down ? "down" : ""), (key.up ? "up" : ""),
(key.pressed ? "pressed" : ""), (key.released ? "released" : ""),
(key.repeat ? "repeat" : ""), key.scan_code, key.key_code, key.mod);
#endif
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX
if (key->down) {
switch (key->key_code) {
case SDLK_ESCAPE: game->m_game_need_exit = true; break;
case SDLK_SPACE: SetPause(game, !game->m_game_is_paused); break;
if (key.down) {
switch (key.key_code) {
case SDLK_ESCAPE: game.m_game_need_exit = true; break;
case SDLK_SPACE: SetPause(game, !game.m_game_is_paused); break;
case SDLK_F1:
if (!key->repeat) {
if (!key.repeat) {
RenderDocRequestCapture();
}
break;
@@ -398,159 +390,153 @@ void GameEventKeyboard(WindowGame* game, const EventKeyboard* key) {
}
}
const auto button = KeyboardKeyToPadButton(key->key_code);
if (button != 0 && (key->down || key->up) && !key->repeat) {
const auto button = KeyboardKeyToPadButton(key.key_code);
if (button != 0 && (key.down || key.up) && !key.repeat) {
static bool keyboard_connected = false;
if (!keyboard_connected) {
Controller::ControllerConnect(KEYBOARD_CONTROLLER_ID);
keyboard_connected = true;
}
Controller::ControllerButton(KEYBOARD_CONTROLLER_ID, button, key->down);
Controller::ControllerButton(KEYBOARD_CONTROLLER_ID, button, key.down);
}
#endif
}
void GameEventMouse([[maybe_unused]] WindowGame* game, [[maybe_unused]] const EventMouse* mb) {
void GameEventMouse([[maybe_unused]] WindowGame& game, [[maybe_unused]] const EventMouse& mb) {
#ifdef KYTY_DBG_INPUT
if (mb->wheel) {
LOGF("Mouse wheel: time = %.04f, %s[%d, %d]\n", mb->timestamp_seconds,
(mb->touch ? "touch, " : ""), mb->x, mb->y);
} else if (mb->motion) {
LOGF("Mouse motion: time = %.04f, %s%s%s%s%s%s, [%d, %d], (%d, %d)\n",
mb->timestamp_seconds, (mb->left ? "left" : ""), (mb->middle ? "middle" : ""),
(mb->right ? "right" : ""), (mb->x1 ? "x1" : ""), (mb->x2 ? "x2" : ""),
(mb->touch ? "_touch" : ""), mb->x, mb->y, mb->motion_x, mb->motion_y);
if (mb.wheel) {
LOGF("Mouse wheel: time = %.04f, %s[%d, %d]\n", mb.timestamp_seconds,
(mb.touch ? "touch, " : ""), mb.x, mb.y);
} else if (mb.motion) {
LOGF("Mouse motion: time = %.04f, %s%s%s%s%s%s, [%d, %d], (%d, %d)\n", mb.timestamp_seconds,
(mb.left ? "left" : ""), (mb.middle ? "middle" : ""), (mb.right ? "right" : ""),
(mb.x1 ? "x1" : ""), (mb.x2 ? "x2" : ""), (mb.touch ? "_touch" : ""), mb.x, mb.y,
mb.motion_x, mb.motion_y);
} else {
LOGF("Mouse click: time = %.04f, %d, %s%s%s%s%s%s, %s%s, %s%s, [%d, %d]\n",
mb->timestamp_seconds, mb->num_of_clicks, (mb->left ? "left" : ""),
(mb->middle ? "middle" : ""), (mb->right ? "right" : ""), (mb->x1 ? "x1" : ""),
(mb->x2 ? "x2" : ""), (mb->touch ? "_touch" : ""), (mb->down ? "down" : ""),
(mb->up ? "up" : ""), (mb->pressed ? "pressed" : ""), (mb->released ? "released" : ""),
mb->x, mb->y);
mb.timestamp_seconds, mb.num_of_clicks, (mb.left ? "left" : ""),
(mb.middle ? "middle" : ""), (mb.right ? "right" : ""), (mb.x1 ? "x1" : ""),
(mb.x2 ? "x2" : ""), (mb.touch ? "_touch" : ""), (mb.down ? "down" : ""),
(mb.up ? "up" : ""), (mb.pressed ? "pressed" : ""), (mb.released ? "released" : ""),
mb.x, mb.y);
}
#endif
}
void GameEventFinger([[maybe_unused]] WindowGame* game, [[maybe_unused]] const EventFinger* f) {
void GameEventFinger([[maybe_unused]] WindowGame& game, [[maybe_unused]] const EventFinger& f) {
#ifdef KYTY_DBG_INPUT
if (f->motion) {
if (f.motion) {
LOGF("Finger motion: time = %.04f, %d, %d, (x,y) = [%f, %f], (dx,dy) = [%f, %f], pressure "
"= %f\n",
f->timestamp_seconds, f->touch_id, f->finger_id, f->x, f->y, f->dx, f->dy,
f->pressure);
f.timestamp_seconds, f.touch_id, f.finger_id, f.x, f.y, f.dx, f.dy, f.pressure);
} else {
LOGF("Finger press: time = %.04f, %d, %d, %s%s, (x,y) = [%f, %f], (dx,dy) = [%f, %f], "
"pressure = %f\n",
f->timestamp_seconds, f->touch_id, f->finger_id, (f->down ? "down" : ""),
(f->up ? "up" : ""), f->x, f->y, f->dx, f->dy, f->pressure);
f.timestamp_seconds, f.touch_id, f.finger_id, (f.down ? "down" : ""),
(f.up ? "up" : ""), f.x, f.y, f.dx, f.dy, f.pressure);
}
#endif
}
void GameEventController([[maybe_unused]] WindowGame* game,
[[maybe_unused]] const EventController* f) {
EXIT_NOT_IMPLEMENTED(f->remapped);
void GameEventController([[maybe_unused]] WindowGame& game,
[[maybe_unused]] const EventController& f) {
EXIT_NOT_IMPLEMENTED(f.remapped);
#ifdef KYTY_DBG_INPUT
if (f->added || f->removed) {
LOGF("Controller %s: %d, time = %.04f\n", (f->added ? "added" : "removed"), f->id,
f->timestamp_seconds);
} else if (f->axis) {
LOGF("Controller axis: %d, axis = %d, value = %d, time = %.04f\n", f->id, f->axis_id,
f->axis_value, f->timestamp_seconds);
if (f.added || f.removed) {
LOGF("Controller %s: %d, time = %.04f\n", (f.added ? "added" : "removed"), f.id,
f.timestamp_seconds);
} else if (f.axis) {
LOGF("Controller axis: %d, axis = %d, value = %d, time = %.04f\n", f.id, f.axis_id,
f.axis_value, f.timestamp_seconds);
} else {
LOGF("Controller button: "
"%d, %s%s, %s%s, button = %d, time = %.04f\n",
f->id, (f->down ? "down" : ""), (f->up ? "up" : ""), (f->pressed ? "pressed" : ""),
(f->released ? "released" : ""), f->button, f->timestamp_seconds);
f.id, (f.down ? "down" : ""), (f.up ? "up" : ""), (f.pressed ? "pressed" : ""),
(f.released ? "released" : ""), f.button, f.timestamp_seconds);
}
#endif
if (f->added) {
auto* pad = SDL_GameControllerOpen(f->id);
if (f.added) {
auto* pad = SDL_GameControllerOpen(f.id);
EXIT_NOT_IMPLEMENTED(pad == nullptr);
int id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(pad));
Controller::ControllerConnect(id);
}
if (f->removed) {
Controller::ControllerDisconnect(f->id);
SDL_GameControllerClose(SDL_GameControllerFromInstanceID(f->id));
if (f.removed) {
Controller::ControllerDisconnect(f.id);
SDL_GameControllerClose(SDL_GameControllerFromInstanceID(f.id));
}
if (f->down || f->up) {
const auto button = ControllerButtonToPadButton(f->button);
if (f.down || f.up) {
const auto button = ControllerButtonToPadButton(f.button);
if (button != 0) {
Controller::ControllerButton(f->id, button, f->down);
Controller::ControllerButton(f.id, button, f.down);
}
}
if (f->axis) {
const auto axis = ControllerAxisFromSdl(f->axis_id);
if (f.axis) {
const auto axis = ControllerAxisFromSdl(f.axis_id);
if (axis != Controller::Axis::AxisMax) {
Controller::ControllerAxis(f->id, axis,
ControllerAxisValueFromSdl(f->axis_id, f->axis_value));
Controller::ControllerAxis(f.id, axis,
ControllerAxisValueFromSdl(f.axis_id, f.axis_value));
}
}
}
void GameEventDisplay([[maybe_unused]] WindowGame* game, [[maybe_unused]] const EventDisplay* d) {
auto* p = static_cast<WindowGamePrivate*>(game->private_data);
auto* ctx = static_cast<GraphicContext*>(p->ctx);
void GameEventDisplay([[maybe_unused]] WindowGame& game) {
auto* p = static_cast<WindowGamePrivate*>(game.private_data);
p->mutex.Lock();
game->m_screen_width = ctx->screen_width;
game->m_screen_height = ctx->screen_height;
game.m_screen_width = p->graphics.screen_width;
game.m_screen_height = p->graphics.screen_height;
p->mutex.Unlock();
}
void GameEventLowMemory(WindowGame* /*game*/) {
void GameEventLowMemory(WindowGame& /*game*/) {
LOGF("Event: low_memory\n");
}
void GameEventWillEnterBackground(WindowGame* game) {
void GameEventWillEnterBackground(WindowGame& game) {
LOGF("Event: will_enter_background\n");
SetPause(game, true);
}
void GameEventDidEnterBackground(WindowGame* /*game*/) {
void GameEventDidEnterBackground(WindowGame& /*game*/) {
LOGF("Event: did_enter_background\n");
}
void GameEventWillEnterForeground(WindowGame* /*game*/) {
void GameEventWillEnterForeground(WindowGame& /*game*/) {
LOGF("Event: will_enter_foreground\n");
}
void GameEventDidEnterForeground(WindowGame* game) {
void GameEventDidEnterForeground(WindowGame& game) {
LOGF("Event: did_enter_foreground\n");
SetPause(game, false);
}
void GameEventResize(WindowGame* game, uint32_t new_width, uint32_t new_height) {
void GameEventResize(WindowGame& game, uint32_t new_width, uint32_t new_height) {
EXIT_IF(new_width == 0 || new_height == 0);
EXIT_IF(!game);
auto* p = static_cast<WindowGamePrivate*>(game->private_data);
auto* p = static_cast<WindowGamePrivate*>(game.private_data);
EXIT_IF(p == nullptr);
auto* ctx = static_cast<GraphicContext*>(p->ctx);
EXIT_IF(ctx == nullptr);
p->mutex.Lock();
{
p->skip_frames++;
ctx->screen_width = new_width;
ctx->screen_height = new_height;
p->graphics.screen_width = new_width;
p->graphics.screen_height = new_height;
game->m_screen_width = ctx->screen_width;
game->m_screen_height = ctx->screen_height;
game.m_screen_width = p->graphics.screen_width;
game.m_screen_height = p->graphics.screen_height;
}
p->mutex.Unlock();
}
static void ProcessWindowEvent(WindowGame* game, SDL_WindowEvent window) {
static void ProcessWindowEvent(WindowGame& game, SDL_WindowEvent window) {
switch (window.event) {
case SDL_WINDOWEVENT_SHOWN: LOGF("Window %" PRIu32 " shown\n", window.windowID); break;
@@ -608,7 +594,7 @@ static void ProcessWindowEvent(WindowGame* game, SDL_WindowEvent window) {
}
}
static void ProcessDisplayEvent(WindowGame* game, SDL_DisplayEvent display) {
static void ProcessDisplayEvent(WindowGame& game, SDL_DisplayEvent display) {
bool sdl = false;
switch (display.event) {
@@ -617,32 +603,17 @@ static void ProcessDisplayEvent(WindowGame* game, SDL_DisplayEvent display) {
LOGF("Display %" PRIu32 "[%s] changed orientation to %d - ", display.display,
sdl ? "SDL" : "Kyty", static_cast<int>(display.data1));
EventDisplay d {};
d.orientation = DisplayOrientation::Unknown;
switch (display.data1) {
case SDL_ORIENTATION_UNKNOWN: LOGF("UNKNOWN\n"); break;
case SDL_ORIENTATION_LANDSCAPE:
LOGF("LANDSCAPE\n");
d.orientation = DisplayOrientation::Landscape;
break;
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
LOGF("LANDSCAPE_FLIPPED\n");
d.orientation = DisplayOrientation::LandscapeFlipped;
break;
case SDL_ORIENTATION_PORTRAIT:
LOGF("PORTRAIT\n");
d.orientation = DisplayOrientation::Portrait;
break;
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
d.orientation = DisplayOrientation::PortraitFlipped;
LOGF("PORTRAIT_FLIPPED\n");
break;
case SDL_ORIENTATION_LANDSCAPE: LOGF("LANDSCAPE\n"); break;
case SDL_ORIENTATION_LANDSCAPE_FLIPPED: LOGF("LANDSCAPE_FLIPPED\n"); break;
case SDL_ORIENTATION_PORTRAIT: LOGF("PORTRAIT\n"); break;
case SDL_ORIENTATION_PORTRAIT_FLIPPED: LOGF("PORTRAIT_FLIPPED\n"); break;
default: LOGF("???\n");
}
if (!sdl) {
GameEventDisplay(game, &d);
GameEventDisplay(game);
}
break;
@@ -654,30 +625,24 @@ static void ProcessDisplayEvent(WindowGame* game, SDL_DisplayEvent display) {
}
}
int GamePollEvent(WindowGame* game) {
EXIT_IF(!game);
auto* event = static_cast<SDL_Event*>(game->event);
int GamePollEvent(WindowGame& game) {
auto* event = static_cast<SDL_Event*>(game.event);
EXIT_IF(!event);
return SDL_PollEvent(event);
}
int GameWaitEvent(WindowGame* game) {
EXIT_IF(!game);
auto* event = static_cast<SDL_Event*>(game->event);
int GameWaitEvent(WindowGame& game) {
auto* event = static_cast<SDL_Event*>(game.event);
EXIT_IF(!event);
return SDL_WaitEvent(event);
}
void GameProcessEvent(WindowGame* game, double time_s) {
EXIT_IF(!game);
auto* event = static_cast<SDL_Event*>(game->event);
void GameProcessEvent(WindowGame& game, double time_s) {
auto* event = static_cast<SDL_Event*>(game.event);
EXIT_IF(!event);
@@ -712,7 +677,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
key.mod = event->key.keysym.mod;
key.timestamp_seconds = time_s;
GameEventKeyboard(game, &key);
GameEventKeyboard(game, key);
break;
}
@@ -744,7 +709,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
mb.motion_y = 0;
mb.timestamp_seconds = time_s;
GameEventMouse(game, &mb);
GameEventMouse(game, mb);
break;
}
@@ -771,7 +736,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
mb.motion_y = 0;
mb.timestamp_seconds = time_s;
GameEventMouse(game, &mb);
GameEventMouse(game, mb);
break;
}
@@ -798,7 +763,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
mb.motion_y = event->motion.yrel;
mb.timestamp_seconds = time_s;
GameEventMouse(game, &mb);
GameEventMouse(game, mb);
break;
}
@@ -820,7 +785,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
f.pressure = event->tfinger.pressure;
f.timestamp_seconds = time_s;
GameEventFinger(game, &f);
GameEventFinger(game, f);
break;
}
@@ -842,7 +807,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
c.released = false;
c.timestamp_seconds = time_s;
GameEventController(game, &c);
GameEventController(game, c);
break;
}
@@ -865,7 +830,7 @@ void GameProcessEvent(WindowGame* game, double time_s) {
c.released = (event->cbutton.state == SDL_RELEASED);
c.timestamp_seconds = time_s;
GameEventController(game, &c);
GameEventController(game, c);
break;
}
@@ -889,20 +854,20 @@ void GameProcessEvent(WindowGame* game, double time_s) {
c.released = false;
c.timestamp_seconds = time_s;
GameEventController(game, &c);
GameEventController(game, c);
break;
}
}
}
void GameMainLoop(WindowGame* game, void* data) {
void GameMainLoop(WindowGame& game) {
bool need_exit = false;
Common::Timer timer;
timer.Start();
if (!GameInit(game, timer, data)) {
if (!GameInit(game, timer)) {
need_exit = true;
}
@@ -916,7 +881,7 @@ void GameMainLoop(WindowGame* game, void* data) {
continue;
}
if (game->m_game_is_paused) {
if (game.m_game_is_paused) {
if (!timer.IsPaused()) {
timer.Pause();
}
@@ -924,13 +889,13 @@ void GameMainLoop(WindowGame* game, void* data) {
GameWaitEvent(game);
GameProcessEvent(game, timer.GetTimeS());
need_exit = game->m_game_need_exit;
need_exit = game.m_game_need_exit;
continue;
}
need_exit = game->m_game_need_exit;
need_exit = game.m_game_need_exit;
if (game->m_game_is_paused) {
if (game.m_game_is_paused) {
if (!timer.IsPaused()) {
timer.Pause();
}
@@ -952,14 +917,13 @@ void GameMainLoop(WindowGame* game, void* data) {
GameClose(game);
}
static void WindowCreate(WindowContext* ctx) {
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->window != nullptr);
EXIT_IF(ctx->graphic_ctx.screen_width == 0);
EXIT_IF(ctx->graphic_ctx.screen_height == 0);
static void WindowCreate(WindowContext& context) {
EXIT_IF(context.window != nullptr);
EXIT_IF(context.graphic_ctx.screen_width == 0);
EXIT_IF(context.graphic_ctx.screen_height == 0);
int width = static_cast<int>(ctx->graphic_ctx.screen_width);
int height = static_cast<int>(ctx->graphic_ctx.screen_height);
int width = static_cast<int>(context.graphic_ctx.screen_width);
int height = static_cast<int>(context.graphic_ctx.screen_height);
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, "0");
@@ -971,17 +935,17 @@ static void WindowCreate(WindowContext* ctx) {
LOGF("WindowCreate(): width = %d, height = %d\n", width, height);
ctx->window =
context.window =
SDL_CreateWindow(KYTY_SDL_WINDOW_CAPTION, KYTY_SDL_WINDOWPOS_CENTERED,
KYTY_SDL_WINDOWPOS_CENTERED, width, height, KYTY_SDL_WINDOW_FLAGS);
ctx->window_hidden = true;
context.window_hidden = true;
if (ctx->window == nullptr) {
if (context.window == nullptr) {
EXIT("%s\n", SDL_GetError());
}
SDL_SetWindowResizable(ctx->window, SDL_FALSE);
SDL_SetWindowResizable(context.window, SDL_FALSE);
}
void WindowInit(uint32_t width, uint32_t height) {
@@ -1015,19 +979,21 @@ void WindowRun() {
{
EXIT_IF(g_window_ctx->graphic_initialized);
WindowCreate(g_window_ctx);
VulkanCreate(g_window_ctx);
WindowCreate(*g_window_ctx);
VulkanCreate(*g_window_ctx);
g_window_ctx->game = &game;
g_window_ctx->graphic_initialized = true;
g_window_ctx->graphic_initialized_condvar.Signal();
}
g_window_ctx->mutex.Unlock();
GraphicsRenderCreateContext();
GameMainLoop(&game, &g_window_ctx->graphic_ctx);
g_window_ctx->mutex.Lock();
g_window_ctx->graphic_initialized = true;
g_window_ctx->graphic_initialized_condvar.Signal();
g_window_ctx->mutex.Unlock();
GameMainLoop(game);
// TODO: replace std::_Exit shutdown with full Vulkan teardown, then destroy
// the VMA allocator immediately before vkDestroyDevice.
@@ -1043,12 +1009,12 @@ vk::SurfaceCapabilitiesKHR* VulkanGetSurfaceCapabilities() {
return &g_window_ctx->surface_capabilities->capabilities;
}
GraphicContext* WindowGetGraphicContext() {
GraphicContext& WindowGetGraphicContext() {
EXIT_IF(g_window_ctx == nullptr);
Common::LockGuard lock(g_window_ctx->mutex);
return &g_window_ctx->graphic_ctx;
return g_window_ctx->graphic_ctx;
}
static int WindowIconRead(void* user, char* data, int size) {
@@ -41,9 +41,9 @@ struct WindowContext {
extern WindowContext* g_window_ctx;
void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface,
SurfaceCapabilities* capabilities);
VulkanSwapchain* VulkanCreateSwapchain(GraphicContext* ctx, uint32_t image_count);
void VulkanCreate(WindowContext* ctx);
SurfaceCapabilities& capabilities);
VulkanSwapchain* VulkanCreateSwapchain(uint32_t image_count);
void VulkanCreate(WindowContext& window);
void WindowUpdateIcon();
void WindowUpdateTitle();
+12 -13
View File
@@ -6,7 +6,7 @@
#include <algorithm>
#include <cstring>
namespace Libs::Graphics::Rt {
namespace Libs::Graphics {
namespace {
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
void AppendHardwareRayTracingDeviceExtensions(
void GraphicContext::AppendHardwareRayTracingDeviceExtensions(
const std::vector<vk::ExtensionProperties>& available_extensions,
std::vector<const char*>* device_extensions, GraphicContext* ctx) {
EXIT_IF(device_extensions == nullptr || ctx == nullptr);
std::vector<const char*>& device_extensions) {
const char* required[] = {
VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
@@ -40,27 +39,27 @@ void AppendHardwareRayTracingDeviceExtensions(
if (!ExtensionAvailable(available_extensions, extension)) {
LOGF("Vulkan RT: extension %s is unavailable; hardware ray tracing disabled\n",
extension);
ctx->rt_extensions_enabled = false;
rt_extensions_enabled = false;
return;
}
}
for (const auto* extension: required) {
AppendExtensionIfMissing(*device_extensions, extension);
AppendExtensionIfMissing(device_extensions, extension);
}
if (ExtensionAvailable(available_extensions, VK_KHR_SPIRV_1_4_EXTENSION_NAME)) {
AppendExtensionIfMissing(*device_extensions, VK_KHR_SPIRV_1_4_EXTENSION_NAME);
AppendExtensionIfMissing(device_extensions, VK_KHR_SPIRV_1_4_EXTENSION_NAME);
}
if (ExtensionAvailable(available_extensions, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)) {
AppendExtensionIfMissing(*device_extensions, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
AppendExtensionIfMissing(device_extensions, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
}
ctx->rt_extensions_enabled = true;
rt_extensions_enabled = true;
LOGF("Vulkan RT: enabling hardware ray query extensions\n");
}
void LoadHardwareRayTracingFunctions(GraphicContext* ctx) {
EXIT_IF(ctx == nullptr || ctx->device == nullptr);
if (!ctx->rt_extensions_enabled) {
void GraphicContext::LoadHardwareRayTracingFunctions() const {
EXIT_IF(device == nullptr);
if (!rt_extensions_enabled) {
return;
}
@@ -75,4 +74,4 @@ void LoadHardwareRayTracingFunctions(GraphicContext* ctx) {
}
}
} // namespace Libs::Graphics::Rt
} // namespace Libs::Graphics
+1 -13
View File
@@ -5,18 +5,6 @@
#include <vector>
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
namespace Libs::Graphics {} // namespace Libs::Graphics
#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,
std::set<uint32_t>* registers) {
bool CollectValue(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>& visited,
std::set<uint32_t>& registers) {
if (id <= ScalarProvenance::Unknown) {
return true;
}
if (id >= provenance.values.size()) {
return false;
}
if ((*visited)[id] != 0) {
if (visited[id] != 0) {
return true;
}
(*visited)[id] = 1;
visited[id] = 1;
const auto& value = provenance.values[id];
if (value.op == ScalarValueOp::UserData) {
registers->insert(value.imm);
registers.insert(value.imm);
return true;
}
if (value.op == ScalarValueOp::Phi) {
@@ -92,7 +92,7 @@ bool CollectValue(const ScalarProvenance& provenance, uint32_t id, std::vector<u
}
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) {
return true;
}
@@ -112,49 +112,49 @@ bool CollectUserData(const Program& program, std::vector<uint32_t>& result) {
std::set<uint32_t> registers;
std::vector<uint8_t> visited(program.provenance.values.size());
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
for (const auto read: program.srt.dynamic_reads) {
if (!CollectValue(program.provenance, read, &visited, &registers)) {
if (!CollectValue(program.provenance, read, visited, registers)) {
return false;
}
}
for (const auto source: program.srt.dynamic_sources) {
if (!CollectSource(program, source, true, &visited, &registers)) {
if (!CollectSource(program, source, true, visited, registers)) {
return false;
}
}
for (const auto& block: program.blocks) {
for (const auto& inst: block.instructions) {
if (inst.op == Opcode::SLoadDword && inst.memory.kind == ResourceKind::ScalarBuffer &&
!CollectValue(program.provenance, inst.scalar_value, &visited, &registers)) {
!CollectValue(program.provenance, inst.scalar_value, visited, registers)) {
return false;
}
for (uint32_t i = 0; i < inst.src_count; i++) {
if (!CollectValue(program.provenance, inst.scalar_sources[i], &visited,
&registers)) {
if (!CollectValue(program.provenance, inst.scalar_sources[i], visited,
registers)) {
return false;
}
}
@@ -164,10 +164,10 @@ bool CollectUserData(const Program& program, std::vector<uint32_t>& result) {
return true;
}
void AddBinding(BindingLayout* layout, DescriptorBindingKind kind,
void AddBinding(BindingLayout& layout, DescriptorBindingKind kind,
std::vector<uint32_t> resources = {}) {
layout->descriptors.push_back(
{kind, static_cast<uint32_t>(layout->descriptors.size()), std::move(resources)});
layout.descriptors.push_back(
{kind, static_cast<uint32_t>(layout.descriptors.size()), std::move(resources)});
}
bool UsesGds(const Program& program) {
@@ -183,11 +183,10 @@ bool UsesGds(const Program& program) {
} // namespace
bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std::string* error) {
if (program == nullptr || !program->shader_info_complete || program->binding_layout_complete) {
bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std::string* error) {
if (!program.shader_info_complete || program.binding_layout_complete) {
if (error != nullptr) {
*error = program == nullptr ? "invalid binding-layout program"
: !program->shader_info_complete ? "shader info is not ready"
*error = !program.shader_info_complete ? "shader info is not ready"
: "binding layout already allocated";
}
return false;
@@ -208,25 +207,25 @@ bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std
BindingLayout next;
next.descriptor_set = options.descriptor_set;
next.push_constant_offset = options.push_constant_offset;
if (!CollectUserData(*program, next.user_data_registers)) {
if (!CollectUserData(program, next.user_data_registers)) {
if (error != nullptr) {
*error = "shader plan contains an invalid scalar provenance reference";
}
return false;
}
if (!program->info.buffers.empty()) {
std::vector<uint32_t> resources(program->info.buffers.size());
if (!program.info.buffers.empty()) {
std::vector<uint32_t> resources(program.info.buffers.size());
for (uint32_t i = 0; i < resources.size(); i++) {
resources[i] = i;
}
AddBinding(&next, DescriptorBindingKind::Buffers, std::move(resources));
AddBinding(next, DescriptorBindingKind::Buffers, std::move(resources));
}
std::array<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;
if (!ImageBinding(program->info.images[i], kind)) {
if (!ImageBinding(program.info.images[i], kind)) {
if (error != nullptr) {
*error = "shader info contains an invalid image binding class";
}
@@ -243,29 +242,29 @@ bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std
}
for (uint32_t i = 0; i < image_groups.size(); i++) {
if (!image_groups[i].empty()) {
AddBinding(&next, ImageBindingKinds[i], std::move(image_groups[i]));
AddBinding(next, ImageBindingKinds[i], std::move(image_groups[i]));
}
}
if (!program->info.samplers.empty()) {
std::vector<uint32_t> resources(program->info.samplers.size());
if (!program.info.samplers.empty()) {
std::vector<uint32_t> resources(program.info.samplers.size());
for (uint32_t i = 0; i < resources.size(); i++) {
resources[i] = i;
}
AddBinding(&next, DescriptorBindingKind::Samplers, std::move(resources));
AddBinding(next, DescriptorBindingKind::Samplers, std::move(resources));
}
if (UsesGds(*program)) {
AddBinding(&next, DescriptorBindingKind::Gds);
if (UsesGds(program)) {
AddBinding(next, DescriptorBindingKind::Gds);
}
if (!program->info.addresses.empty()) {
std::vector<uint32_t> resources(program->info.addresses.size());
if (!program.info.addresses.empty()) {
std::vector<uint32_t> resources(program.info.addresses.size());
for (uint32_t i = 0; i < resources.size(); i++) {
resources[i] = i;
}
AddBinding(&next, DescriptorBindingKind::AddressMemory, std::move(resources));
AddBinding(next, DescriptorBindingKind::AddressMemory, std::move(resources));
}
if (!program->srt.reads.empty()) {
AddBinding(&next, DescriptorBindingKind::FlattenedSrt);
if (!program.srt.reads.empty()) {
AddBinding(next, DescriptorBindingKind::FlattenedSrt);
}
const auto available_push_dwords = (MaxPushConstantBytes - options.push_constant_offset) / 4u;
@@ -273,11 +272,11 @@ bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std
if (next.user_data_registers.size() <= push_limit) {
next.push_constant_size = static_cast<uint32_t>(next.user_data_registers.size() * 4u);
} else {
AddBinding(&next, DescriptorBindingKind::UserData);
AddBinding(next, DescriptorBindingKind::UserData);
}
program->bindings = std::move(next);
program->binding_layout_complete = true;
program.bindings = std::move(next);
program.binding_layout_complete = true;
return true;
}
@@ -11,7 +11,7 @@ struct BindingLayoutOptions {
uint32_t max_push_dwords = 32;
};
bool AllocateBindings(Program* program, const BindingLayoutOptions& options, std::string* error);
bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std::string* error);
const DescriptorBinding* FindBinding(const BindingLayout& layout, DescriptorBindingKind kind);
+20 -20
View File
@@ -4,7 +4,7 @@
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) {
if (word_index + 1u >= code.size()) {
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 en = word0 & 0xfu;
inst->pc = pc;
inst->word = word0;
inst->word_count = 2;
inst->family = Family::EXP;
inst->opcode_id = target;
inst->opcode = Opcode::Exp;
inst->exp.target = target;
inst->exp.en = en;
inst->exp.compr = ((word0 >> 10u) & 1u) != 0;
inst->exp.done = ((word0 >> 11u) & 1u) != 0;
inst->exp.vm = ((word0 >> 12u) & 1u) != 0;
inst.pc = pc;
inst.word = word0;
inst.word_count = 2;
inst.family = Family::EXP;
inst.opcode_id = target;
inst.opcode = Opcode::Exp;
inst.exp.target = target;
inst.exp.en = en;
inst.exp.compr = ((word0 >> 10u) & 1u) != 0;
inst.exp.done = ((word0 >> 11u) & 1u) != 0;
inst.exp.vm = ((word0 >> 12u) & 1u) != 0;
SetRawWords(inst, code, word_index, 2);
if (!DecodeVectorGpr(word1 & 0xffu, &inst->src0, error) ||
!DecodeVectorGpr((word1 >> 8u) & 0xffu, &inst->src1, error) ||
!DecodeVectorGpr((word1 >> 16u) & 0xffu, &inst->src2, error) ||
!DecodeVectorGpr((word1 >> 24u) & 0xffu, &inst->src3, error)) {
if (!DecodeVectorGpr(word1 & 0xffu, inst.src0, error) ||
!DecodeVectorGpr((word1 >> 8u) & 0xffu, inst.src1, error) ||
!DecodeVectorGpr((word1 >> 16u) & 0xffu, inst.src2, error) ||
!DecodeVectorGpr((word1 >> 24u) & 0xffu, inst.src3, error)) {
return false;
}
if (target == 0x14u && inst->exp.done && en == 0x1u) {
inst->src_count = 1u;
if (target == 0x14u && inst.exp.done && en == 0x1u) {
inst.src_count = 1u;
} else {
inst->src_count = inst->exp.compr ? 2u : 4u;
inst.src_count = inst.exp.compr ? 2u : 4u;
}
if (en == 0u) {
inst->src_count = 0;
inst.src_count = 0;
}
return true;
+1 -1
View File
@@ -5,7 +5,7 @@
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);
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
+23 -23
View File
@@ -226,7 +226,7 @@ bool IsSingleDmaskBit(uint32_t dmask) {
} // 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) {
if (word_index + 1u >= code.size()) {
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* atomic = LookupAtomic(opcode);
inst->pc = pc;
inst->word = word0;
inst->word_count = word_count;
inst->family = Family::MIMG;
inst->opcode_id = opcode;
inst->opcode = (sample != nullptr ? Opcode::ImageSample
inst.pc = pc;
inst.word = word0;
inst.word_count = word_count;
inst.family = Family::MIMG;
inst.opcode_id = opcode;
inst.opcode = (sample != nullptr ? Opcode::ImageSample
: gather != nullptr ? gather->decoded
: atomic != nullptr ? atomic->decoded
: opcode == 0x00u ? Opcode::ImageLoad
@@ -272,20 +272,20 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
: opcode == 0x0eu ? Opcode::ImageGetResinfo
: opcode == 0x60u ? Opcode::ImageGetLod
: Opcode::Unsupported);
inst->dmask = (word0 >> 8u) & 0xfu;
inst->data_dwords = gather != nullptr ? 4u : CountDmaskComponents(inst->dmask);
inst->glc = ((word0 >> 13u) & 1u) != 0;
inst->slc = ((word0 >> 25u) & 1u) != 0;
inst->image_sample_flags = (sample != nullptr ? sample->flags
inst.dmask = (word0 >> 8u) & 0xfu;
inst.data_dwords = gather != nullptr ? 4u : CountDmaskComponents(inst.dmask);
inst.glc = ((word0 >> 13u) & 1u) != 0;
inst.slc = ((word0 >> 25u) & 1u) != 0;
inst.image_sample_flags = (sample != nullptr ? sample->flags
: gather != nullptr ? gather->flags
: 0u) |
(a16 ? ImageSampleFlagA16 : 0u);
inst->image_dimension = dimension;
inst->image_nsa_dwords = nsa_dwords;
inst.image_dimension = dimension;
inst.image_nsa_dwords = nsa_dwords;
for (uint32_t i = 0; i < nsa_dwords * 4u && i < MaxImageNsaAddressComponents; i++) {
inst->image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu;
inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu;
}
inst->image_address_components =
inst.image_address_components =
sample != nullptr ? ImageSampleAddressComponents(sample->flags, dimension)
: gather != nullptr ? ImageSampleAddressComponents(gather->flags, dimension)
: atomic != nullptr ? 3u
@@ -297,19 +297,19 @@ bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
: 0u);
SetRawWords(inst, code, word_index, word_count);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
SetUnsupported(inst, Family::MIMG, opcode, "MIMG opcode is not implemented");
}
if (gather != nullptr && !IsSingleDmaskBit(inst->dmask)) {
if (gather != nullptr && !IsSingleDmaskBit(inst.dmask)) {
SetUnsupported(inst, Family::MIMG, opcode,
"MIMG image gather requires exactly one dmask bit");
}
DecodeVectorGpr(vdata, &inst->dst, nullptr);
DecodeVectorGpr(vaddr, &inst->src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr);
DecodeScalarSource(ssamp * 4u, pc, &inst->src2, nullptr);
inst->src_count = 3;
DecodeVectorGpr(vdata, inst.dst, nullptr);
DecodeVectorGpr(vaddr, inst.src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
DecodeScalarSource(ssamp * 4u, pc, inst.src2, nullptr);
inst.src_count = 3;
return true;
}
+1 -1
View File
@@ -5,7 +5,7 @@
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);
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;
}
void MarkMemoryUnsupported(Instruction* inst, Family family, uint32_t opcode, const char* reason) {
inst->family = family;
inst->opcode_id = opcode;
inst->opcode = Opcode::Unsupported;
void MarkMemoryUnsupported(Instruction& inst, Family family, uint32_t opcode, const char* reason) {
inst.family = family;
inst.opcode_id = opcode;
inst.opcode = Opcode::Unsupported;
SetUnsupported(inst, family, opcode, reason);
}
void ApplyMemoryInfo(Instruction* inst, const MemoryOpcodeInfo* info) {
void ApplyMemoryInfo(Instruction& inst, const MemoryOpcodeInfo* info) {
if (info == nullptr) {
inst->opcode = Opcode::Unsupported;
inst.opcode = Opcode::Unsupported;
return;
}
inst->opcode = info->decoded;
inst->data_dwords = info->data_dwords;
inst->data_bits = info->data_bits;
inst->data_signed = info->data_signed;
inst->typed = info->typed;
inst->formatted = info->formatted;
inst.opcode = info->decoded;
inst.data_dwords = info->data_dwords;
inst.data_bits = info->data_bits;
inst.data_signed = info->data_signed;
inst.typed = info->typed;
inst.formatted = info->formatted;
}
bool IsDsWriteOpcode(Opcode opcode) {
@@ -215,7 +215,7 @@ bool IsFlatStoreOpcode(Opcode opcode) {
} // namespace
bool DecodeSmem(uint32_t pc, std::span<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) {
if (word_index + 1u >= code.size()) {
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 soffset = (word1 >> 25u) & 0x7fu;
inst->pc = pc;
inst->word = word0;
inst->word_count = 2;
inst->offset = SignExtendU32(word1 & 0x1fffffu, 21u);
inst->glc = ((word0 >> 16u) & 1u) != 0;
inst->family = Family::SMEM;
inst->opcode_id = opcode;
inst.pc = pc;
inst.word = word0;
inst.word_count = 2;
inst.offset = SignExtendU32(word1 & 0x1fffffu, 21u);
inst.glc = ((word0 >> 16u) & 1u) != 0;
inst.family = Family::SMEM;
inst.opcode_id = opcode;
const auto* info =
LookupMemoryOpcode(SMEM_OPS, static_cast<uint32_t>(std::size(SMEM_OPS)), opcode);
ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
MarkMemoryUnsupported(inst, Family::SMEM, opcode, "SMEM opcode is not implemented");
}
DecodeScalarDestination(sdst, pc, &inst->dst, nullptr);
DecodeScalarDestination(sdst, pc, inst.dst, nullptr);
// SMEM encodes SBASE in SGPR pairs. Scalar-buffer loads still use the same
// pair index; their descriptor operand consumes four SGPRs from that base.
DecodeScalarSource(sbase * 2u, pc, &inst->src0, nullptr);
DecodeScalarSource(soffset, pc, &inst->src1, nullptr);
inst->src_count = 2;
DecodeScalarSource(sbase * 2u, pc, inst.src0, nullptr);
DecodeScalarSource(soffset, pc, inst.src1, nullptr);
inst.src_count = 2;
return true;
}
bool DecodeMubuf(uint32_t pc, std::span<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 (error != nullptr) {
*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 soffset = (word1 >> 24u) & 0xffu;
inst->pc = pc;
inst->word = word0;
inst->word_count = 2;
inst->offset = word0 & 0xfffu;
inst->idxen = ((word0 >> 13u) & 1u) != 0;
inst->offen = ((word0 >> 12u) & 1u) != 0;
inst->glc = ((word0 >> 14u) & 1u) != 0;
inst->slc = ((word1 >> 22u) & 1u) != 0;
inst->family = Family::MUBUF;
inst->opcode_id = opcode;
inst.pc = pc;
inst.word = word0;
inst.word_count = 2;
inst.offset = word0 & 0xfffu;
inst.idxen = ((word0 >> 13u) & 1u) != 0;
inst.offen = ((word0 >> 12u) & 1u) != 0;
inst.glc = ((word0 >> 14u) & 1u) != 0;
inst.slc = ((word1 >> 22u) & 1u) != 0;
inst.family = Family::MUBUF;
inst.opcode_id = opcode;
const auto* info =
LookupMemoryOpcode(MUBUF_OPS, static_cast<uint32_t>(std::size(MUBUF_OPS)), opcode);
ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
MarkMemoryUnsupported(inst, Family::MUBUF, opcode, "MUBUF opcode is not implemented");
}
DecodeVectorGpr(vdata, &inst->dst, nullptr);
DecodeVectorGpr(vaddr, &inst->src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr);
DecodeScalarSource(soffset, pc, &inst->src2, nullptr);
inst->src_count = 3;
DecodeVectorGpr(vdata, inst.dst, nullptr);
DecodeVectorGpr(vaddr, inst.src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
DecodeScalarSource(soffset, pc, inst.src2, nullptr);
inst.src_count = 3;
return true;
}
bool DecodeMtbuf(uint32_t pc, std::span<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 (error != nullptr) {
*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 soffset = (word1 >> 24u) & 0xffu;
inst->pc = pc;
inst->word = word0;
inst->word_count = 2;
inst->offset = word0 & 0xfffu;
inst->idxen = ((word0 >> 13u) & 1u) != 0;
inst->offen = ((word0 >> 12u) & 1u) != 0;
inst->glc = ((word0 >> 14u) & 1u) != 0;
inst->slc = ((word1 >> 22u) & 1u) != 0;
inst->family = Family::MTBUF;
inst->opcode_id = opcode;
inst->data_format = dfmt;
inst->number_format = nfmt;
inst.pc = pc;
inst.word = word0;
inst.word_count = 2;
inst.offset = word0 & 0xfffu;
inst.idxen = ((word0 >> 13u) & 1u) != 0;
inst.offen = ((word0 >> 12u) & 1u) != 0;
inst.glc = ((word0 >> 14u) & 1u) != 0;
inst.slc = ((word1 >> 22u) & 1u) != 0;
inst.family = Family::MTBUF;
inst.opcode_id = opcode;
inst.data_format = dfmt;
inst.number_format = nfmt;
const auto* info =
LookupMemoryOpcode(MTBUF_OPS, static_cast<uint32_t>(std::size(MTBUF_OPS)), opcode);
ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
MarkMemoryUnsupported(inst, Family::MTBUF, opcode, "MTBUF opcode is not implemented");
}
DecodeVectorGpr(vdata, &inst->dst, nullptr);
DecodeVectorGpr(vaddr, &inst->src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, &inst->src1, nullptr);
DecodeScalarSource(soffset, pc, &inst->src2, nullptr);
inst->src_count = 3;
DecodeVectorGpr(vdata, inst.dst, nullptr);
DecodeVectorGpr(vaddr, inst.src0, nullptr);
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
DecodeScalarSource(soffset, pc, inst.src2, nullptr);
inst.src_count = 3;
return true;
}
bool DecodeFlat(uint32_t pc, std::span<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) {
if (word_index + 1u >= code.size()) {
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 addr = word1 & 0xffu;
inst->pc = pc;
inst->word = word0;
inst->word_count = 2;
inst->offset = seg == 0u ? (offset & 0x7ffu) : SignExtendU32(offset, 12u);
inst->glc = ((word0 >> 16u) & 1u) != 0;
inst->slc = ((word0 >> 17u) & 1u) != 0;
inst->family = Family::FLAT;
inst->opcode_id = opcode;
inst->memory_segment = seg;
inst.pc = pc;
inst.word = word0;
inst.word_count = 2;
inst.offset = seg == 0u ? (offset & 0x7ffu) : SignExtendU32(offset, 12u);
inst.glc = ((word0 >> 16u) & 1u) != 0;
inst.slc = ((word0 >> 17u) & 1u) != 0;
inst.family = Family::FLAT;
inst.opcode_id = opcode;
inst.memory_segment = seg;
const auto* info =
LookupMemoryOpcode(FLAT_OPS, static_cast<uint32_t>(std::size(FLAT_OPS)), opcode);
ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2);
if (dlc != 0 || lds != 0 || inst->glc || inst->slc || seg == 3u) {
if (dlc != 0 || lds != 0 || inst.glc || inst.slc || seg == 3u) {
SetUnsupported(inst, Family::FLAT, opcode, "FLAT modifiers or segment are not implemented");
return true;
}
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
MarkMemoryUnsupported(inst, Family::FLAT, opcode, "FLAT opcode is not implemented");
return true;
}
DecodeVectorGpr(IsFlatStoreOpcode(inst->opcode) ? data : vdst, &inst->dst, nullptr);
DecodeVectorGpr(addr, &inst->src0, nullptr);
inst->src_count = 1;
DecodeVectorGpr(IsFlatStoreOpcode(inst.opcode) ? data : vdst, inst.dst, nullptr);
DecodeVectorGpr(addr, inst.src0, nullptr);
inst.src_count = 1;
if (seg == 0u || saddr == 0x7du || saddr == 0x7fu) {
DecodeVectorGpr(addr + 1u, &inst->src1, nullptr);
inst->src_count = 2;
DecodeVectorGpr(addr + 1u, inst.src1, nullptr);
inst.src_count = 2;
} else {
DecodeScalarSource(saddr, pc, &inst->src1, nullptr);
inst->src_count = 2;
DecodeScalarSource(saddr, pc, inst.src1, nullptr);
inst.src_count = 2;
}
return true;
}
bool DecodeDs(uint32_t pc, std::span<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) {
if (word_index + 1u >= code.size()) {
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 addr = word1 & 0xffu;
inst->pc = pc;
inst->word = word0;
inst->word_count = 2;
inst->offset = offset0 | (offset1 << 8u);
inst->gds = ((word0 >> 17u) & 1u) != 0u;
inst->family = Family::DS;
inst->opcode_id = opcode;
inst.pc = pc;
inst.word = word0;
inst.word_count = 2;
inst.offset = offset0 | (offset1 << 8u);
inst.gds = ((word0 >> 17u) & 1u) != 0u;
inst.family = Family::DS;
inst.opcode_id = opcode;
const auto* info = LookupMemoryOpcode(DS_OPS, static_cast<uint32_t>(std::size(DS_OPS)), opcode);
ApplyMemoryInfo(inst, info);
SetRawWords(inst, code, word_index, 2);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
MarkMemoryUnsupported(inst, Family::DS, opcode, "DS opcode is not implemented");
}
if (inst->opcode == Opcode::DsSwizzleB32 && inst->offset >= 0xe000u) {
if (inst.opcode == Opcode::DsSwizzleB32 && inst.offset >= 0xe000u) {
SetUnsupported(inst, Family::DS, opcode, "DS swizzle FFT mode is not implemented");
}
if (inst->gds &&
(inst->opcode == Opcode::DsSwizzleB32 || inst->opcode == Opcode::DsWriteAddtidB32 ||
inst->opcode == Opcode::DsReadAddtidB32)) {
if (inst.gds &&
(inst.opcode == Opcode::DsSwizzleB32 || inst.opcode == Opcode::DsWriteAddtidB32 ||
inst.opcode == Opcode::DsReadAddtidB32)) {
SetUnsupported(inst, Family::DS, opcode, "DS swizzle/addtid is available only for LDS");
}
if (inst->gds && (inst->opcode == Opcode::DsAppend || inst->opcode == Opcode::DsConsume) &&
inst->offset != 0u) {
if (inst.gds && (inst.opcode == Opcode::DsAppend || inst.opcode == Opcode::DsConsume) &&
inst.offset != 0u) {
SetUnsupported(inst, Family::DS, opcode,
"GDS append/consume requires a zero instruction offset");
}
if (inst->opcode == Opcode::DsWriteAddtidB32 && data1 != 0u) {
if (inst.opcode == Opcode::DsWriteAddtidB32 && data1 != 0u) {
SetUnsupported(inst, Family::DS, opcode,
"DS write addtid data1 operand is not implemented");
}
if (inst->opcode == Opcode::DsReadAddtidB32 && (data0 != 0u || data1 != 0u)) {
if (inst.opcode == Opcode::DsReadAddtidB32 && (data0 != 0u || data1 != 0u)) {
SetUnsupported(inst, Family::DS, opcode,
"DS read addtid data operands are not implemented");
}
if (inst->opcode == Opcode::DsWrite2B32 || opcode == 0x37u) {
inst->offset = offset0 * 4u;
inst->secondary_offset = offset1 * 4u;
} else if (inst->opcode == Opcode::DsWrite2St64B32 || opcode == 0x38u) {
inst->offset = offset0 * 256u;
inst->secondary_offset = offset1 * 256u;
} else if (inst->opcode == Opcode::DsWrite2B64 || inst->opcode == Opcode::DsRead2B64) {
inst->offset = offset0 * 8u;
inst->secondary_offset = offset1 * 8u;
} else if (inst->opcode == Opcode::DsWrite2St64B64 || inst->opcode == Opcode::DsRead2St64B64) {
inst->offset = offset0 * 512u;
inst->secondary_offset = offset1 * 512u;
if (inst.opcode == Opcode::DsWrite2B32 || opcode == 0x37u) {
inst.offset = offset0 * 4u;
inst.secondary_offset = offset1 * 4u;
} else if (inst.opcode == Opcode::DsWrite2St64B32 || opcode == 0x38u) {
inst.offset = offset0 * 256u;
inst.secondary_offset = offset1 * 256u;
} else if (inst.opcode == Opcode::DsWrite2B64 || inst.opcode == Opcode::DsRead2B64) {
inst.offset = offset0 * 8u;
inst.secondary_offset = offset1 * 8u;
} else if (inst.opcode == Opcode::DsWrite2St64B64 || inst.opcode == Opcode::DsRead2St64B64) {
inst.offset = offset0 * 512u;
inst.secondary_offset = offset1 * 512u;
}
DecodeVectorGpr(vdst, &inst->dst, nullptr);
DecodeVectorGpr(addr, &inst->src0, nullptr);
DecodeVectorGpr(data0, &inst->src1, nullptr);
DecodeVectorGpr(data1, &inst->src2, nullptr);
inst->src_count = DsSourceCount(inst->opcode);
DecodeVectorGpr(vdst, inst.dst, nullptr);
DecodeVectorGpr(addr, inst.src0, nullptr);
DecodeVectorGpr(data0, inst.src1, nullptr);
DecodeVectorGpr(data1, inst.src2, nullptr);
inst.src_count = DsSourceCount(inst.opcode);
return true;
}
+5 -5
View File
@@ -5,15 +5,15 @@
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);
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,
Instruction* inst, std::string* error);
bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction* inst,
Instruction& inst, std::string* error);
bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
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);
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
@@ -5,6 +5,7 @@
#include <algorithm>
#include <fmt/format.h>
#include <functional>
namespace Libs::Graphics::ShaderRecompiler::IR {
namespace {
@@ -200,11 +201,10 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
}
bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
ResourceSnapshot* snapshot, std::string* error) {
if (snapshot == nullptr || !program.resource_tracking_complete) {
ResourceSnapshot& snapshot, std::string* error) {
if (!program.resource_tracking_complete) {
if (error != nullptr) {
*error = snapshot == nullptr ? "invalid resource snapshot"
: "shader resources were not tracked";
*error = "shader resources were not tracked";
}
return false;
}
@@ -229,7 +229,7 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
std::vector<DescriptorValue> values;
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;
}
@@ -280,25 +280,24 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
if (!ValidateResourceSnapshot(program, next, error)) {
return false;
}
*snapshot = std::move(next);
snapshot = std::move(next);
return true;
}
bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std::string* error) {
if (program == nullptr || !program->resource_tracking_complete ||
program->shader_info_complete || program->binding_layout_complete) {
bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std::string* error) {
if (!program.resource_tracking_complete || program.shader_info_complete ||
program.binding_layout_complete) {
if (error != nullptr) {
*error = program == nullptr ? "invalid resource specialization program"
: !program->resource_tracking_complete ? "shader resources were not tracked"
*error = !program.resource_tracking_complete ? "shader resources were not tracked"
: "resource specialization is too late";
}
return false;
}
if (!ValidateResourceSnapshot(*program, snapshot, error)) {
if (!ValidateResourceSnapshot(program, snapshot, error)) {
return false;
}
auto next = program->info;
auto next = program.info;
for (uint32_t i = 0; i < next.buffers.size(); i++) {
ShaderBufferResource descriptor;
if (!DecodeBufferDescriptor(snapshot.buffers[i], descriptor)) {
@@ -347,12 +346,12 @@ bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std
}
}
struct ImagePatch {
Instruction* inst;
std::reference_wrapper<Instruction> inst;
ResourceKind kind;
Decoder::ImageDimension dimension;
};
std::vector<ImagePatch> patches;
for (auto& block: program->blocks) {
for (auto& block: program.blocks) {
for (auto& inst: block.instructions) {
if (inst.memory.kind != ResourceKind::Image &&
inst.memory.kind != ResourceKind::ImageUint &&
@@ -368,13 +367,13 @@ bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std
return false;
}
const auto& image = next.images[inst.memory.resource];
patches.push_back({&inst, image.kind, image.dimension});
patches.push_back({std::ref(inst), image.kind, image.dimension});
}
}
program->info = std::move(next);
program.info = std::move(next);
for (const auto& patch: patches) {
patch.inst->memory.kind = patch.kind;
patch.inst->memory.image_dimension = patch.dimension;
patch.inst.get().memory.kind = patch.kind;
patch.inst.get().memory.image_dimension = patch.dimension;
}
return true;
}
@@ -31,11 +31,11 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
// Resolves the immutable dense resource topology against one runtime user-data/SRT snapshot.
// On failure the destination is unchanged.
bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
ResourceSnapshot* snapshot, std::string* error);
ResourceSnapshot& snapshot, std::string* error);
// Applies runtime descriptor shape/format facts to a copied dense topology before layout and
// emission. On failure the program is unchanged.
bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std::string* error);
bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std::string* error);
} // namespace Libs::Graphics::ShaderRecompiler::IR
@@ -4,6 +4,7 @@
#include <algorithm>
#include <fmt/format.h>
#include <functional>
namespace Libs::Graphics::ShaderRecompiler::IR {
namespace {
@@ -82,17 +83,17 @@ uint32_t ByteExtent(const Instruction& inst) {
return end > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(end);
}
bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>* visited,
std::vector<uint32_t>* path) {
path->push_back(id);
bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>& visited,
std::vector<uint32_t>& path) {
path.push_back(id);
if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) {
return true;
}
if ((*visited)[id] != 0) {
path->pop_back();
if (visited[id] != 0) {
path.pop_back();
return false;
}
(*visited)[id] = 1;
visited[id] = 1;
const auto& value = provenance.values[id];
if (value.op == ScalarValueOp::Phi) {
for (const auto arg: value.phi_args) {
@@ -100,7 +101,7 @@ bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vecto
return true;
}
}
path->pop_back();
path.pop_back();
return false;
}
const auto args = ScalarValueArgCount(value.op);
@@ -109,19 +110,19 @@ bool ContainsUnknown(const ScalarProvenance& provenance, uint32_t id, std::vecto
return true;
}
}
path->pop_back();
path.pop_back();
return false;
}
bool IsLoopInvariantValue(const ScalarProvenance& provenance, uint32_t id,
std::vector<uint8_t>* visiting) {
std::vector<uint8_t>& visiting) {
if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) {
return false;
}
if ((*visiting)[id] != 0) {
if (visiting[id] != 0) {
return true;
}
(*visiting)[id] = 1;
visiting[id] = 1;
const auto& value = provenance.values[id];
if (value.op == ScalarValueOp::Phi) {
uint32_t invariant = ScalarProvenance::Undefined;
@@ -150,7 +151,7 @@ bool IsLoopInvariantDescriptor(const ScalarProvenance& provenance,
const DescriptorValue& descriptor) {
std::vector<uint8_t> visiting(provenance.values.size());
for (uint32_t i = 0; i < descriptor.dword_count; i++) {
if (!IsLoopInvariantValue(provenance, descriptor.dwords[i], &visiting)) {
if (!IsLoopInvariantValue(provenance, descriptor.dwords[i], visiting)) {
return false;
}
}
@@ -173,7 +174,7 @@ public:
}
for (auto& block: m_program.blocks) {
for (auto& inst: block.instructions) {
if (!Collect(&inst, error)) {
if (!Collect(inst, error)) {
return false;
}
}
@@ -181,10 +182,11 @@ public:
LinkImageAliases();
m_program.info = std::move(m_info);
for (const auto& patch: m_patches) {
patch.inst->memory.resource = patch.resource;
patch.inst->memory.sampler = patch.sampler;
patch.inst->memory.resource_source = ScalarProvenance::Undefined;
patch.inst->memory.sampler_source = ScalarProvenance::Undefined;
auto& inst = patch.inst.get();
inst.memory.resource = patch.resource;
inst.memory.sampler = patch.sampler;
inst.memory.resource_source = ScalarProvenance::Undefined;
inst.memory.sampler_source = ScalarProvenance::Undefined;
}
m_program.resource_tracking_complete = true;
return true;
@@ -192,7 +194,7 @@ public:
private:
struct Patch {
Instruction* inst = nullptr;
std::reference_wrapper<Instruction> inst;
uint32_t resource = 0;
uint32_t sampler = 0;
};
@@ -214,7 +216,7 @@ private:
std::vector<uint8_t> visited(m_program.provenance.values.size());
for (uint32_t i = 0; i < descriptor->dword_count; i++) {
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];
std::string chain;
for (const auto id: path) {
@@ -400,50 +402,49 @@ private:
return true;
}
bool Collect(Instruction* inst, std::string* error) {
if (IsAddress(*inst)) {
const bool unbased = inst->memory.resource_source == ScalarProvenance::Unknown;
if ((!unbased && !ValidateSource(inst->memory.resource_source, 2, inst->pc, error)) ||
(unbased && inst->memory.kind != ResourceKind::Flat &&
inst->memory.kind != ResourceKind::Global &&
inst->memory.kind != ResourceKind::Scratch)) {
return unbased ? Fail(inst->pc, error, "scalar memory base is unresolved") : false;
bool Collect(Instruction& inst, std::string* error) {
if (IsAddress(inst)) {
const bool unbased = inst.memory.resource_source == ScalarProvenance::Unknown;
if ((!unbased && !ValidateSource(inst.memory.resource_source, 2, inst.pc, error)) ||
(unbased && inst.memory.kind != ResourceKind::Flat &&
inst.memory.kind != ResourceKind::Global &&
inst.memory.kind != ResourceKind::Scratch)) {
return unbased ? Fail(inst.pc, error, "scalar memory base is unresolved") : false;
}
const auto resource = AddAddress(*inst);
const auto resource = AddAddress(inst);
if (resource == UINT32_MAX) {
return Fail(inst->pc, error, "address resource limit exceeded");
return Fail(inst.pc, error, "address resource limit exceeded");
}
m_patches.push_back({inst, resource, 0});
m_patches.push_back({std::ref(inst), resource, 0});
return true;
}
if (!IsBuffer(*inst) && !IsImage(*inst)) {
if (!IsBuffer(inst) && !IsImage(inst)) {
return true;
}
if (!ValidateSource(inst->memory.resource_source, IsBuffer(*inst) ? 4u : 8u, inst->pc,
if (!ValidateSource(inst.memory.resource_source, IsBuffer(inst) ? 4u : 8u, inst.pc,
error)) {
return false;
}
Patch patch;
patch.inst = inst;
patch.resource = IsBuffer(*inst) ? AddBuffer(*inst) : AddImage(*inst);
if (patch.resource == UINT32_MAX) {
return Fail(inst->pc, error,
IsBuffer(*inst) ? "buffer resource limit exceeded"
const auto resource = IsBuffer(inst) ? AddBuffer(inst) : AddImage(inst);
if (resource == UINT32_MAX) {
return Fail(inst.pc, error,
IsBuffer(inst) ? "buffer resource limit exceeded"
: "image resource limit exceeded");
}
if (NeedsSampler(inst->op)) {
if (!ValidateSource(inst->memory.sampler_source, 4, inst->pc, error)) {
uint32_t sampler = 0;
if (NeedsSampler(inst.op)) {
if (!ValidateSource(inst.memory.sampler_source, 4, inst.pc, error)) {
return false;
}
patch.sampler = AddSampler(*inst);
if (patch.sampler == UINT32_MAX) {
return Fail(inst->pc, error, "sampler resource limit exceeded");
sampler = AddSampler(inst);
if (sampler == UINT32_MAX) {
return Fail(inst.pc, error, "sampler resource limit exceeded");
}
if (!AddSampledPair(patch.resource, patch.sampler, inst->pc, error)) {
if (!AddSampledPair(resource, sampler, inst.pc, error)) {
return false;
}
}
m_patches.push_back(patch);
m_patches.push_back({std::ref(inst), resource, sampler});
return true;
}
@@ -454,15 +455,8 @@ private:
} // namespace
bool TrackResources(Program* program, std::string* error) {
if (program == nullptr) {
if (error != nullptr) {
*error = "shader resource tracking: hash=0x0000000000000000 stage=unknown "
"pc=0x00000000 invalid program";
}
return false;
}
return Tracker(*program).Run(error);
bool TrackResources(Program& program, std::string* error) {
return Tracker(program).Run(error);
}
} // namespace Libs::Graphics::ShaderRecompiler::IR
@@ -7,7 +7,7 @@ namespace Libs::Graphics::ShaderRecompiler::IR {
// Collects immutable resource topology, then replaces descriptor operands with dense indices.
// On failure the program is left unpatched.
bool TrackResources(Program* program, std::string* error);
bool TrackResources(Program& program, std::string* error);
} // namespace Libs::Graphics::ShaderRecompiler::IR
+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,
Instruction* inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) {
if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error) ||
!DecodeScalarSource(ssrc1, pc, &inst->src1, error)) {
Instruction& inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) {
if (!DecodeScalarSource(ssrc0, pc, inst.src0, error) ||
!DecodeScalarSource(ssrc1, pc, inst.src1, error)) {
return false;
}
inst->src_count = 2;
inst.src_count = 2;
return ReadLiteralOperands(code, word_index, inst, error);
}
} // namespace
bool DecodeSop1(uint32_t pc, std::span<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) {
const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 8u) & 0xffu;
const uint32_t ssrc0 = word & 0xffu;
const uint32_t sdst = (word >> 16u) & 0x7fu;
inst->pc = pc;
inst->word = word;
inst->family = Family::SOP1;
inst->opcode_id = opcode;
inst->opcode = Lookup(SOP1_OPS, static_cast<uint32_t>(std::size(SOP1_OPS)), opcode);
inst.pc = pc;
inst.word = word;
inst.family = Family::SOP1;
inst.opcode_id = opcode;
inst.opcode = Lookup(SOP1_OPS, static_cast<uint32_t>(std::size(SOP1_OPS)), opcode);
SetRawWords(inst, code, word_index, 1);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
SetUnsupported(inst, Family::SOP1, opcode, "SOP1 opcode is not implemented");
return true;
}
switch (inst->opcode) {
switch (inst.opcode) {
case Opcode::SGetpcB64:
inst->src_count = 0;
return DecodeScalarDestination(sdst, pc, &inst->dst, error);
inst.src_count = 0;
return DecodeScalarDestination(sdst, pc, inst.dst, error);
case Opcode::SSetpcB64:
inst->src_count = 1;
inst->dst.kind = OperandKind::Null;
if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error)) {
inst.src_count = 1;
inst.dst.kind = OperandKind::Null;
if (!DecodeScalarSource(ssrc0, pc, inst.src0, error)) {
return false;
}
return ReadLiteralOperands(code, word_index, inst, error);
default: break;
}
if (!DecodeScalarSource(ssrc0, pc, &inst->src0, error) ||
!DecodeScalarDestination(sdst, pc, &inst->dst, error)) {
if (!DecodeScalarSource(ssrc0, pc, inst.src0, error) ||
!DecodeScalarDestination(sdst, pc, inst.dst, error)) {
return false;
}
inst->src_count = 1;
inst.src_count = 1;
return ReadLiteralOperands(code, word_index, inst, error);
}
bool DecodeSop2(uint32_t pc, std::span<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) {
const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 23u) & 0x7fu;
@@ -149,25 +149,25 @@ bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
const uint32_t ssrc0 = word & 0xffu;
const uint32_t sdst = (word >> 16u) & 0x7fu;
inst->pc = pc;
inst->word = word;
inst->family = Family::SOP2;
inst->opcode_id = opcode;
inst->opcode = Lookup(SOP2_OPS, static_cast<uint32_t>(std::size(SOP2_OPS)), opcode);
inst.pc = pc;
inst.word = word;
inst.family = Family::SOP2;
inst.opcode_id = opcode;
inst.opcode = Lookup(SOP2_OPS, static_cast<uint32_t>(std::size(SOP2_OPS)), opcode);
SetRawWords(inst, code, word_index, 1);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
SetUnsupported(inst, Family::SOP2, opcode, "SOP2 opcode is not implemented");
return true;
}
if (!DecodeScalarDestination(sdst, pc, &inst->dst, error)) {
if (!DecodeScalarDestination(sdst, pc, inst.dst, error)) {
return false;
}
return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error);
}
bool DecodeSopk(uint32_t pc, std::span<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) {
const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 23u) & 0x1fu;
@@ -176,72 +176,72 @@ bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
(void)error;
inst->pc = pc;
inst->word = word;
inst->family = Family::SOPK;
inst->opcode_id = opcode;
inst->opcode = Lookup(SOPK_OPS, static_cast<uint32_t>(std::size(SOPK_OPS)), opcode);
inst->src0.kind = OperandKind::IntegerInlineConstant;
inst->src0.signed_val = imm;
inst->src0.value = static_cast<uint32_t>(imm);
inst->src_count = 1;
inst.pc = pc;
inst.word = word;
inst.family = Family::SOPK;
inst.opcode_id = opcode;
inst.opcode = Lookup(SOPK_OPS, static_cast<uint32_t>(std::size(SOPK_OPS)), opcode);
inst.src0.kind = OperandKind::IntegerInlineConstant;
inst.src0.signed_val = imm;
inst.src0.value = static_cast<uint32_t>(imm);
inst.src_count = 1;
SetRawWords(inst, code, word_index, 1);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
SetUnsupported(inst, Family::SOPK, opcode, "SOPK opcode is not implemented");
return true;
}
switch (inst->opcode) {
case Opcode::SMovkI32: return DecodeScalarDestination(sdst, pc, &inst->dst, error);
switch (inst.opcode) {
case Opcode::SMovkI32: return DecodeScalarDestination(sdst, pc, inst.dst, error);
case Opcode::SWaitcnt: {
const uint32_t waitcnt = word & 0xffffu;
inst->dst.kind = OperandKind::Null;
inst->src0.signed_val = static_cast<int32_t>(waitcnt);
inst->src0.value = waitcnt;
inst->src_count = 1;
inst.dst.kind = OperandKind::Null;
inst.src0.signed_val = static_cast<int32_t>(waitcnt);
inst.src0.value = waitcnt;
inst.src_count = 1;
return true;
}
case Opcode::SSetregB32:
inst->dst.kind = OperandKind::Null;
inst->src1.kind = OperandKind::LiteralConstant;
inst->src1.value = word & 0xffffu;
inst->src1.signed_val = static_cast<int32_t>(imm);
inst->src_count = 2;
return DecodeScalarSource(sdst, pc, &inst->src0, error);
inst.dst.kind = OperandKind::Null;
inst.src1.kind = OperandKind::LiteralConstant;
inst.src1.value = word & 0xffffu;
inst.src1.signed_val = static_cast<int32_t>(imm);
inst.src_count = 2;
return DecodeScalarSource(sdst, pc, inst.src0, error);
default: break;
}
inst->src1 = inst->src0;
if (!DecodeScalarSource(sdst, pc, &inst->src0, error)) {
inst.src1 = inst.src0;
if (!DecodeScalarSource(sdst, pc, inst.src0, error)) {
return false;
}
if (inst->opcode == Opcode::SAddI32 || inst->opcode == Opcode::SMulkI32) {
inst->src_count = 2;
return DecodeScalarDestination(sdst, pc, &inst->dst, error);
if (inst.opcode == Opcode::SAddI32 || inst.opcode == Opcode::SMulkI32) {
inst.src_count = 2;
return DecodeScalarDestination(sdst, pc, inst.dst, error);
}
inst->dst.kind = OperandKind::Scc;
inst->src_count = 2;
inst.dst.kind = OperandKind::Scc;
inst.src_count = 2;
return true;
}
bool DecodeSopc(uint32_t pc, std::span<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) {
const uint32_t word = code[word_index];
const uint32_t ssrc1 = (word >> 8u) & 0xffu;
const uint32_t ssrc0 = word & 0xffu;
const uint32_t opcode = (word >> 16u) & 0x7fu;
inst->pc = pc;
inst->word = word;
inst->family = Family::SOPC;
inst->opcode_id = opcode;
inst->opcode = Lookup(SOPC_OPS, static_cast<uint32_t>(std::size(SOPC_OPS)), opcode);
inst->dst.kind = OperandKind::Scc;
inst.pc = pc;
inst.word = word;
inst.family = Family::SOPC;
inst.opcode_id = opcode;
inst.opcode = Lookup(SOPC_OPS, static_cast<uint32_t>(std::size(SOPC_OPS)), opcode);
inst.dst.kind = OperandKind::Scc;
SetRawWords(inst, code, word_index, 1);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
SetUnsupported(inst, Family::SOPC, opcode, "SOPC opcode is not implemented");
return true;
}
@@ -249,7 +249,7 @@ bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
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) {
const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 16u) & 0x7fu;
@@ -257,24 +257,24 @@ bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
(void)error;
inst->pc = pc;
inst->word = word;
inst->family = Family::SOPP;
inst->opcode_id = opcode;
inst->opcode = Lookup(SOPP_OPS, static_cast<uint32_t>(std::size(SOPP_OPS)), opcode);
inst->src0.kind = OperandKind::LiteralConstant;
inst->src0.value = simm;
inst->src0.signed_val = static_cast<int16_t>(simm);
inst->src_count = (inst->opcode == Opcode::SNop || inst->opcode == Opcode::SWaitcnt ||
inst->opcode == Opcode::SSleep || inst->opcode == Opcode::SSendmsg ||
inst->opcode == Opcode::STtraceData || inst->opcode == Opcode::SInstPrefetch)
inst.pc = pc;
inst.word = word;
inst.family = Family::SOPP;
inst.opcode_id = opcode;
inst.opcode = Lookup(SOPP_OPS, static_cast<uint32_t>(std::size(SOPP_OPS)), opcode);
inst.src0.kind = OperandKind::LiteralConstant;
inst.src0.value = simm;
inst.src0.signed_val = static_cast<int16_t>(simm);
inst.src_count = (inst.opcode == Opcode::SNop || inst.opcode == Opcode::SWaitcnt ||
inst.opcode == Opcode::SSleep || inst.opcode == Opcode::SSendmsg ||
inst.opcode == Opcode::STtraceData || inst.opcode == Opcode::SInstPrefetch)
? 1
: 0;
inst->branch_offset = static_cast<int32_t>(static_cast<int16_t>(simm)) * 4;
inst->branch_target = pc + 4u + static_cast<uint32_t>(inst->branch_offset);
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);
SetRawWords(inst, code, word_index, 1);
if (inst->opcode == Opcode::Unsupported) {
if (inst.opcode == Opcode::Unsupported) {
SetUnsupported(inst, Family::SOPP, opcode, "SOPP control-flow opcode is not implemented");
}
return true;
@@ -5,15 +5,15 @@
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);
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);
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);
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);
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);
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
@@ -140,20 +140,20 @@ bool ScalarMemoryLoad(Opcode op) {
return op == Opcode::SLoadDword || op == Opcode::SBufferLoadDword;
}
bool ValueResolved(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>* visited) {
bool ValueResolved(const ScalarProvenance& provenance, uint32_t id, std::vector<uint8_t>& visited) {
if (id <= ScalarProvenance::Unknown || id >= provenance.values.size()) {
return false;
}
if ((*visited)[id] == 1) {
if (visited[id] == 1) {
return false;
}
if ((*visited)[id] == 2) {
if (visited[id] == 2) {
return true;
}
if ((*visited)[id] == 3) {
if (visited[id] == 3) {
return false;
}
(*visited)[id] = 1;
visited[id] = 1;
const auto& value = provenance.values[id];
bool resolved = true;
if (value.op == ScalarValueOp::Phi) {
@@ -167,13 +167,13 @@ bool ValueResolved(const ScalarProvenance& provenance, uint32_t id, std::vector<
resolved = ValueResolved(provenance, value.args[i], visited);
}
}
(*visited)[id] = resolved ? 2 : 3;
visited[id] = resolved ? 2 : 3;
return resolved;
}
class Builder {
public:
explicit Builder(Program* program): m_program(program), m_graph(program->provenance) {}
explicit Builder(Program& program): m_program(program), m_graph(program.provenance) {}
bool Run(std::string* error) {
m_graph = {};
@@ -181,7 +181,7 @@ public:
m_graph.values[ScalarProvenance::Undefined].op = ScalarValueOp::Undefined;
m_graph.values[ScalarProvenance::Unknown].op = ScalarValueOp::Unknown;
const auto block_count = m_program->blocks.size();
const auto block_count = m_program.blocks.size();
m_entry.resize(block_count);
m_exit.resize(block_count);
m_phi.resize(block_count);
@@ -200,8 +200,8 @@ public:
m_user_data.Fill(ScalarProvenance::Undefined);
for (uint32_t reg = 0; reg < ScalarRegisters; reg++) {
m_user_data.regs[reg] =
reg >= m_program->user_data_base &&
reg - m_program->user_data_base < m_program->user_data_count
reg >= m_program.user_data_base &&
reg - m_program.user_data_base < m_program.user_data_count
? InternValue({ScalarValueOp::UserData, 0, reg})
: ScalarProvenance::Unknown;
}
@@ -211,7 +211,7 @@ public:
if (block_count == 0) {
return true;
}
for (const auto& block: m_program->blocks) {
for (const auto& block: m_program.blocks) {
for (const auto predecessor: block.predecessors) {
if (predecessor >= block_count) {
return Fail(error, fmt::format("scalar provenance has invalid predecessor {}",
@@ -238,20 +238,20 @@ public:
const bool entry_changed = next_entry != m_entry[block_index];
m_entry[block_index] = next_entry;
auto next_exit = Execute(m_program->blocks[block_index], next_entry, false);
auto next_exit = Execute(m_program.blocks[block_index], next_entry, false);
const bool was_ready = m_exit_ready[block_index];
if (was_ready && !entry_changed && next_exit == m_exit[block_index]) {
continue;
}
m_exit[block_index] = next_exit;
m_exit_ready[block_index] = true;
for (const auto successor: m_program->blocks[block_index].successors) {
for (const auto successor: m_program.blocks[block_index].successors) {
Queue(successor);
}
}
for (size_t block = 0; block < block_count; block++) {
Execute(m_program->blocks[block], m_entry[block], true);
Execute(m_program.blocks[block], m_entry[block], true);
}
return true;
}
@@ -366,40 +366,37 @@ private:
return InternValue(std::move(node));
}
bool ConstantOperand(const Operand& operand, const ScalarState& state, uint32_t* value) {
if (value == nullptr) {
return false;
}
bool ConstantOperand(const Operand& operand, const ScalarState& state, uint32_t& value) {
const auto id = OperandValue(operand, state);
if (id >= m_graph.values.size() || m_graph.values[id].op != ScalarValueOp::Constant) {
return false;
}
*value = m_graph.values[id].imm;
value = m_graph.values[id].imm;
return true;
}
uint32_t ReadVectorLane(const Instruction& inst, const ScalarState& state) {
if (inst.src_count < 2 || inst.src[0].kind != OperandKind::Register ||
inst.src[0].reg.file != RegisterFile::Vector ||
(m_program->wave_size != 32 && m_program->wave_size != 64)) {
(m_program.wave_size != 32 && m_program.wave_size != 64)) {
return ScalarProvenance::Unknown;
}
uint32_t lane = 0;
if (!ConstantOperand(inst.src[1], state, &lane)) {
if (!ConstantOperand(inst.src[1], state, lane)) {
return ScalarProvenance::Unknown;
}
const auto found = state.vector_lanes.find(
VectorLaneKey(inst.src[0].reg.index, lane % m_program->wave_size));
VectorLaneKey(inst.src[0].reg.index, lane % m_program.wave_size));
return found != state.vector_lanes.end() ? found->second : ScalarProvenance::Unknown;
}
void ClearVectorLanes(uint32_t reg, ScalarState* state) {
const auto first = state->vector_lanes.lower_bound(VectorLaneKey(reg, 0));
const auto last = state->vector_lanes.lower_bound((static_cast<uint64_t>(reg) + 1u) << 32u);
state->vector_lanes.erase(first, last);
void ClearVectorLanes(uint32_t reg, ScalarState& state) {
const auto first = state.vector_lanes.lower_bound(VectorLaneKey(reg, 0));
const auto last = state.vector_lanes.lower_bound((static_cast<uint64_t>(reg) + 1u) << 32u);
state.vector_lanes.erase(first, last);
}
void WriteVectorDestination(const Instruction& inst, ScalarState* state) {
void WriteVectorDestination(const Instruction& inst, ScalarState& state) {
if (inst.dst.kind != OperandKind::Register || inst.dst.reg.file != RegisterFile::Vector) {
return;
}
@@ -410,8 +407,8 @@ private:
for (uint32_t i = 0; i < inst.src_count; i++) {
uint32_t src_reg = 0;
if (VectorRegister(inst.src[i], src_reg) &&
state->address_bases[src_reg] > ScalarProvenance::Unknown) {
address_base = state->address_bases[src_reg];
state.address_bases[src_reg] > ScalarProvenance::Unknown) {
address_base = state.address_bases[src_reg];
break;
}
}
@@ -419,16 +416,16 @@ private:
for (uint32_t i = 0; i < inst.src_count; i++) {
uint32_t src_reg = 0;
if (ScalarRegister(inst.src[i], src_reg) &&
state->regs[src_reg] > ScalarProvenance::Unknown) {
address_base = state->regs[src_reg];
state.regs[src_reg] > ScalarProvenance::Unknown) {
address_base = state.regs[src_reg];
break;
}
}
}
}
state->address_bases[reg] = ScalarProvenance::Unknown;
state.address_bases[reg] = ScalarProvenance::Unknown;
if (inst.op == Opcode::MoveRelDestU32) {
state->vector_lanes.clear();
state.vector_lanes.clear();
return;
}
if (inst.op != Opcode::WriteLaneU32) {
@@ -438,24 +435,24 @@ private:
}
for (uint32_t i = 0; i < dwords && reg <= UINT32_MAX - i; i++) {
ClearVectorLanes(reg + i, state);
if (reg + i < state->address_bases.size()) {
state->address_bases[reg + i] = ScalarProvenance::Unknown;
if (reg + i < state.address_bases.size()) {
state.address_bases[reg + i] = ScalarProvenance::Unknown;
}
}
state->address_bases[reg] = address_base;
state.address_bases[reg] = address_base;
return;
}
if (inst.src_count < 2 || (m_program->wave_size != 32 && m_program->wave_size != 64)) {
if (inst.src_count < 2 || (m_program.wave_size != 32 && m_program.wave_size != 64)) {
ClearVectorLanes(reg, state);
return;
}
uint32_t lane = 0;
if (!ConstantOperand(inst.src[1], *state, &lane)) {
if (!ConstantOperand(inst.src[1], state, lane)) {
ClearVectorLanes(reg, state);
return;
}
state->vector_lanes[VectorLaneKey(reg, lane % m_program->wave_size)] =
OperandValue(inst.src[0], *state);
state.vector_lanes[VectorLaneKey(reg, lane % m_program.wave_size)] =
OperandValue(inst.src[0], state);
}
uint32_t ReadConst(const Instruction& inst, const ScalarState& state, bool buffer) {
@@ -514,31 +511,31 @@ private:
}
}
void UpdateScc(const Instruction& inst, const ScalarState& before, ScalarState* state) {
void UpdateScc(const Instruction& inst, const ScalarState& before, ScalarState& state) {
switch (inst.op) {
case Opcode::ScalarAddCarryU32:
state->scc = Define(inst, ScalarValueOp::Carry, before);
state.scc = Define(inst, ScalarValueOp::Carry, before);
break;
case Opcode::ScalarSubBorrowU32:
case Opcode::ScalarSubBorrowCarryU32: state->scc = DefineBorrow(inst, before); break;
case Opcode::ScalarSubBorrowCarryU32: state.scc = DefineBorrow(inst, before); break;
case Opcode::ScalarShiftLeftAddCarryU32:
state->scc = Define(inst, ScalarValueOp::ShiftLeftAddCarry, before);
state.scc = Define(inst, ScalarValueOp::ShiftLeftAddCarry, before);
break;
default: break;
}
}
void WriteDestination(const Instruction& inst, ScalarState* state) {
void WriteDestination(const Instruction& inst, ScalarState& state) {
if (inst.dst.kind == OperandKind::Register && inst.dst.reg.file == RegisterFile::Scc) {
state->scc = inst.op == Opcode::MoveU32 && inst.src_count != 0
? OperandValue(inst.src[0], *state)
state.scc = inst.op == Opcode::MoveU32 && inst.src_count != 0
? OperandValue(inst.src[0], state)
: ScalarProvenance::Unknown;
return;
}
if (inst.dst.kind == OperandKind::Register && inst.dst.reg.file == RegisterFile::M0) {
const auto before = *state;
const auto before = state;
const auto op = Operation(inst.op);
state->m0 = inst.op == Opcode::MoveU32 && inst.src_count != 0
state.m0 = inst.op == Opcode::MoveU32 && inst.src_count != 0
? OperandValue(inst.src[0], before)
: op != ScalarValueOp::Unknown ? Define(inst, op, before)
: ScalarProvenance::Unknown;
@@ -551,10 +548,10 @@ private:
return;
}
const auto before = *state;
state->regs[dst] = ScalarProvenance::Unknown;
const auto before = state;
state.regs[dst] = ScalarProvenance::Unknown;
if (PairDwordOpcode(inst.op) && dst + 1 < ScalarRegisters) {
state->regs[dst + 1] = ScalarProvenance::Unknown;
state.regs[dst + 1] = ScalarProvenance::Unknown;
}
uint32_t value = ScalarProvenance::Unknown;
@@ -582,10 +579,10 @@ private:
if (inst.src_count != 0 && dst + 1 < ScalarRegisters) {
if (ScalarRegister(inst.src[0], src) && src + 1 < ScalarRegisters) {
value = before.regs[src];
state->regs[dst + 1] = before.regs[src + 1];
state.regs[dst + 1] = before.regs[src + 1];
} else {
value = OperandValue(inst.src[0], before);
state->regs[dst + 1] = Constant(
state.regs[dst + 1] = Constant(
inst.src[0].kind == OperandKind::ImmediateU32 && inst.src[0].sext_64
? UINT32_MAX
: 0u);
@@ -596,7 +593,7 @@ private:
case Opcode::BitFieldMaskU64:
value = Define(inst, ScalarValueOp::BitFieldMaskU64Low, before);
if (dst + 1 < ScalarRegisters) {
state->regs[dst + 1] = Define(inst, ScalarValueOp::BitFieldMaskU64High, before);
state.regs[dst + 1] = Define(inst, ScalarValueOp::BitFieldMaskU64High, before);
}
break;
case Opcode::SLoadDword: value = ReadConst(inst, before, false); break;
@@ -610,12 +607,12 @@ private:
break;
}
}
state->regs[dst] = value;
state.regs[dst] = value;
UpdateScc(inst, before, state);
uint32_t dst2 = 0;
if (ScalarRegister(inst.dst2, dst2)) {
state->regs[dst2] =
state.regs[dst2] =
inst.src_count > 1 ? OperandValue(inst.src[1], before) : ScalarProvenance::Unknown;
}
}
@@ -663,57 +660,57 @@ private:
return AddDescriptor(descriptor);
}
void AttachSources(Instruction* inst, const ScalarState& state) {
inst->memory.resource_source = 0;
inst->memory.sampler_source = 0;
if (inst->op == Opcode::SLoadDword) {
inst->memory.resource_source = AddDescriptor(state, inst->memory.resource, 2);
void AttachSources(Instruction& inst, const ScalarState& state) {
inst.memory.resource_source = 0;
inst.memory.sampler_source = 0;
if (inst.op == Opcode::SLoadDword) {
inst.memory.resource_source = AddDescriptor(state, inst.memory.resource, 2);
return;
}
if (inst->memory.kind == ResourceKind::Flat || inst->memory.kind == ResourceKind::Global ||
inst->memory.kind == ResourceKind::Scratch) {
inst->memory.resource_source = ScalarProvenance::Unknown;
if (inst->memory.kind == ResourceKind::Flat) {
inst->memory.resource_source = AddFlatAddressDescriptor(*inst, state);
if (inst.memory.kind == ResourceKind::Flat || inst.memory.kind == ResourceKind::Global ||
inst.memory.kind == ResourceKind::Scratch) {
inst.memory.resource_source = ScalarProvenance::Unknown;
if (inst.memory.kind == ResourceKind::Flat) {
inst.memory.resource_source = AddFlatAddressDescriptor(inst, state);
}
for (uint32_t i = 0; i < inst->src_count; i++) {
const auto& source = inst->src[i];
if (inst->memory.resource_source == ScalarProvenance::Unknown &&
for (uint32_t i = 0; i < inst.src_count; i++) {
const auto& source = inst.src[i];
if (inst.memory.resource_source == ScalarProvenance::Unknown &&
source.kind == OperandKind::Register &&
source.reg.file == RegisterFile::Scalar) {
inst->memory.resource_source = AddDescriptor(state, source.reg.index, 2);
inst.memory.resource_source = AddDescriptor(state, source.reg.index, 2);
break;
}
}
return;
}
if (inst->memory.kind == ResourceKind::Buffer ||
(inst->memory.kind == ResourceKind::ScalarBuffer &&
inst->op == Opcode::SBufferLoadDword)) {
const auto base = inst->memory.resource * 4u;
inst->memory.resource_source = AddDescriptor(state, base, 4);
if (inst.memory.kind == ResourceKind::Buffer ||
(inst.memory.kind == ResourceKind::ScalarBuffer &&
inst.op == Opcode::SBufferLoadDword)) {
const auto base = inst.memory.resource * 4u;
inst.memory.resource_source = AddDescriptor(state, base, 4);
return;
}
if (inst->memory.kind == ResourceKind::Image ||
inst->memory.kind == ResourceKind::ImageUint ||
inst->memory.kind == ResourceKind::StorageImage ||
inst->memory.kind == ResourceKind::StorageImageUint) {
inst->memory.resource_source = AddDescriptor(state, inst->memory.resource * 4u, 8);
if (inst->op == Opcode::ImageSample || inst->op == Opcode::ImageGather4 ||
inst->op == Opcode::ImageGetLod) {
inst->memory.sampler_source = AddDescriptor(state, inst->memory.sampler * 4u, 4);
if (inst.memory.kind == ResourceKind::Image ||
inst.memory.kind == ResourceKind::ImageUint ||
inst.memory.kind == ResourceKind::StorageImage ||
inst.memory.kind == ResourceKind::StorageImageUint) {
inst.memory.resource_source = AddDescriptor(state, inst.memory.resource * 4u, 8);
if (inst.op == Opcode::ImageSample || inst.op == Opcode::ImageGather4 ||
inst.op == Opcode::ImageGetLod) {
inst.memory.sampler_source = AddDescriptor(state, inst.memory.sampler * 4u, 4);
}
}
}
void AttachScalarSources(Instruction* inst, const ScalarState& state) {
std::fill(std::begin(inst->scalar_sources), std::end(inst->scalar_sources),
void AttachScalarSources(Instruction& inst, const ScalarState& state) {
std::fill(std::begin(inst.scalar_sources), std::end(inst.scalar_sources),
ScalarProvenance::Undefined);
for (uint32_t i = 0; i < inst->src_count; i++) {
const auto& source = inst->src[i];
for (uint32_t i = 0; i < inst.src_count; i++) {
const auto& source = inst.src[i];
if (source.kind == OperandKind::Register && source.reg.file != RegisterFile::Vector &&
source.reg.file != RegisterFile::Exec) {
inst->scalar_sources[i] = OperandValue(source, state);
inst.scalar_sources[i] = OperandValue(source, state);
}
}
}
@@ -729,11 +726,11 @@ private:
auto& component_inst = block.instructions[index + component];
if (attach_sources) {
component_inst.scalar_value = ScalarProvenance::Undefined;
AttachScalarSources(&component_inst, before);
AttachSources(&component_inst, before);
AttachScalarSources(component_inst, before);
AttachSources(component_inst, before);
}
auto component_state = before;
WriteDestination(component_inst, &component_state);
WriteDestination(component_inst, component_state);
uint32_t dst = 0;
ScalarRegister(component_inst.dst, dst);
state.regs[dst] = component_state.regs[dst];
@@ -746,11 +743,11 @@ private:
}
if (attach_sources) {
inst.scalar_value = ScalarProvenance::Undefined;
AttachScalarSources(&inst, state);
AttachSources(&inst, state);
AttachScalarSources(inst, state);
AttachSources(inst, state);
}
WriteVectorDestination(inst, &state);
WriteDestination(inst, &state);
WriteVectorDestination(inst, state);
WriteDestination(inst, state);
if (attach_sources) {
uint32_t dst = 0;
if (ScalarRegister(inst.dst, dst)) {
@@ -765,7 +762,7 @@ private:
ScalarState MergeEntry(size_t block_index) {
ScalarState result;
result.Fill(ScalarProvenance::Undefined);
const auto& block = m_program->blocks[block_index];
const auto& block = m_program.blocks[block_index];
const auto merge = [&](uint32_t initial, auto predecessor_value, uint32_t* phi) {
std::vector<uint32_t> incoming;
if (initial != ScalarProvenance::Undefined) {
@@ -845,7 +842,7 @@ private:
}
}
Program* m_program;
Program& m_program;
ScalarProvenance& m_graph;
ScalarState m_user_data;
std::vector<ScalarState> m_entry;
@@ -860,40 +857,34 @@ private:
} // namespace
bool BuildScalarProvenance(Program* program, std::string* error) {
if (program == nullptr) {
if (error != nullptr) {
*error = "invalid scalar provenance program";
}
return false;
}
if (program->resource_tracking_complete) {
bool BuildScalarProvenance(Program& program, std::string* error) {
if (program.resource_tracking_complete) {
if (error != nullptr) {
*error = "cannot rebuild scalar provenance after resource tracking";
}
return false;
}
if (program->user_data_count > 64) {
if (program.user_data_count > 64) {
if (error != nullptr) {
*error = "scalar provenance user-data count exceeds 64 SGPRs";
}
return false;
}
if (program->user_data_base > ScalarRegisters ||
program->user_data_count > ScalarRegisters - program->user_data_base) {
if (program.user_data_base > ScalarRegisters ||
program.user_data_count > ScalarRegisters - program.user_data_base) {
if (error != nullptr) {
*error = "scalar provenance user-data window is out of range";
}
return false;
}
if (program->srt_patching_complete) {
if (program.srt_patching_complete) {
if (error != nullptr) {
*error = "cannot rebuild scalar provenance after SRT patching";
}
return false;
}
program->srt = {};
program->srt_plan_complete = false;
program.srt = {};
program.srt_plan_complete = false;
return Builder(program).Run(error);
}
@@ -911,7 +902,7 @@ bool DescriptorSourceResolved(const Program& program, uint32_t source) {
}
std::vector<uint8_t> visited(program.provenance.values.size());
for (uint32_t i = 0; i < descriptor->dword_count; i++) {
if (!ValueResolved(program.provenance, descriptor->dwords[i], &visited)) {
if (!ValueResolved(program.provenance, descriptor->dwords[i], visited)) {
return false;
}
}
@@ -6,7 +6,7 @@
namespace Libs::Graphics::ShaderRecompiler::IR {
// Builds scalar reaching definitions and attaches descriptor sources to individual memory uses.
bool BuildScalarProvenance(Program* program, std::string* error);
bool BuildScalarProvenance(Program& program, std::string* error);
uint32_t ScalarValueArgCount(ScalarValueOp op);
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;
};
bool BuildGraph(const Decoder::Program& program, Graph* graph, std::string* error);
bool Structurize(Graph* graph, std::string* error);
bool BuildGraph(const Decoder::Program& program, Graph& graph, std::string* error);
bool Structurize(Graph& graph, std::string* error);
std::string BranchConditionToString(BranchCondition condition);
std::string FailureKindToString(FailureKind kind);
std::string FormatBlockDiagnostic(const Graph& graph, uint32_t block_id, const char* stage,
+87 -101
View File
@@ -44,10 +44,10 @@ bool IsControlFlowBranch(Opcode opcode) {
}
}
void ApplyLiteral(Operand* operand, uint32_t literal) {
if (operand->kind == OperandKind::LiteralConstant) {
operand->value = literal;
operand->signed_val = static_cast<int32_t>(literal);
void ApplyLiteral(Operand& operand, uint32_t literal) {
if (operand.kind == OperandKind::LiteralConstant) {
operand.value = literal;
operand.signed_val = static_cast<int32_t>(literal);
}
}
@@ -196,36 +196,31 @@ std::string FormatExp(const Instruction& inst) {
} // namespace
bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::string* error) {
if (operand == nullptr) {
SetError(error, "internal decoder error: null source operand");
return false;
}
*operand = {};
bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error) {
operand = {};
if (code <= 105u) {
operand->kind = OperandKind::Sgpr;
operand->reg = code;
operand.kind = OperandKind::Sgpr;
operand.reg = code;
return true;
}
if (code >= 128u && code <= 192u) {
operand->kind = OperandKind::IntegerInlineConstant;
operand->signed_val = static_cast<int32_t>(code - 128u);
operand->value = static_cast<uint32_t>(operand->signed_val);
operand.kind = OperandKind::IntegerInlineConstant;
operand.signed_val = static_cast<int32_t>(code - 128u);
operand.value = static_cast<uint32_t>(operand.signed_val);
return true;
}
if (code >= 193u && code <= 208u) {
operand->kind = OperandKind::IntegerInlineConstant;
operand->signed_val = 192 - static_cast<int32_t>(code);
operand->value = static_cast<uint32_t>(operand->signed_val);
operand.kind = OperandKind::IntegerInlineConstant;
operand.signed_val = 192 - static_cast<int32_t>(code);
operand.value = static_cast<uint32_t>(operand.signed_val);
return true;
}
if (code >= 240u && code <= 247u) {
constexpr float values[] = {0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f, 4.0f, -4.0f};
operand->kind = OperandKind::FloatInlineConstant;
operand->float_val = values[code - 240u];
operand->value = FloatBits(operand->float_val);
operand.kind = OperandKind::FloatInlineConstant;
operand.float_val = values[code - 240u];
operand.value = FloatBits(operand.float_val);
return true;
}
if (code >= 256u && code <= 511u) {
@@ -233,22 +228,22 @@ bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::strin
}
switch (code) {
case 106u: operand->kind = OperandKind::VccLo; return true;
case 107u: operand->kind = OperandKind::VccHi; return true;
case 124u: operand->kind = OperandKind::M0; return true;
case 125u: operand->kind = OperandKind::Null; return true;
case 126u: operand->kind = OperandKind::ExecLo; return true;
case 127u: operand->kind = OperandKind::ExecHi; return true;
case 239u: operand->kind = OperandKind::PopsExitingWaveId; return true;
case 106u: operand.kind = OperandKind::VccLo; return true;
case 107u: operand.kind = OperandKind::VccHi; return true;
case 124u: operand.kind = OperandKind::M0; return true;
case 125u: operand.kind = OperandKind::Null; return true;
case 126u: operand.kind = OperandKind::ExecLo; return true;
case 127u: operand.kind = OperandKind::ExecHi; return true;
case 239u: operand.kind = OperandKind::PopsExitingWaveId; return true;
case 248u:
operand->kind = OperandKind::FloatInlineConstant;
operand->float_val = 0.15915494309189535f;
operand->value = FloatBits(operand->float_val);
operand.kind = OperandKind::FloatInlineConstant;
operand.float_val = 0.15915494309189535f;
operand.value = FloatBits(operand.float_val);
return true;
case 251u: operand->kind = OperandKind::VccZ; return true;
case 252u: operand->kind = OperandKind::ExecZ; return true;
case 253u: operand->kind = OperandKind::Scc; return true;
case 255u: operand->kind = OperandKind::LiteralConstant; return true;
case 251u: operand.kind = OperandKind::VccZ; return true;
case 252u: operand.kind = OperandKind::ExecZ; return true;
case 253u: operand.kind = OperandKind::Scc; return true;
case 255u: operand.kind = OperandKind::LiteralConstant; return true;
default:
if (error != nullptr) {
*error = fmt::format("unsupported scalar source operand 0x{:08x} at pc 0x{:08x}",
@@ -258,27 +253,22 @@ bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand* operand, std::strin
}
}
bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand* operand, std::string* error) {
if (operand == nullptr) {
SetError(error, "internal decoder error: null destination operand");
return false;
}
*operand = {};
bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error) {
operand = {};
if (code <= 105u) {
operand->kind = OperandKind::Sgpr;
operand->reg = code;
operand.kind = OperandKind::Sgpr;
operand.reg = code;
return true;
}
switch (code) {
case 106u: operand->kind = OperandKind::VccLo; return true;
case 107u: operand->kind = OperandKind::VccHi; return true;
case 124u: operand->kind = OperandKind::M0; return true;
case 125u: operand->kind = OperandKind::Null; return true;
case 126u: operand->kind = OperandKind::ExecLo; return true;
case 127u: operand->kind = OperandKind::ExecHi; return true;
case 106u: operand.kind = OperandKind::VccLo; return true;
case 107u: operand.kind = OperandKind::VccHi; return true;
case 124u: operand.kind = OperandKind::M0; return true;
case 125u: operand.kind = OperandKind::Null; return true;
case 126u: operand.kind = OperandKind::ExecLo; return true;
case 127u: operand.kind = OperandKind::ExecHi; return true;
default:
if (error != nullptr) {
*error = fmt::format(
@@ -288,67 +278,63 @@ bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand* operand, std::
}
}
bool DecodeVectorGpr(uint32_t reg, Operand* operand, std::string* error) {
if (operand == nullptr) {
SetError(error, "internal decoder error: null VGPR operand");
return false;
}
bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error) {
if (reg > 255u) {
SetError(error, "VGPR index is out of range");
return false;
}
*operand = {};
operand->kind = OperandKind::Vgpr;
operand->reg = reg;
operand = {};
operand.kind = OperandKind::Vgpr;
operand.reg = reg;
return true;
}
bool ReadLiteralOperands(std::span<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) {
if (!HasLiteral(*inst)) {
if (!HasLiteral(inst)) {
return true;
}
if (word_index + inst->word_count >= code.size()) {
if (word_index + inst.word_count >= code.size()) {
if (error != nullptr) {
*error = fmt::format("missing literal constant at pc 0x{:08x}", inst->pc);
*error = fmt::format("missing literal constant at pc 0x{:08x}", inst.pc);
}
return false;
}
const auto literal = code[word_index + inst->word_count];
ApplyLiteral(&inst->src0, literal);
ApplyLiteral(&inst->src1, literal);
ApplyLiteral(&inst->src2, literal);
ApplyLiteral(&inst->src3, literal);
inst->word_count++;
SetRawWords(inst, code, word_index, inst->word_count);
const auto literal = code[word_index + inst.word_count];
ApplyLiteral(inst.src0, literal);
ApplyLiteral(inst.src1, literal);
ApplyLiteral(inst.src2, literal);
ApplyLiteral(inst.src3, literal);
inst.word_count++;
SetRawWords(inst, code, word_index, inst.word_count);
return true;
}
void SetRawWords(Instruction* inst, std::span<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) {
inst->word_count = word_count;
inst->raw_count = std::min<uint32_t>(word_count, MaxInstructionRawWords);
for (uint32_t i = 0; i < inst->raw_count; i++) {
inst->raw[i] = code[word_index + i];
inst.word_count = word_count;
inst.raw_count = std::min<uint32_t>(word_count, MaxInstructionRawWords);
for (uint32_t i = 0; i < inst.raw_count; i++) {
inst.raw[i] = code[word_index + i];
}
}
void SetUnsupported(Instruction* inst, Family family, uint32_t opcode_id, const char* reason) {
inst->opcode = Opcode::Unsupported;
inst->family = family;
inst->opcode_id = opcode_id;
inst->unsupported_reason = reason;
void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const char* reason) {
inst.opcode = Opcode::Unsupported;
inst.family = family;
inst.opcode_id = opcode_id;
inst.unsupported_reason = reason;
}
bool DecodeProgram(std::span<const uint32_t> code, Program* program, std::string* error) {
if (code.empty() || code.size() > UINT32_MAX / sizeof(uint32_t) || program == nullptr) {
bool DecodeProgram(std::span<const uint32_t> code, Program& program, std::string* error) {
if (code.empty() || code.size() > UINT32_MAX / sizeof(uint32_t)) {
SetError(error, "invalid shader decoder input");
return false;
}
program->instructions.clear();
program->code = code;
program.instructions.clear();
program.code = code;
std::set<uint32_t> branch_targets;
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;
bool ok = false;
if ((word & 0x80000000u) == 0u) {
ok = DecodeVop2(pc, code, word_index, &inst, error);
ok = DecodeVop2(pc, code, word_index, inst, error);
} else if ((word & 0xc0000000u) == 0x80000000u) {
const auto opcode = (word >> 23u) & 0x7fu;
switch (opcode) {
case 0x7du: ok = DecodeSop1(pc, code, word_index, &inst, error); break;
case 0x7eu: ok = DecodeSopc(pc, code, word_index, &inst, error); break;
case 0x7fu: ok = DecodeSopp(pc, code, word_index, &inst, error); break;
case 0x7du: ok = DecodeSop1(pc, code, word_index, inst, error); break;
case 0x7eu: ok = DecodeSopc(pc, code, word_index, inst, error); break;
case 0x7fu: ok = DecodeSopp(pc, code, word_index, inst, error); break;
default:
ok = opcode >= 0x60u ? DecodeSopk(pc, code, word_index, &inst, error)
: DecodeSop2(pc, code, word_index, &inst, error);
ok = opcode >= 0x60u ? DecodeSopk(pc, code, word_index, inst, error)
: DecodeSop2(pc, code, word_index, inst, error);
break;
}
} else {
switch (word >> 26u) {
case 0x32u: ok = DecodeVintrp(pc, code, word_index, &inst, error); break;
case 0x33u: ok = DecodeVop3p(pc, code, word_index, &inst, error); break;
case 0x35u: ok = DecodeVop3(pc, code, word_index, &inst, error); break;
case 0x36u: ok = DecodeDs(pc, code, word_index, &inst, error); break;
case 0x37u: ok = DecodeFlat(pc, code, word_index, &inst, error); break;
case 0x38u: ok = DecodeMubuf(pc, code, word_index, &inst, error); break;
case 0x3au: ok = DecodeMtbuf(pc, code, word_index, &inst, error); break;
case 0x3cu: ok = DecodeMimg(pc, code, word_index, &inst, error); break;
case 0x3du: ok = DecodeSmem(pc, code, word_index, &inst, error); break;
case 0x3eu: ok = DecodeExp(pc, code, word_index, &inst, error); break;
case 0x32u: ok = DecodeVintrp(pc, code, word_index, inst, error); break;
case 0x33u: ok = DecodeVop3p(pc, code, word_index, inst, error); break;
case 0x35u: ok = DecodeVop3(pc, code, word_index, inst, error); break;
case 0x36u: ok = DecodeDs(pc, code, word_index, inst, error); break;
case 0x37u: ok = DecodeFlat(pc, code, word_index, inst, error); break;
case 0x38u: ok = DecodeMubuf(pc, code, word_index, inst, error); break;
case 0x3au: ok = DecodeMtbuf(pc, code, word_index, inst, error); break;
case 0x3cu: ok = DecodeMimg(pc, code, word_index, inst, error); break;
case 0x3du: ok = DecodeSmem(pc, code, word_index, inst, error); break;
case 0x3eu: ok = DecodeExp(pc, code, word_index, inst, error); break;
default:
if (error != nullptr) {
*error = fmt::format(
@@ -396,7 +382,7 @@ bool DecodeProgram(std::span<const uint32_t> code, Program* program, std::string
return false;
}
program->instructions.push_back(inst);
program.instructions.push_back(inst);
word_index += inst.word_count;
if (IsControlFlowBranch(inst.opcode)) {
@@ -656,16 +656,16 @@ struct Program {
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 DecodeScalarDestination(uint32_t code, uint32_t pc, Operand* operand, std::string* error);
bool DecodeVectorGpr(uint32_t reg, Operand* operand, std::string* error);
bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction* inst,
bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error);
bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error);
bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error);
bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
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);
void SetUnsupported(Instruction* inst, Family family, uint32_t opcode_id, const char* reason);
void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const char* reason);
std::string FamilyToString(Family family);
std::string OpcodeToString(Opcode opcode);
std::string OperandToString(const Operand& operand);
+1 -1
View File
@@ -753,7 +753,7 @@ struct Program {
};
bool LowerProgram(const Decoder::Program& decoded, const CFG::Graph& cfg, ShaderType stage,
uint32_t wave_size, Program* program, std::string* error);
uint32_t wave_size, Program& program, std::string* error);
std::string RegisterToString(Register reg);
std::string OperandToString(const Operand& operand);
@@ -12,10 +12,10 @@ bool HasInput(const ShaderInfo& info, StageInputKind kind, uint32_t location) {
});
}
void AddInput(ShaderInfo* info, StageInputKind kind, uint32_t location, uint32_t components,
void AddInput(ShaderInfo& info, StageInputKind kind, uint32_t location, uint32_t components,
std::string name) {
if (!HasInput(*info, kind, location)) {
info->inputs.push_back({kind, location, components, std::move(name)});
if (!HasInput(info, kind, location)) {
info.inputs.push_back({kind, location, components, std::move(name)});
}
}
@@ -25,10 +25,10 @@ bool HasOutput(const ShaderInfo& info, StageOutputKind kind, uint32_t index) {
});
}
void AddOutput(ShaderInfo* info, StageOutputKind kind, uint32_t index, uint32_t location,
void AddOutput(ShaderInfo& info, StageOutputKind kind, uint32_t index, uint32_t location,
std::string name) {
if (!HasOutput(*info, kind, index)) {
info->outputs.push_back({kind, index, location, std::move(name)});
if (!HasOutput(info, kind, index)) {
info.outputs.push_back({kind, index, location, std::move(name)});
}
}
@@ -87,7 +87,7 @@ bool ValidateOptions(const Program& program, const ShaderInfoOptions& options, s
}
void CollectVertexInputs(const Program& program, const ShaderVertexInputInfo* vertex,
ShaderInfo* info) {
ShaderInfo& info) {
AddInput(info, StageInputKind::VertexIndex, 0, 1, "gl_VertexIndex");
AddInput(info, StageInputKind::InstanceIndex, 0, 1, "gl_InstanceIndex");
if (vertex == nullptr) {
@@ -114,7 +114,7 @@ void CollectVertexInputs(const Program& program, const ShaderVertexInputInfo* ve
}
}
void CollectPixelInputs(const ShaderPixelInputInfo* pixel, ShaderInfo* info) {
void CollectPixelInputs(const ShaderPixelInputInfo* pixel, ShaderInfo& info) {
if (pixel == nullptr) {
return;
}
@@ -130,7 +130,7 @@ void CollectPixelInputs(const ShaderPixelInputInfo* pixel, ShaderInfo* info) {
}
void CollectComputeInputs(const Program& program, const ShaderComputeInputInfo* compute,
ShaderInfo* info) {
ShaderInfo& info) {
if (compute != nullptr) {
if (compute->group_id[0] || compute->group_id[1] || compute->group_id[2]) {
AddInput(info, StageInputKind::WorkgroupId, 0, 3, "gl_WorkGroupID");
@@ -150,7 +150,7 @@ void CollectComputeInputs(const Program& program, const ShaderComputeInputInfo*
}
}
void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, ShaderInfo* info) {
void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, ShaderInfo& info) {
for (const auto& block: program.blocks) {
for (const auto& inst: block.instructions) {
if (inst.op != Opcode::Export) {
@@ -193,32 +193,30 @@ void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, S
} // namespace
bool CollectShaderInfo(Program* program, const ShaderInfoOptions& options, std::string* error) {
if (program == nullptr || !program->resource_tracking_complete ||
program->shader_info_complete) {
bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::string* error) {
if (!program.resource_tracking_complete || program.shader_info_complete) {
if (error != nullptr) {
*error = program == nullptr ? "invalid shader info program"
: !program->resource_tracking_complete ? "shader resources were not tracked"
*error = !program.resource_tracking_complete ? "shader resources were not tracked"
: "shader info already collected";
}
return false;
}
if (!ValidateOptions(*program, options, error)) {
if (!ValidateOptions(program, options, error)) {
return false;
}
auto next = program->info;
auto next = program.info;
next.inputs.clear();
next.outputs.clear();
switch (program->stage) {
case ShaderType::Vertex: CollectVertexInputs(*program, options.vertex, &next); break;
case ShaderType::Pixel: CollectPixelInputs(options.pixel, &next); break;
case ShaderType::Compute: CollectComputeInputs(*program, options.compute, &next); break;
switch (program.stage) {
case ShaderType::Vertex: CollectVertexInputs(program, options.vertex, next); break;
case ShaderType::Pixel: CollectPixelInputs(options.pixel, next); break;
case ShaderType::Compute: CollectComputeInputs(program, options.compute, next); break;
default: return false;
}
CollectOutputs(*program, options.pixel, &next);
program->info = std::move(next);
program->shader_info_complete = true;
CollectOutputs(program, options.pixel, next);
program.info = std::move(next);
program.shader_info_complete = true;
return true;
}
@@ -13,7 +13,7 @@ struct ShaderInfoOptions {
// Completes the immutable shader interface after resource tracking. On failure Program::info and
// all completion state remain unchanged.
bool CollectShaderInfo(Program* program, const ShaderInfoOptions& options, std::string* error);
bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::string* error);
} // namespace Libs::Graphics::ShaderRecompiler::IR
@@ -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);
}
void AppendUniquePcs(std::vector<uint32_t>* dst, const std::vector<uint32_t>& src) {
EXIT_IF(dst == nullptr);
dst->reserve(dst->size() + src.size());
void AppendUniquePcs(std::vector<uint32_t>& dst, const std::vector<uint32_t>& src) {
dst.reserve(dst.size() + src.size());
for (auto pc: src) {
if (std::find(dst->begin(), dst->end(), pc) == dst->end()) {
dst->push_back(pc);
if (std::find(dst.begin(), dst.end(), pc) == dst.end()) {
dst.push_back(pc);
}
}
}
@@ -578,21 +577,21 @@ int ResolveEmbeddedFetchResource(const ShaderVertexInputInfo* input_info,
return -1;
}
uint32_t RewriteEmbeddedVertexFetches(IR::Program* ir, const ShaderVertexInputInfo* input_info,
uint32_t RewriteEmbeddedVertexFetches(IR::Program& ir, const ShaderVertexInputInfo* input_info,
const std::vector<EmbeddedFetchLoad>& loads) {
if (ir == nullptr || input_info == nullptr || loads.empty()) {
if (input_info == nullptr || loads.empty()) {
return 0;
}
std::vector<uint32_t> prolog_pcs;
prolog_pcs.reserve(loads.size());
for (const auto& load: loads) {
AppendUniquePcs(&prolog_pcs, load.prolog_loads);
AppendUniquePcs(prolog_pcs, load.prolog_loads);
}
auto* mutable_input_info = const_cast<ShaderVertexInputInfo*>(input_info);
uint32_t rewritten = 0;
for (auto& block: ir->blocks) {
for (auto& block: ir.blocks) {
for (auto& inst: block.instructions) {
if (IsIrFetchPrologLoad(inst) && EmbeddedFetchPcInList(prolog_pcs, inst.pc)) {
auto pc = inst.pc;
@@ -637,8 +636,8 @@ uint32_t RewriteEmbeddedVertexFetches(IR::Program* ir, const ShaderVertexInputIn
} // namespace
bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
CompileResult* result, std::string* error) {
if (code.empty() || result == nullptr) {
CompileResult& result, std::string* error) {
if (code.empty()) {
if (error != nullptr) {
*error = "invalid shader recompiler input";
}
@@ -664,7 +663,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
static_cast<uint64_t>(code.size()));
Decoder::Program decoded;
if (!Decoder::DecodeProgram(code, &decoded, error)) {
if (!Decoder::DecodeProgram(code, decoded, error)) {
return false;
}
LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " decode instructions=%" PRIu64
@@ -683,7 +682,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
CFG::Graph cfg;
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG BuildGraph\n", GetDumpLabel(options),
StageName(options.stage), options.shader_hash);
if (!CFG::BuildGraph(decoded, &cfg, error)) {
if (!CFG::BuildGraph(decoded, cfg, error)) {
return false;
}
LOGF("%s phase end: stage=%s hash=0x%016" PRIx64 " CFG BuildGraph blocks=%" PRIu64
@@ -703,7 +702,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
const auto unstructured_cfg = cfg;
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG Structurize\n",
GetDumpLabel(options), StageName(options.stage), options.shader_hash);
if (!CFG::Structurize(&cfg, &structure_error)) {
if (!CFG::Structurize(cfg, &structure_error)) {
const auto diagnostic = FormatCfgFailure(cfg, options, structure_error);
LOGF("%s structured CFG bug/failure: %s\n", GetDumpLabel(options), diagnostic.c_str());
dispatcher_fallback = true;
@@ -729,7 +728,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
IR::Program ir;
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " IR LowerProgram\n", GetDumpLabel(options),
StageName(options.stage), options.shader_hash);
if (!IR::LowerProgram(decoded, cfg, options.stage, options.wave_size, &ir, error)) {
if (!IR::LowerProgram(decoded, cfg, options.stage, options.wave_size, ir, error)) {
return false;
}
ir.lane_mask_mode = options.lane_mask_mode;
@@ -747,18 +746,18 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
DetectEmbeddedVertexFetch(decoded, options.vertex_input_info, ir.user_data_base,
ir.user_data_count, options.wave_size);
auto rewritten =
RewriteEmbeddedVertexFetches(&ir, options.vertex_input_info, embedded_fetch.loads);
RewriteEmbeddedVertexFetches(ir, options.vertex_input_info, embedded_fetch.loads);
if (rewritten > 0 || !embedded_fetch.loads.empty()) {
LOGF("%s embedded vertex fetch rewrite: detected=%" PRIu64 " rewritten=%" PRIu32 "\n",
GetDumpLabel(options), static_cast<uint64_t>(embedded_fetch.loads.size()),
rewritten);
}
}
if (!IR::BuildScalarProvenance(&ir, error)) {
if (!IR::BuildScalarProvenance(ir, error)) {
return false;
}
std::string srt_error;
if (!IR::BuildSrtPlan(&ir, &srt_error)) {
if (!IR::BuildSrtPlan(ir, &srt_error)) {
LOGF("%s SRT planning failed: %s\n", GetDumpLabel(options), srt_error.c_str());
if (error != nullptr) {
*error = std::move(srt_error);
@@ -770,7 +769,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
ir.fallback_reason = dispatcher_reason;
}
if (!IR::PatchSrtReads(&ir, error) || !IR::TrackResources(&ir, error)) {
if (!IR::PatchSrtReads(ir, error) || !IR::TrackResources(ir, error)) {
return false;
}
if (options.stage == ShaderType::Vertex) {
@@ -810,11 +809,11 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
: nullptr;
runtime.userdata = options.read_memory_data;
runtime.flat_memory_base = options.flat_memory_base;
if (!IR::MaterializeResources(ir, runtime, &resources, error)) {
if (!IR::MaterializeResources(ir, runtime, resources, error)) {
return false;
}
}
if (!IR::SpecializeResources(&ir, resources, error)) {
if (!IR::SpecializeResources(ir, resources, error)) {
return false;
}
@@ -828,13 +827,13 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
options.pixel_input_info != nullptr ? options.pixel_input_info : &default_pixel;
info_options.compute =
options.compute_input_info != nullptr ? options.compute_input_info : &default_compute;
if (!IR::CollectShaderInfo(&ir, info_options, error)) {
if (!IR::CollectShaderInfo(ir, info_options, error)) {
return false;
}
IR::BindingLayoutOptions layout_options;
layout_options.descriptor_set = options.descriptor_set;
layout_options.push_constant_offset = options.push_constant_offset;
if (!IR::AllocateBindings(&ir, layout_options, error)) {
if (!IR::AllocateBindings(ir, layout_options, error)) {
return false;
}
std::string ir_dump;
@@ -850,7 +849,7 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " SPIR-V EmitProgram\n",
GetDumpLabel(options), StageName(options.stage), options.shader_hash);
if (!Spirv::EmitProgram(ir, resources, options.vertex_input_info, options.pixel_input_info,
options.compute_input_info, &spirv, &emit_error)) {
options.compute_input_info, spirv, &emit_error)) {
if (dispatcher_fallback && error != nullptr) {
*error = fmt::format("dispatcher fallback failed after {}: {}",
dispatcher_reason.c_str(), emit_error.c_str());
@@ -868,15 +867,15 @@ bool TryRecompile(std::span<const uint32_t> code, const CompileOptions& options,
LOGF("%s dispatcher fallback used: %s\n", GetDumpLabel(options), dispatcher_reason.c_str());
}
result->spirv = std::move(spirv);
result->program = std::move(ir);
result->resources = std::move(resources);
result.spirv = std::move(spirv);
result.program = std::move(ir);
result.resources = std::move(resources);
if (options.dump_ir) {
result->decoded_dump = std::move(decoded_dump);
result->ir_dump = std::move(ir_dump);
result.decoded_dump = std::move(decoded_dump);
result.ir_dump = std::move(ir_dump);
} else {
result->decoded_dump.clear();
result->ir_dump.clear();
result.decoded_dump.clear();
result.ir_dump.clear();
}
return true;
}
@@ -44,7 +44,7 @@ struct CompileResult {
};
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
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff. Show more