mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 16:51:20 +00:00
graphics: refactoring #2
This commit is contained in:
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
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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, ©);
|
||||
vk_buffer.copyBuffer(src.buffer, dst.buffer, 1, ©);
|
||||
const vk::BufferMemoryBarrier after[] = {
|
||||
MakeDmaBarrier(dst, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
|
||||
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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*>(¶ms);
|
||||
for (std::size_t i = 0; i < sizeof(params); i++) {
|
||||
Mix(hash, bytes[i]);
|
||||
@@ -161,10 +165,10 @@ private:
|
||||
struct GraphicsPipelineKeyHash {
|
||||
std::size_t operator()(const GraphicsPipelineKey& key) const {
|
||||
std::size_t hash = 0;
|
||||
PipelineKeyHash::Mix(&hash, key.render_pass_id);
|
||||
PipelineKeyHash::MixShaderId(&hash, key.vs_shader_id);
|
||||
PipelineKeyHash::MixShaderId(&hash, key.ps_shader_id);
|
||||
PipelineKeyHash::MixStaticParams(&hash, key.static_params);
|
||||
PipelineKeyHash::Mix(hash, key.render_pass_id);
|
||||
PipelineKeyHash::MixShaderId(hash, key.vs_shader_id);
|
||||
PipelineKeyHash::MixShaderId(hash, key.ps_shader_id);
|
||||
PipelineKeyHash::MixStaticParams(hash, key.static_params);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
@@ -172,11 +176,12 @@ private:
|
||||
struct ComputePipelineKeyHash {
|
||||
std::size_t operator()(const ComputePipelineKey& key) const {
|
||||
std::size_t hash = 0;
|
||||
PipelineKeyHash::MixShaderId(&hash, key.cs_shader_id);
|
||||
PipelineKeyHash::MixShaderId(hash, key.cs_shader_id);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
GraphicContext& m_graphics;
|
||||
std::unordered_map<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
|
||||
|
||||
@@ -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, ®istered_meta)) {
|
||||
cache.RegisterMeta(target.address, target.size);
|
||||
if (!cache.ResolveMetaRange(target.address, target.size, registered_meta)) {
|
||||
EXIT("failed to resolve registered HTile compute-clear range\n");
|
||||
}
|
||||
} else {
|
||||
target = registered_target;
|
||||
}
|
||||
g_render_ctx->GetBufferCache()->ValidateGpuAccess(target.address, target.size, false, true);
|
||||
GetRenderContext().GetBufferCache().ValidateGpuAccess(target.address, target.size, false, true);
|
||||
|
||||
uint32_t metadata_writes = 0;
|
||||
ShaderBufferResource metadata_descriptor {};
|
||||
@@ -245,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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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, ©_region);
|
||||
vk_command.copyBuffer(m_buffer.buffer, dst_buffer.buffer, 1, ©_region);
|
||||
SetBufferMemoryBarrier(
|
||||
vk_command, dst_buffer->buffer, dst_offset, size,
|
||||
vk::AccessFlagBits::eTransferWrite,
|
||||
vk_command, dst_buffer.buffer, dst_offset, size, vk::AccessFlagBits::eTransferWrite,
|
||||
vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndexRead |
|
||||
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
|
||||
vk::PipelineStageFlagBits::eTransfer,
|
||||
@@ -310,61 +310,57 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
void UploadToImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size,
|
||||
uint32_t src_pitch, vk::ImageAspectFlags copy_aspect,
|
||||
vk::ImageLayout initial_layout, vk::ImageLayout final_layout) {
|
||||
const auto transition_aspects = GetTransferAspects(*image, copy_aspect);
|
||||
RecordUpload<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>(®ion, 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, ®ion);
|
||||
|
||||
if (r.src_image != dst_image) {
|
||||
if (&r.src_image != &dst_image) {
|
||||
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1,
|
||||
GetTransferAspects(*r.src_image, r.src_aspect),
|
||||
GetTransferAspects(r.src_image, r.src_aspect),
|
||||
vk::ImageLayout::eTransferSrcOptimal, restore_layout);
|
||||
}
|
||||
}
|
||||
@@ -785,11 +798,11 @@ void CopyImage(CommandBuffer* buffer, std::span<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, ®ion);
|
||||
vk_buffer.copyImage(r.src_image.image, vk::ImageLayout::eTransferSrcOptimal,
|
||||
dst_image.image, vk::ImageLayout::eTransferDstOptimal, 1, ®ion);
|
||||
|
||||
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1,
|
||||
GetTransferAspects(*r.src_image, r.src_aspect),
|
||||
GetTransferAspects(r.src_image, r.src_aspect),
|
||||
vk::ImageLayout::eTransferSrcOptimal, src_layout);
|
||||
}
|
||||
|
||||
@@ -839,59 +852,60 @@ void CopyImage(CommandBuffer* buffer, std::span<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, ©);
|
||||
|
||||
SetBufferMemoryBarrier(
|
||||
@@ -900,9 +914,9 @@ void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage*
|
||||
vk::PipelineStageFlagBits::eTransfer);
|
||||
|
||||
copy.imageSubresource.aspectMask = dst_aspect;
|
||||
vk_buffer.copyBufferToImage(copy_buffer->buffer, dst_image->image,
|
||||
vk_buffer.copyBufferToImage(copy_buffer->buffer, dst_image.image,
|
||||
vk::ImageLayout::eTransferDstOptimal, 1, ©);
|
||||
if (row + rows < src_image->extent.height) {
|
||||
if (row + rows < src_image.extent.height) {
|
||||
SetBufferMemoryBarrier(
|
||||
vk_buffer, copy_buffer->buffer, 0, copy_buffer_size,
|
||||
vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eTransferWrite,
|
||||
@@ -916,22 +930,20 @@ void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage*
|
||||
final_layout);
|
||||
}
|
||||
|
||||
void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image,
|
||||
VulkanSwapchain* dst_swapchain) {
|
||||
auto vk_buffer = buffer->Handle();
|
||||
if (src_image->layout != vk::ImageLayout::eTransferSrcOptimal) {
|
||||
EXIT("invalid prepared presentation image, image=%p vk_image=%p layout=%d\n",
|
||||
static_cast<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, ®ion,
|
||||
vk::Filter::eLinear);
|
||||
}
|
||||
|
||||
void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color) {
|
||||
auto vk_buffer = buffer->Handle();
|
||||
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image->layout,
|
||||
void ClearColorImage(CommandBuffer& buffer, VulkanImage& image, const vk::ClearColorValue& color) {
|
||||
auto vk_buffer = buffer.Handle();
|
||||
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image.layout,
|
||||
vk::ImageLayout::eTransferDstOptimal);
|
||||
const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
|
||||
vk_buffer.clearColorImage(image->image, vk::ImageLayout::eTransferDstOptimal, &color, 1,
|
||||
&range);
|
||||
vk_buffer.clearColorImage(image.image, vk::ImageLayout::eTransferDstOptimal, &color, 1, &range);
|
||||
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor,
|
||||
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal);
|
||||
}
|
||||
|
||||
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
|
||||
uint32_t src_pitch, vk::ImageLayout dst_layout) {
|
||||
void UploadImage(VulkanImage& dst_image, const void* src_data, uint64_t size, uint32_t src_pitch,
|
||||
vk::ImageLayout dst_layout) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_IF(size == 0);
|
||||
|
||||
GetStagingBuffer(StagingBufferType::Texture)
|
||||
->UploadToImage(ctx, dst_image, src_data, size, src_pitch, vk::ImageAspectFlagBits::eColor,
|
||||
.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, ©_region);
|
||||
vk_command.copyBuffer(src_buffer.buffer, dst_buffer.buffer, 1, ©_region);
|
||||
SetBufferMemoryBarrier(
|
||||
vk_command, dst_buffer->buffer, 0, size, vk::AccessFlagBits::eTransferWrite,
|
||||
vk_command, dst_buffer.buffer, 0, size, vk::AccessFlagBits::eTransferWrite,
|
||||
vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
|
||||
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands);
|
||||
});
|
||||
}
|
||||
|
||||
void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
|
||||
void* dst_data, uint64_t size) {
|
||||
void DownloadBuffer(VulkanBuffer& src_buffer, uint64_t src_offset, void* dst_data, uint64_t size) {
|
||||
auto& graphics = GetRenderContext().GetGraphics();
|
||||
EXIT_IF(size == 0);
|
||||
EXIT_IF(src_offset > src_buffer->buffer_size || size > src_buffer->buffer_size - src_offset);
|
||||
const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family;
|
||||
EXIT_IF(src_offset > src_buffer.buffer_size || size > src_buffer.buffer_size - src_offset);
|
||||
const auto family = graphics.queues[GraphicContext::QUEUE_UTIL].family;
|
||||
EXIT_IF(family == static_cast<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, ©);
|
||||
vk_command.copyBuffer(src_buffer.buffer, readback.buffer, 1, ©);
|
||||
SetBufferMemoryBarrier(vk_command, readback.buffer, 0, size,
|
||||
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eHostRead,
|
||||
vk::PipelineStageFlagBits::eTransfer,
|
||||
@@ -1105,10 +1114,10 @@ void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_
|
||||
});
|
||||
|
||||
void* mapped = nullptr;
|
||||
VulkanMapMemory(ctx, &readback.memory, &mapped);
|
||||
graphics.MapMemory(readback.memory, mapped);
|
||||
std::memcpy(dst_data, mapped, size);
|
||||
VulkanUnmapMemory(ctx, &readback.memory);
|
||||
VulkanDeleteBuffer(ctx, &readback);
|
||||
graphics.UnmapMemory(readback.memory);
|
||||
graphics.DeleteBuffer(readback);
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::Transfer
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
@@ -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, ®isters)) {
|
||||
if (!CollectSource(program, buffer.source, false, visited, registers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& image: program.info.images) {
|
||||
if (!CollectSource(program, image.source, false, &visited, ®isters)) {
|
||||
if (!CollectSource(program, image.source, false, visited, registers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& sampler: program.info.samplers) {
|
||||
if (!CollectSource(program, sampler.source, false, &visited, ®isters)) {
|
||||
if (!CollectSource(program, sampler.source, false, visited, registers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& address: program.info.addresses) {
|
||||
if (!CollectSource(program, address.source, true, &visited, ®isters)) {
|
||||
if (!CollectSource(program, address.source, true, visited, registers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& read: program.srt.reads) {
|
||||
if (!CollectValue(program.provenance, read.value, &visited, ®isters)) {
|
||||
if (!CollectValue(program.provenance, read.value, visited, registers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto read: program.srt.dynamic_reads) {
|
||||
if (!CollectValue(program.provenance, read, &visited, ®isters)) {
|
||||
if (!CollectValue(program.provenance, read, visited, registers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto source: program.srt.dynamic_sources) {
|
||||
if (!CollectSource(program, source, true, &visited, ®isters)) {
|
||||
if (!CollectSource(program, source, true, visited, registers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& block: program.blocks) {
|
||||
for (const auto& inst: block.instructions) {
|
||||
if (inst.op == Opcode::SLoadDword && inst.memory.kind == ResourceKind::ScalarBuffer &&
|
||||
!CollectValue(program.provenance, inst.scalar_value, &visited, ®isters)) {
|
||||
!CollectValue(program.provenance, inst.scalar_value, visited, registers)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < inst.src_count; i++) {
|
||||
if (!CollectValue(program.provenance, inst.scalar_sources[i], &visited,
|
||||
®isters)) {
|
||||
if (!CollectValue(program.provenance, inst.scalar_sources[i], visited,
|
||||
registers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -164,10 +164,10 @@ bool CollectUserData(const Program& program, std::vector<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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,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
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in new issue
Block a user