mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
shader: centralize program compilation and permutation caching
This commit is contained in:
@@ -888,12 +888,10 @@ void LogDrawPhase(const char* draw_name, const char* phase) {
|
||||
}
|
||||
}
|
||||
|
||||
void LogPipelineTrace(const char* phase, uint32_t vs_hash0, uint32_t vs_crc32, uint32_t ps_hash0,
|
||||
uint32_t ps_crc32) {
|
||||
void LogPipelineTrace(const char* phase, uint64_t vertex_program_id, uint64_t pixel_program_id) {
|
||||
if (graphics_debug_dump_enabled()) {
|
||||
LOGF("PipelineTrace: %s VS=0x%08" PRIx32 "/0x%08" PRIx32 " PS=0x%08" PRIx32 "/0x%08" PRIx32
|
||||
"\n",
|
||||
phase, vs_hash0, vs_crc32, ps_hash0, ps_crc32);
|
||||
LOGF("PipelineTrace: %s VS=%" PRIu64 " PS=%" PRIu64 "\n", phase, vertex_program_id,
|
||||
pixel_program_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,14 @@
|
||||
#include "graphics/host_gpu/renderer/image/imageView.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/shader/shaderCompiler.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -36,6 +39,88 @@ void NormalizeStaticParamsForDynamicState(PipelineStaticParameters& static_param
|
||||
|
||||
} // namespace
|
||||
|
||||
struct PipelineCache::ProgramCache {
|
||||
struct SourceKey {
|
||||
ShaderType stage = ShaderType::Unknown;
|
||||
uint64_t hash = 0;
|
||||
|
||||
bool operator==(const SourceKey&) const = default;
|
||||
};
|
||||
|
||||
struct Permutation {
|
||||
std::vector<uint32_t> static_key;
|
||||
std::shared_ptr<const ShaderRecompiler::IR::Program> program;
|
||||
ShaderProgram handle;
|
||||
};
|
||||
|
||||
struct SourceKeyHash {
|
||||
std::size_t operator()(const SourceKey& key) const {
|
||||
std::size_t hash = static_cast<std::size_t>(key.stage);
|
||||
PipelineKeyHash::Mix(hash, static_cast<std::size_t>(key.hash));
|
||||
if constexpr (sizeof(std::size_t) < sizeof(uint64_t)) {
|
||||
PipelineKeyHash::Mix(hash, static_cast<std::size_t>(key.hash >> 32u));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
static uint64_t MixId(uint64_t hash, uint64_t value) {
|
||||
return hash ^ (value + 0x9e3779b97f4a7c15ull + (hash << 6u) + (hash >> 2u));
|
||||
}
|
||||
|
||||
static constexpr std::size_t MaxStaticKeyWords =
|
||||
5 + ShaderVertexInputInfo::RES_MAX * 17;
|
||||
|
||||
template <typename InputInfo>
|
||||
ShaderProgram Get(const ShaderParams& params, InputInfo& input_info) {
|
||||
constexpr ShaderType stage = [] {
|
||||
if constexpr (std::is_same_v<InputInfo, ShaderVertexInputInfo>) {
|
||||
return ShaderType::Vertex;
|
||||
} else if constexpr (std::is_same_v<InputInfo, ShaderPixelInputInfo>) {
|
||||
return ShaderType::Pixel;
|
||||
} else {
|
||||
static_assert(std::is_same_v<InputInfo, ShaderComputeInputInfo>);
|
||||
return ShaderType::Compute;
|
||||
}
|
||||
}();
|
||||
|
||||
BuildStageStaticKey(input_info, key_scratch);
|
||||
auto& permutations = programs[{stage, params.hash}];
|
||||
for (const auto& permutation: permutations) {
|
||||
if (permutation.static_key == key_scratch &&
|
||||
MaterializeProgram(permutation.program, params, input_info)) {
|
||||
return permutation.handle;
|
||||
}
|
||||
}
|
||||
|
||||
const auto module = CompileProgram(device, params, input_info);
|
||||
EXIT_IF(module == nullptr || !input_info.stage);
|
||||
uint64_t id = MixId(MixId(params.hash, static_cast<uint64_t>(stage)), permutations.size());
|
||||
if (id == 0) {
|
||||
id = 1;
|
||||
}
|
||||
const ShaderProgram handle {.id = id, .module = module};
|
||||
permutations.push_back({key_scratch, input_info.stage.program, handle});
|
||||
|
||||
std::printf("Num compiled %u shaders\n", ++num_compiled);
|
||||
return handle;
|
||||
}
|
||||
|
||||
explicit ProgramCache(vk::Device device): device(device) {
|
||||
key_scratch.reserve(MaxStaticKeyWords);
|
||||
}
|
||||
|
||||
std::unordered_map<SourceKey, std::vector<Permutation>, SourceKeyHash> programs;
|
||||
std::vector<uint32_t> key_scratch;
|
||||
vk::Device device;
|
||||
uint32_t num_compiled = 0;
|
||||
};
|
||||
|
||||
PipelineCache::PipelineCache(GraphicContext& graphics)
|
||||
: m_graphics(graphics), m_program_cache(std::make_unique<ProgramCache>(graphics.device)) {
|
||||
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
|
||||
}
|
||||
|
||||
PipelineCache::~PipelineCache() {
|
||||
auto destroy = [this](const auto& pipelines) {
|
||||
for (const auto& [key, pipeline]: pipelines) {
|
||||
@@ -47,32 +132,62 @@ PipelineCache::~PipelineCache() {
|
||||
};
|
||||
destroy(m_graphics_pipelines);
|
||||
destroy(m_compute_pipelines);
|
||||
for (const auto& [key, permutations]: m_program_cache->programs) {
|
||||
(void)key;
|
||||
for (const auto& permutation: permutations) {
|
||||
m_graphics.device.destroyShaderModule(permutation.handle.module, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderProgram PipelineCache::GetVertexProgram(const HW::VertexShaderInfo& regs,
|
||||
const HW::ShaderRegisters& sh,
|
||||
ShaderVertexInputInfo& input_info) {
|
||||
const auto params = PrepareProgram(regs, sh, input_info);
|
||||
Common::LockGuard lock(m_mutex);
|
||||
return m_program_cache->Get(params, input_info);
|
||||
}
|
||||
|
||||
ShaderProgram PipelineCache::GetPixelProgram(
|
||||
const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
const ShaderVertexInputInfo& vertex_info,
|
||||
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
|
||||
ShaderPixelInputInfo& input_info) {
|
||||
const auto params = PrepareProgram(regs, sh, vertex_info, target_export_mapping, input_info);
|
||||
Common::LockGuard lock(m_mutex);
|
||||
return m_program_cache->Get(params, input_info);
|
||||
}
|
||||
|
||||
ShaderProgram PipelineCache::GetComputeProgram(const HW::ComputeShaderInfo& regs,
|
||||
const HW::ShaderRegisters& sh,
|
||||
ShaderComputeInputInfo& input_info) {
|
||||
input_info.needs_lds_barriers = !m_graphics.compute_wave64_supported;
|
||||
const auto params = PrepareProgram(regs, sh, input_info);
|
||||
Common::LockGuard lock(m_mutex);
|
||||
return m_program_cache->Get(params, input_info);
|
||||
}
|
||||
|
||||
bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other) const noexcept {
|
||||
return std::memcmp(this, &other, sizeof(*this)) == 0;
|
||||
}
|
||||
|
||||
PipelineCache::GraphicsPipeline&
|
||||
PipelineCache::CreateGraphicsPipeline(RenderColorInfo* colors, uint32_t color_count,
|
||||
RenderDepthInfo& depth, ShaderVertexInputInfo& vs_input_info,
|
||||
CommandBuffer& command, ShaderPixelInputInfo* ps_input_info,
|
||||
vk::PrimitiveTopology topology, bool primitive_restart_enable,
|
||||
bool ps_active, std::span<const uint32_t> vs_spirv,
|
||||
std::span<const uint32_t> ps_spirv) {
|
||||
PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
|
||||
std::span<const RenderColorInfo> colors, const RenderDepthInfo& depth,
|
||||
const ShaderVertexInputInfo& vs_input_info, CommandBuffer& command,
|
||||
const ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology,
|
||||
bool primitive_restart_enable, const ShaderProgram& vertex_program,
|
||||
const ShaderProgram& pixel_program) {
|
||||
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Gfx)", profiler::colors::DeepOrangeA200);
|
||||
|
||||
EXIT_IF(colors == nullptr);
|
||||
EXIT_IF(color_count > RENDER_COLOR_ATTACHMENTS_MAX);
|
||||
EXIT_IF(vs_spirv.empty());
|
||||
EXIT_IF(ps_active && ps_spirv.empty());
|
||||
EXIT_IF(colors.size() > RENDER_COLOR_ATTACHMENTS_MAX);
|
||||
EXIT_IF(!vertex_program);
|
||||
const bool ps_active = ps_input_info != nullptr;
|
||||
EXIT_IF(ps_active && !pixel_program);
|
||||
const auto color_count = static_cast<uint32_t>(colors.size());
|
||||
|
||||
Common::LockGuard lock(m_mutex);
|
||||
auto& ctx = command.GetRegisters();
|
||||
auto& sh_ctx = command.GetShaders();
|
||||
auto& ctx = command.GetRegisters();
|
||||
|
||||
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++) {
|
||||
@@ -83,11 +198,8 @@ PipelineCache::CreateGraphicsPipeline(RenderColorInfo* colors, uint32_t color_co
|
||||
}
|
||||
const HW::ModeControl& mc = ctx.GetModeControl();
|
||||
|
||||
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);
|
||||
}
|
||||
const auto vs_id = vertex_program.id;
|
||||
const auto ps_id = ps_active ? pixel_program.id : 0;
|
||||
|
||||
PipelineStaticParameters static_params {};
|
||||
GraphicsPipeline p {};
|
||||
@@ -203,20 +315,17 @@ PipelineCache::CreateGraphicsPipeline(RenderColorInfo* colors, uint32_t color_co
|
||||
if (ps_active) {
|
||||
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",
|
||||
vs_id.hash0, vs_id.crc32, static_cast<uint64_t>(vs_spirv.size()), ps_id.hash0,
|
||||
ps_id.crc32, static_cast<uint64_t>(ps_spirv.size()));
|
||||
LOGF("PipelineTrace: shader modules VS=%" PRIu64 " module=%p PS=%" PRIu64
|
||||
" module=%p\n",
|
||||
vs_id, static_cast<void*>(vertex_program.module), ps_id,
|
||||
static_cast<void*>(pixel_program.module));
|
||||
}
|
||||
|
||||
auto cached = std::make_unique<GraphicsPipeline>(p);
|
||||
LogPipelineTrace("CreatePipelineInternal begin", vs_id.hash0, vs_id.crc32, ps_id.hash0,
|
||||
ps_id.crc32);
|
||||
CreatePipelineInternal(m_graphics, *cached, rendering, 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);
|
||||
LogPipelineTrace("CreatePipelineInternal begin", vs_id, ps_id);
|
||||
CreatePipelineInternal(m_graphics, *cached, rendering, vs_input_info, vertex_program.module,
|
||||
ps_input_info, pixel_program.module, static_params);
|
||||
LogPipelineTrace("CreatePipelineInternal done", vs_id, ps_id);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cached->pipeline == nullptr);
|
||||
EXIT_NOT_IMPLEMENTED(cached->pipeline_layout == nullptr);
|
||||
@@ -228,19 +337,16 @@ PipelineCache::CreateGraphicsPipeline(RenderColorInfo* colors, uint32_t color_co
|
||||
}
|
||||
|
||||
PipelineCache::ComputePipeline&
|
||||
PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info,
|
||||
const HW::ComputeShaderInfo& cs_regs,
|
||||
std::span<const uint32_t> cs_spirv) {
|
||||
PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info,
|
||||
const ShaderProgram& compute_program) {
|
||||
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100);
|
||||
|
||||
EXIT_IF(cs_spirv.empty());
|
||||
EXIT_IF(!compute_program);
|
||||
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
auto cs_id = ShaderGetIdCS(cs_regs, input_info, true);
|
||||
|
||||
ComputePipeline p {};
|
||||
p.cs_shader_id = cs_id;
|
||||
p.cs_shader_id = compute_program.id;
|
||||
|
||||
ComputePipelineKey key {};
|
||||
key.cs_shader_id = p.cs_shader_id;
|
||||
@@ -254,7 +360,7 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info,
|
||||
}
|
||||
|
||||
auto cached = std::make_unique<ComputePipeline>(p);
|
||||
CreatePipelineInternal(m_graphics, *cached, input_info, cs_spirv);
|
||||
CreatePipelineInternal(m_graphics, *cached, input_info, compute_program.module);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cached->pipeline == nullptr);
|
||||
EXIT_NOT_IMPLEMENTED(cached->pipeline_layout == nullptr);
|
||||
|
||||
@@ -95,11 +95,18 @@ struct PipelineRenderingState {
|
||||
bool operator==(const PipelineRenderingState&) const = default;
|
||||
};
|
||||
|
||||
struct ShaderProgram {
|
||||
uint64_t id = 0;
|
||||
vk::ShaderModule module = nullptr;
|
||||
|
||||
explicit operator bool() const {
|
||||
return id != 0 && module != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
class PipelineCache {
|
||||
public:
|
||||
explicit PipelineCache(GraphicContext& graphics): m_graphics(graphics) {
|
||||
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
|
||||
}
|
||||
explicit PipelineCache(GraphicContext& graphics);
|
||||
~PipelineCache();
|
||||
KYTY_CLASS_NO_COPY(PipelineCache);
|
||||
|
||||
@@ -111,29 +118,42 @@ public:
|
||||
};
|
||||
|
||||
struct GraphicsPipeline: Pipeline {
|
||||
ShaderId vs_shader_id;
|
||||
ShaderId ps_shader_id;
|
||||
uint64_t vs_shader_id = 0;
|
||||
uint64_t ps_shader_id = 0;
|
||||
};
|
||||
|
||||
struct ComputePipeline: Pipeline {
|
||||
ShaderId cs_shader_id;
|
||||
uint64_t cs_shader_id = 0;
|
||||
};
|
||||
|
||||
GraphicsPipeline&
|
||||
CreateGraphicsPipeline(RenderColorInfo* colors, uint32_t color_count, RenderDepthInfo& depth,
|
||||
ShaderVertexInputInfo& vs_input_info, CommandBuffer& command,
|
||||
ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology,
|
||||
bool primitive_restart_enable, 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);
|
||||
ShaderProgram GetVertexProgram(const HW::VertexShaderInfo& regs,
|
||||
const HW::ShaderRegisters& sh,
|
||||
ShaderVertexInputInfo& input_info);
|
||||
ShaderProgram
|
||||
GetPixelProgram(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
const ShaderVertexInputInfo& vertex_info,
|
||||
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
|
||||
ShaderPixelInputInfo& input_info);
|
||||
ShaderProgram GetComputeProgram(const HW::ComputeShaderInfo& regs,
|
||||
const HW::ShaderRegisters& sh,
|
||||
ShaderComputeInputInfo& input_info);
|
||||
|
||||
GraphicsPipeline& CreateGraphicsPipeline(
|
||||
std::span<const RenderColorInfo> colors, const RenderDepthInfo& depth,
|
||||
const ShaderVertexInputInfo& vs_input_info, CommandBuffer& command,
|
||||
const ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology,
|
||||
bool primitive_restart_enable, const ShaderProgram& vertex_program,
|
||||
const ShaderProgram& pixel_program);
|
||||
ComputePipeline& CreateComputePipeline(ShaderComputeInputInfo& input_info,
|
||||
const ShaderProgram& compute_program);
|
||||
|
||||
private:
|
||||
struct ProgramCache;
|
||||
|
||||
struct GraphicsPipelineKey {
|
||||
PipelineRenderingState rendering;
|
||||
ShaderId vs_shader_id;
|
||||
ShaderId ps_shader_id;
|
||||
uint64_t vs_shader_id = 0;
|
||||
uint64_t ps_shader_id = 0;
|
||||
PipelineStaticParameters static_params;
|
||||
|
||||
bool operator==(const GraphicsPipelineKey& other) const {
|
||||
@@ -143,7 +163,7 @@ private:
|
||||
};
|
||||
|
||||
struct ComputePipelineKey {
|
||||
ShaderId cs_shader_id;
|
||||
uint64_t cs_shader_id = 0;
|
||||
|
||||
bool operator==(const ComputePipelineKey& other) const {
|
||||
return cs_shader_id == other.cs_shader_id;
|
||||
@@ -156,15 +176,6 @@ private:
|
||||
(hash >> 2u);
|
||||
}
|
||||
|
||||
static void MixShaderId(std::size_t& hash, const ShaderId& id) {
|
||||
Mix(hash, id.hash0);
|
||||
Mix(hash, id.crc32);
|
||||
Mix(hash, id.ids.size());
|
||||
for (auto value: id.ids) {
|
||||
Mix(hash, value);
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
@@ -186,8 +197,8 @@ private:
|
||||
std::size_t operator()(const GraphicsPipelineKey& key) const {
|
||||
std::size_t hash = 0;
|
||||
PipelineKeyHash::MixRendering(hash, key.rendering);
|
||||
PipelineKeyHash::MixShaderId(hash, key.vs_shader_id);
|
||||
PipelineKeyHash::MixShaderId(hash, key.ps_shader_id);
|
||||
PipelineKeyHash::Mix(hash, key.vs_shader_id);
|
||||
PipelineKeyHash::Mix(hash, key.ps_shader_id);
|
||||
PipelineKeyHash::MixStaticParams(hash, key.static_params);
|
||||
return hash;
|
||||
}
|
||||
@@ -196,12 +207,13 @@ private:
|
||||
struct ComputePipelineKeyHash {
|
||||
std::size_t operator()(const ComputePipelineKey& key) const {
|
||||
std::size_t hash = 0;
|
||||
PipelineKeyHash::MixShaderId(hash, key.cs_shader_id);
|
||||
PipelineKeyHash::Mix(hash, key.cs_shader_id);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
GraphicContext& m_graphics;
|
||||
GraphicContext& m_graphics;
|
||||
std::unique_ptr<ProgramCache> m_program_cache;
|
||||
std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>,
|
||||
GraphicsPipelineKeyHash>
|
||||
m_graphics_pipelines;
|
||||
@@ -210,17 +222,15 @@ private:
|
||||
Common::Mutex m_mutex;
|
||||
};
|
||||
|
||||
void LogPipelineTrace(const char* phase, uint32_t vs_hash0, uint32_t vs_crc32, uint32_t ps_hash0,
|
||||
uint32_t ps_crc32);
|
||||
void LogPipelineTrace(const char* phase, uint64_t vertex_program_id, uint64_t pixel_program_id);
|
||||
void CreatePipelineInternal(
|
||||
GraphicContext& graphics, PipelineCache::GraphicsPipeline& pipeline,
|
||||
const PipelineRenderingState& rendering, 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);
|
||||
vk::ShaderModule vertex_module, const ShaderPixelInputInfo* ps_input_info,
|
||||
vk::ShaderModule pixel_module, const PipelineStaticParameters& static_params);
|
||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipeline& pipeline,
|
||||
const ShaderComputeInputInfo& input_info,
|
||||
std::span<const uint32_t> cs_shader);
|
||||
vk::ShaderModule compute_module);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
|
||||
@@ -422,43 +422,19 @@ static void CreateDescriptorLayout(GraphicContext& graphics, PipelineCache::Pipe
|
||||
void CreatePipelineInternal(
|
||||
GraphicContext& graphics, PipelineCache::GraphicsPipeline& pipeline,
|
||||
const PipelineRenderingState& rendering, 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(ps_active && ps_input_info == nullptr);
|
||||
vk::ShaderModule vertex_module, const ShaderPixelInputInfo* ps_input_info,
|
||||
vk::ShaderModule pixel_module, const PipelineStaticParameters& static_params) {
|
||||
const bool ps_active = ps_input_info != nullptr;
|
||||
EXIT_IF(vertex_module == nullptr || (ps_active && pixel_module == nullptr));
|
||||
|
||||
const bool rect_list = static_params.topology == vk::PrimitiveTopology::ePatchList;
|
||||
|
||||
vk::ShaderModule vert_shader_module = nullptr;
|
||||
vk::ShaderModule tess_control_shader_module = nullptr;
|
||||
vk::ShaderModule tess_eval_shader_module = nullptr;
|
||||
vk::ShaderModule frag_shader_module = nullptr;
|
||||
|
||||
vk::ShaderModuleCreateInfo create_info {};
|
||||
|
||||
create_info.sType = vk::StructureType::eShaderModuleCreateInfo;
|
||||
create_info.pNext = nullptr;
|
||||
create_info.flags = {};
|
||||
|
||||
create_info.codeSize = vs_shader.size() * 4;
|
||||
create_info.pCode = vs_shader.data();
|
||||
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));
|
||||
}
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
|
||||
if (ps_active) {
|
||||
create_info.codeSize = ps_shader.size() * 4;
|
||||
create_info.pCode = ps_shader.data();
|
||||
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));
|
||||
}
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
}
|
||||
vk::Result result {};
|
||||
if (rect_list) {
|
||||
const auto shaders =
|
||||
BuildRectListShaders(vs_input_info, ps_active ? ps_input_info : nullptr);
|
||||
@@ -483,10 +459,8 @@ void CreatePipelineInternal(
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
}
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(vert_shader_module == nullptr);
|
||||
EXIT_NOT_IMPLEMENTED(
|
||||
rect_list && (tess_control_shader_module == nullptr || tess_eval_shader_module == nullptr));
|
||||
EXIT_NOT_IMPLEMENTED(ps_active && frag_shader_module == nullptr);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo vert_shader_stage_info {};
|
||||
|
||||
@@ -494,7 +468,7 @@ void CreatePipelineInternal(
|
||||
vert_shader_stage_info.pNext = nullptr;
|
||||
vert_shader_stage_info.flags = {};
|
||||
vert_shader_stage_info.stage = vk::ShaderStageFlagBits::eVertex;
|
||||
vert_shader_stage_info.module = vert_shader_module;
|
||||
vert_shader_stage_info.module = vertex_module;
|
||||
vert_shader_stage_info.pName = "main";
|
||||
vert_shader_stage_info.pSpecializationInfo = nullptr;
|
||||
|
||||
@@ -503,7 +477,7 @@ void CreatePipelineInternal(
|
||||
frag_shader_stage_info.pNext = nullptr;
|
||||
frag_shader_stage_info.flags = {};
|
||||
frag_shader_stage_info.stage = vk::ShaderStageFlagBits::eFragment;
|
||||
frag_shader_stage_info.module = frag_shader_module;
|
||||
frag_shader_stage_info.module = pixel_module;
|
||||
frag_shader_stage_info.pName = "main";
|
||||
frag_shader_stage_info.pSpecializationInfo = nullptr;
|
||||
|
||||
@@ -854,9 +828,9 @@ void CreatePipelineInternal(
|
||||
EXIT_IF(pipeline.pipeline_layout != nullptr);
|
||||
|
||||
if (graphics_debug_dump_enabled()) {
|
||||
LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=0x%08" PRIx32 "/0x%08" PRIx32
|
||||
" PS=0x%08" PRIx32 "/0x%08" PRIx32 " set_layouts=1 push_constants=%" PRIu32 "\n",
|
||||
vs_hash0, vs_crc32, ps_hash0, ps_crc32, 1u);
|
||||
LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=%" PRIu64 " PS=%" PRIu64
|
||||
" set_layouts=1 push_constants=%" PRIu32 "\n",
|
||||
pipeline.vs_shader_id, pipeline.ps_shader_id, 1u);
|
||||
}
|
||||
result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
|
||||
&pipeline.pipeline_layout);
|
||||
@@ -955,11 +929,12 @@ void CreatePipelineInternal(
|
||||
EXIT_IF(pipeline.pipeline != nullptr);
|
||||
|
||||
if (graphics_debug_dump_enabled()) {
|
||||
LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=0x%08" PRIx32 "/0x%08" PRIx32
|
||||
" PS=0x%08" PRIx32 "/0x%08" PRIx32 " topology=%" PRIu32 " color_mask=0x%08" PRIx32
|
||||
LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=%" PRIu64 " PS=%" PRIu64
|
||||
" topology=%" PRIu32 " color_mask=0x%08" PRIx32
|
||||
" depth=%s blend=%s dyn_states=%" PRIu32 " viewport=%f,%f %fx%f"
|
||||
" scissor=%d,%d %ux%u\n",
|
||||
vs_hash0, vs_crc32, ps_hash0, ps_crc32, static_cast<uint32_t>(static_params.topology),
|
||||
pipeline.vs_shader_id, pipeline.ps_shader_id,
|
||||
static_cast<uint32_t>(static_params.topology),
|
||||
static_params.color_mask[0], (static_params.with_depth ? "true" : "false"),
|
||||
(static_params.blend_enable[0] ? "true" : "false"), dynamic_states_count, viewport.x,
|
||||
viewport.y, viewport.width, viewport.height, scissor.offset.x, scissor.offset.y,
|
||||
@@ -975,39 +950,19 @@ void CreatePipelineInternal(
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
|
||||
|
||||
if (frag_shader_module != nullptr) {
|
||||
graphics.device.destroyShaderModule(frag_shader_module, nullptr);
|
||||
}
|
||||
if (tess_control_shader_module != nullptr) {
|
||||
graphics.device.destroyShaderModule(tess_control_shader_module, nullptr);
|
||||
}
|
||||
if (tess_eval_shader_module != nullptr) {
|
||||
graphics.device.destroyShaderModule(tess_eval_shader_module, nullptr);
|
||||
}
|
||||
graphics.device.destroyShaderModule(vert_shader_module, nullptr);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipeline& pipeline,
|
||||
const ShaderComputeInputInfo& input_info,
|
||||
std::span<const uint32_t> cs_shader) {
|
||||
vk::ShaderModule comp_shader_module = nullptr;
|
||||
|
||||
vk::ShaderModuleCreateInfo create_info {};
|
||||
|
||||
create_info.sType = vk::StructureType::eShaderModuleCreateInfo;
|
||||
create_info.pNext = nullptr;
|
||||
create_info.flags = {};
|
||||
create_info.codeSize = cs_shader.size() * 4;
|
||||
create_info.pCode = cs_shader.data();
|
||||
LOGF("PipelineTrace: vkCreateShaderModule CS begin words=%" PRIu64 "\n",
|
||||
static_cast<uint64_t>(cs_shader.size()));
|
||||
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);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(comp_shader_module == nullptr);
|
||||
vk::ShaderModule compute_module) {
|
||||
EXIT_IF(compute_module == nullptr);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo comp_shader_stage_info {};
|
||||
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo comp_subgroup_size {};
|
||||
@@ -1015,7 +970,7 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipe
|
||||
comp_shader_stage_info.pNext = nullptr;
|
||||
comp_shader_stage_info.flags = {};
|
||||
comp_shader_stage_info.stage = vk::ShaderStageFlagBits::eCompute;
|
||||
comp_shader_stage_info.module = comp_shader_module;
|
||||
comp_shader_stage_info.module = compute_module;
|
||||
comp_shader_stage_info.pName = "main";
|
||||
comp_shader_stage_info.pSpecializationInfo = nullptr;
|
||||
EXIT_IF(!input_info.stage);
|
||||
@@ -1048,8 +1003,8 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipe
|
||||
|
||||
LOGF("PipelineTrace: vkCreatePipelineLayout CS begin set_layouts=1 push_constants=%u\n",
|
||||
1u);
|
||||
result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
|
||||
&pipeline.pipeline_layout);
|
||||
auto 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));
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
@@ -1075,8 +1030,6 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipe
|
||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
|
||||
|
||||
graphics.device.destroyShaderModule(comp_shader_module, nullptr);
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -207,17 +207,12 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
||||
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, !m_context.GetGraphics().compute_wave64_supported,
|
||||
input_info, cs_shader)) {
|
||||
EXIT("ShaderCompileInfoCS failed for dispatch with CS shader 0x%016" PRIx64 "\n",
|
||||
cs_regs.cs_regs.data_addr);
|
||||
}
|
||||
|
||||
ShaderComputeInputInfo input_info {};
|
||||
const bool use_thread_dimensions = (mode & DISPATCH_INITIATOR_USE_THREAD_DIMENSIONS) != 0;
|
||||
input_info.dispatch_thread_dimensions = use_thread_dimensions;
|
||||
const auto compute_program =
|
||||
m_context.GetPipelineCache().GetComputeProgram(cs_regs, sh_regs, input_info);
|
||||
if (use_thread_dimensions) {
|
||||
input_info.dispatch_thread_dimensions = true;
|
||||
input_info.dispatch_threads_num[0] = thread_group_x;
|
||||
input_info.dispatch_threads_num[1] = thread_group_y;
|
||||
input_info.dispatch_threads_num[2] = thread_group_z;
|
||||
@@ -332,7 +327,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
||||
|
||||
buffer.EndRendering();
|
||||
auto& pipeline =
|
||||
m_context.GetPipelineCache().CreateComputePipeline(input_info, sh_ctx.GetCs(), cs_shader);
|
||||
m_context.GetPipelineCache().CreateComputePipeline(input_info, compute_program);
|
||||
auto bindings = PrepareBindings(input_info.stage);
|
||||
FindBuffers(bindings);
|
||||
if (program.info.uses_dma) {
|
||||
|
||||
@@ -483,15 +483,15 @@ static bool ShouldSkipGeShader(const CommandBuffer& buffer) {
|
||||
}
|
||||
|
||||
struct DrawRenderState {
|
||||
RenderDepthInfo depth_info;
|
||||
RenderColorInfo color_info[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
uint32_t color_count = 0;
|
||||
bool ps_active = true;
|
||||
RenderState rendering;
|
||||
ShaderVertexInputInfo vs_input_info;
|
||||
ShaderPixelInputInfo ps_input_info;
|
||||
std::span<const uint32_t> vs_shader;
|
||||
std::span<const uint32_t> ps_shader;
|
||||
RenderDepthInfo depth_info;
|
||||
RenderColorInfo color_info[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
uint32_t color_count = 0;
|
||||
bool ps_active = true;
|
||||
RenderState rendering;
|
||||
ShaderVertexInputInfo vs_input_info;
|
||||
ShaderPixelInputInfo ps_input_info;
|
||||
ShaderProgram vertex_program;
|
||||
ShaderProgram pixel_program;
|
||||
};
|
||||
|
||||
struct DrawCallInfo {
|
||||
@@ -1003,32 +1003,30 @@ static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw, bool
|
||||
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.vertex_program = {};
|
||||
state.pixel_program = {};
|
||||
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;
|
||||
}
|
||||
if (log_phases) {
|
||||
LogDrawPhase(draw.name, "ShaderCompileInfoVS");
|
||||
}
|
||||
if (!ShaderCompileInfoVS(vertex_shader_info, shader_regs, state.vs_input_info,
|
||||
state.vs_shader)) {
|
||||
EXIT("ShaderCompileInfoVS failed for draw %s\n", draw.name);
|
||||
LogDrawPhase(draw.name, "GetVertexProgram");
|
||||
}
|
||||
auto& pipeline_cache = buffer.GetContext().GetPipelineCache();
|
||||
state.vertex_program =
|
||||
pipeline_cache.GetVertexProgram(vertex_shader_info, shader_regs, state.vs_input_info);
|
||||
|
||||
if (!state.ps_active) {
|
||||
return;
|
||||
}
|
||||
if (log_phases) {
|
||||
LogDrawPhase(draw.name, "ShaderCompileInfoPS");
|
||||
}
|
||||
if (!ShaderCompileInfoPS(pixel_shader_info, shader_regs, state.vs_input_info,
|
||||
target_export_mapping, state.ps_input_info, state.ps_shader)) {
|
||||
EXIT("ShaderCompileInfoPS failed for draw %s\n", draw.name);
|
||||
LogDrawPhase(draw.name, "GetPixelProgram");
|
||||
}
|
||||
state.pixel_program =
|
||||
pipeline_cache.GetPixelProgram(pixel_shader_info, shader_regs, state.vs_input_info,
|
||||
target_export_mapping, state.ps_input_info);
|
||||
}
|
||||
|
||||
static PreparedVertexBuffers PrepareVertexBuffers(uint64_t submit_id, CommandBuffer& buffer,
|
||||
@@ -1180,9 +1178,9 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
|
||||
LogDrawPhase(draw.name, "CreatePipeline");
|
||||
}
|
||||
auto& pipeline = m_context.GetPipelineCache().CreateGraphicsPipeline(
|
||||
state.color_info, state.color_count, state.depth_info, state.vs_input_info, buffer,
|
||||
&state.ps_input_info, topology, primitive_restart_enable, state.ps_active, state.vs_shader,
|
||||
state.ps_shader);
|
||||
std::span {state.color_info, state.color_count}, state.depth_info, state.vs_input_info, buffer,
|
||||
state.ps_active ? &state.ps_input_info : nullptr, topology, primitive_restart_enable,
|
||||
state.vertex_program, state.pixel_program);
|
||||
|
||||
// Resource preparation above may synchronously finish and restart the scheduler. From this
|
||||
// point onward, every operation targets the current command buffer and cannot touch guest
|
||||
|
||||
+258
-651
File diff suppressed because it is too large
Load Diff
@@ -60,17 +60,6 @@ bool ShaderMaterializeStageRuntime(
|
||||
std::string* error, ShaderSpecializationMemoryReader read_specialization_memory = nullptr,
|
||||
void* read_memory_data = nullptr);
|
||||
|
||||
struct ShaderId {
|
||||
uint32_t hash0 = 0;
|
||||
uint32_t crc32 = 0;
|
||||
std::vector<uint32_t> ids;
|
||||
|
||||
bool operator==(const ShaderId& other) const {
|
||||
return hash0 == other.hash0 && crc32 == other.crc32 && ids == other.ids;
|
||||
}
|
||||
bool operator!=(const ShaderId& other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
constexpr uint32_t DstSel(uint32_t x, uint32_t y = 0, uint32_t z = 0, uint32_t w = 0) {
|
||||
return x | (y << 3u) | (z << 6u) | (w << 9u);
|
||||
}
|
||||
@@ -254,28 +243,6 @@ void ShaderMapUserData(uint64_t addr, const ShaderMappedData& data);
|
||||
void ShaderDbgDumpInputInfo(const ShaderVertexInputInfo& info);
|
||||
void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo& info);
|
||||
void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo& info);
|
||||
ShaderId ShaderGetIdVS(const HW::VertexShaderInfo& regs, const ShaderVertexInputInfo& input_info,
|
||||
bool include_bind_specialization);
|
||||
ShaderId ShaderGetIdPS(const HW::PixelShaderInfo& regs, const ShaderPixelInputInfo& input_info,
|
||||
bool include_bind_specialization);
|
||||
ShaderId ShaderGetIdCS(const HW::ComputeShaderInfo& regs, const ShaderComputeInputInfo& input_info,
|
||||
bool include_bind_specialization);
|
||||
// Returned SPIR-V spans are read-only views backed by the shader program cache.
|
||||
bool ShaderCompileInfoVS(const HW::VertexShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
ShaderVertexInputInfo& input_info, std::span<const uint32_t>& spirv);
|
||||
bool ShaderCompileInfoPS(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
const ShaderVertexInputInfo& vs_info,
|
||||
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
|
||||
ShaderPixelInputInfo& input_info, std::span<const uint32_t>& spirv);
|
||||
bool ShaderCompileInfoCS(const HW::ComputeShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
bool needs_lds_barriers, ShaderComputeInputInfo& input_info,
|
||||
std::span<const uint32_t>& spirv);
|
||||
bool ShaderCompileSpirvVS(const HW::VertexShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
ShaderVertexInputInfo& input_info, std::vector<uint32_t>& spirv);
|
||||
bool ShaderCompileSpirvPS(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
ShaderPixelInputInfo& input_info, std::vector<uint32_t>& spirv);
|
||||
bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
ShaderComputeInputInfo& input_info, std::vector<uint32_t>& spirv);
|
||||
bool ShaderAddressValid(uint64_t addr);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_SHADERCOMPILER_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_SHADERCOMPILER_H_
|
||||
|
||||
#include "graphics/host_gpu/vulkanCommon.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
struct ShaderParams {
|
||||
std::span<const uint32_t> code;
|
||||
std::span<const uint32_t> user_data;
|
||||
uint64_t hash = 0;
|
||||
|
||||
[[nodiscard]] uint64_t Base() const {
|
||||
return reinterpret_cast<uint64_t>(code.data());
|
||||
}
|
||||
};
|
||||
|
||||
void BuildStageStaticKey(const ShaderVertexInputInfo& input_info, std::vector<uint32_t>& key);
|
||||
void BuildStageStaticKey(const ShaderPixelInputInfo& input_info, std::vector<uint32_t>& key);
|
||||
void BuildStageStaticKey(const ShaderComputeInputInfo& input_info, std::vector<uint32_t>& key);
|
||||
|
||||
ShaderParams PrepareProgram(const HW::VertexShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
ShaderVertexInputInfo& input_info);
|
||||
ShaderParams PrepareProgram(
|
||||
const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
const ShaderVertexInputInfo& vertex_info,
|
||||
std::span<const Prospero::ColorComponentMapping, 8> target_export_mapping,
|
||||
ShaderPixelInputInfo& input_info);
|
||||
ShaderParams PrepareProgram(const HW::ComputeShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||
ShaderComputeInputInfo& input_info);
|
||||
|
||||
bool MaterializeProgram(const std::shared_ptr<const ShaderRecompiler::IR::Program>& program,
|
||||
const ShaderParams& params, ShaderVertexInputInfo& input_info);
|
||||
bool MaterializeProgram(const std::shared_ptr<const ShaderRecompiler::IR::Program>& program,
|
||||
const ShaderParams& params, ShaderPixelInputInfo& input_info);
|
||||
bool MaterializeProgram(const std::shared_ptr<const ShaderRecompiler::IR::Program>& program,
|
||||
const ShaderParams& params, ShaderComputeInputInfo& input_info);
|
||||
|
||||
vk::ShaderModule CompileProgram(vk::Device device, const ShaderParams& params,
|
||||
ShaderVertexInputInfo& input_info);
|
||||
vk::ShaderModule CompileProgram(vk::Device device, const ShaderParams& params,
|
||||
ShaderPixelInputInfo& input_info);
|
||||
vk::ShaderModule CompileProgram(vk::Device device, const ShaderParams& params,
|
||||
ShaderComputeInputInfo& input_info);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_SHADERCOMPILER_H_ */
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/BindingLayout.h"
|
||||
#include "graphics/shader/rectListShader.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
#include "graphics/shader/shaderCompiler.h"
|
||||
#include "kernel/eventQueue.h"
|
||||
#include "kernel/memory.h"
|
||||
#include "libs/agc.h"
|
||||
@@ -1057,12 +1058,14 @@ void CheckRectListShaders() {
|
||||
pixel.interpolator_settings[0] = 0x400u;
|
||||
pixel.interpolator_settings[1] = 0;
|
||||
pixel.stage.program = program;
|
||||
HW::PixelShaderInfo ps_regs{};
|
||||
const auto perspective_id = ShaderGetIdPS(ps_regs, pixel, false);
|
||||
std::vector<uint32_t> perspective_specialization;
|
||||
BuildStageStaticKey(pixel, perspective_specialization);
|
||||
pixel.ps_no_perspective = true;
|
||||
const auto no_perspective_id = ShaderGetIdPS(ps_regs, pixel, false);
|
||||
std::vector<uint32_t> no_perspective_specialization;
|
||||
BuildStageStaticKey(pixel, no_perspective_specialization);
|
||||
pixel.ps_no_perspective = false;
|
||||
Require(name, "pipeline identity", perspective_id != no_perspective_id,
|
||||
Require(name, "pipeline identity",
|
||||
perspective_specialization != no_perspective_specialization,
|
||||
"pixel interpolation mode must participate in the shader and "
|
||||
"pipeline key");
|
||||
|
||||
@@ -22508,83 +22511,12 @@ void CheckStorageTextureDepthTileUploadLayout() {
|
||||
"1x1 R8_UINT depth tile lost its 64 KiB source footprint");
|
||||
std::printf("[host] %-32s ok\n", "StorageTextureDepthTileUpload");
|
||||
}
|
||||
void CheckImageSpecializationId() {
|
||||
std::array<u32, 1> code{};
|
||||
HW::ComputeShaderInfo regs{};
|
||||
regs.cs_regs.data_addr = reinterpret_cast<uint64_t>(code.data());
|
||||
|
||||
ShaderRecompiler::IR::ImageResource image;
|
||||
image.kind = ShaderRecompiler::IR::ResourceKind::StorageImage;
|
||||
image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||
const auto make_program = [](ShaderRecompiler::IR::ImageResource resource) {
|
||||
ShaderRecompiler::IR::Program program;
|
||||
program.binding_layout_complete = true;
|
||||
program.info.images.push_back(std::move(resource));
|
||||
return program;
|
||||
};
|
||||
auto rgb1_image = image;
|
||||
rgb1_image.shader_swizzle = DstSel(4, 5, 6, 1);
|
||||
auto converted_image = image;
|
||||
converted_image.conversion_format =
|
||||
Prospero::BufferFormat::k11_11_10UInt;
|
||||
auto mip1_image = image;
|
||||
mip1_image.mip_mode = ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
|
||||
auto mip3_image = mip1_image;
|
||||
mip3_image.mip_count = 3;
|
||||
auto array_image = image;
|
||||
array_image.dimension =
|
||||
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
|
||||
auto cube_image = array_image;
|
||||
cube_image.cube = true;
|
||||
|
||||
const auto resources =
|
||||
std::make_shared<const ShaderRecompiler::IR::ResourceSnapshot>();
|
||||
ShaderComputeInputInfo identity_info;
|
||||
identity_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
|
||||
make_program(image));
|
||||
identity_info.stage.resources = resources;
|
||||
auto rgb1_info = identity_info;
|
||||
rgb1_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
|
||||
make_program(rgb1_image));
|
||||
auto converted_info = identity_info;
|
||||
converted_info.stage.program =
|
||||
std::make_shared<const ShaderRecompiler::IR::Program>(
|
||||
make_program(converted_image));
|
||||
auto mip1_info = identity_info;
|
||||
mip1_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
|
||||
make_program(mip1_image));
|
||||
auto mip3_info = identity_info;
|
||||
mip3_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
|
||||
make_program(mip3_image));
|
||||
auto array_info = identity_info;
|
||||
array_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
|
||||
make_program(array_image));
|
||||
auto cube_info = identity_info;
|
||||
cube_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
|
||||
make_program(cube_image));
|
||||
|
||||
const auto identity_id = ShaderGetIdCS(regs, identity_info, true);
|
||||
const auto rgb1_id = ShaderGetIdCS(regs, rgb1_info, true);
|
||||
const auto converted_id = ShaderGetIdCS(regs, converted_info, true);
|
||||
const auto mip1_id = ShaderGetIdCS(regs, mip1_info, true);
|
||||
const auto mip3_id = ShaderGetIdCS(regs, mip3_info, true);
|
||||
const auto array_id = ShaderGetIdCS(regs, array_info, true);
|
||||
const auto cube_id = ShaderGetIdCS(regs, cube_info, true);
|
||||
Require("ImageSpecializationId", "pipeline cache key",
|
||||
identity_id != rgb1_id &&
|
||||
identity_id.ids.size() == rgb1_id.ids.size() &&
|
||||
identity_id != converted_id &&
|
||||
identity_id.ids.size() == converted_id.ids.size() &&
|
||||
mip1_id != mip3_id && mip1_id.ids.size() == mip3_id.ids.size() &&
|
||||
array_id != cube_id && array_id.ids.size() == cube_id.ids.size(),
|
||||
"image conversion, swizzle, mip-count, or cube variants share a "
|
||||
"pipeline ID");
|
||||
|
||||
void CheckImageSamplerSpecialization() {
|
||||
ShaderSamplerResource filtered_sampler{};
|
||||
filtered_sampler.fields[2] =
|
||||
(1u << 20u) | (3u << 22u) | (2u << 24u) | (2u << 26u);
|
||||
filtered_sampler.SetPointFiltering();
|
||||
Require("ImageSpecializationId", "forced point sampler",
|
||||
Require("ImageSamplerSpecialization", "forced point sampler",
|
||||
filtered_sampler.XyMagFilter() == 0u &&
|
||||
filtered_sampler.XyMinFilter() == 0u &&
|
||||
filtered_sampler.ZFilter() == 1u &&
|
||||
@@ -22594,7 +22526,7 @@ void CheckImageSpecializationId() {
|
||||
ShaderSamplerResource base_mip_sampler{};
|
||||
base_mip_sampler.fields[2] = (3u << 20u) | (1u << 22u) | (2u << 24u);
|
||||
base_mip_sampler.SetPointFiltering();
|
||||
Require("ImageSpecializationId", "base-mip point sampler",
|
||||
Require("ImageSamplerSpecialization", "base-mip point sampler",
|
||||
base_mip_sampler.XyMagFilter() == 0u &&
|
||||
base_mip_sampler.XyMinFilter() == 0u &&
|
||||
base_mip_sampler.ZFilter() == 1u &&
|
||||
@@ -22632,12 +22564,12 @@ void CheckImageSpecializationId() {
|
||||
sampler_descriptor.dword_count = 4;
|
||||
mixed_sampler_snapshot.samplers.push_back(sampler_descriptor);
|
||||
std::string specialization_error;
|
||||
Require("ImageSpecializationId", "mixed sampler specialization",
|
||||
Require("ImageSamplerSpecialization", "mixed sampler specialization",
|
||||
ShaderRecompiler::IR::SpecializeResources(mixed_sampler_program,
|
||||
mixed_sampler_snapshot,
|
||||
&specialization_error),
|
||||
specialization_error);
|
||||
Require("ImageSpecializationId", "mixed sampler variant",
|
||||
Require("ImageSamplerSpecialization", "mixed sampler variant",
|
||||
mixed_sampler_program.info.samplers.size() == 2u &&
|
||||
!mixed_sampler_program.info.samplers[0].force_point_filtering &&
|
||||
mixed_sampler_program.info.samplers[1].force_point_filtering &&
|
||||
@@ -22658,7 +22590,7 @@ void CheckImageSpecializationId() {
|
||||
ShaderRecompiler::IR::ResourceSnapshot packed_atomic_snapshot;
|
||||
packed_atomic_snapshot.images.push_back(packed_image_descriptor);
|
||||
std::string atomic_error;
|
||||
Require("ImageSpecializationId", "packed atomic rejection",
|
||||
Require("ImageSamplerSpecialization", "packed atomic rejection",
|
||||
!ShaderRecompiler::IR::SpecializeResources(
|
||||
packed_atomic_program, packed_atomic_snapshot, &atomic_error) &&
|
||||
atomic_error.find("unsupported format 34") != std::string::npos,
|
||||
@@ -24389,7 +24321,7 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--indirect-image-only") == 0) {
|
||||
CheckImageSpecializationId();
|
||||
CheckImageSamplerSpecialization();
|
||||
CheckIndirectImageKeySwitch();
|
||||
return 0;
|
||||
}
|
||||
@@ -24431,7 +24363,7 @@ int main(int argc, char **argv) {
|
||||
CheckBasicStorageTextureDescriptor();
|
||||
CheckStorageTextureLinearUploadLayout();
|
||||
CheckStorageTextureDepthTileUploadLayout();
|
||||
CheckImageSpecializationId();
|
||||
CheckImageSamplerSpecialization();
|
||||
CheckStandard64RenderTargetTileRoundTrip();
|
||||
CheckStorageTextureVolumeUploadLayout();
|
||||
CheckStorageTextureVolumeMipRegions();
|
||||
|
||||
+148
-86
@@ -25,6 +25,7 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/SrtWalker.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/SsaRewrite.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
#include "graphics/shader/shaderCompiler.h"
|
||||
#include "libs/agc.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
@@ -76,6 +77,46 @@ ShaderRecompiler::CompileOptions MakeCompileOptions(ShaderType stage) {
|
||||
return options;
|
||||
}
|
||||
|
||||
bool ReadHostTestMemory(void *, uint64_t address, uint32_t *value) {
|
||||
if (address == 0 || value == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy(value, reinterpret_cast<const void *>(address), sizeof(*value));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompilePixelRuntime(const ShaderParams ¶ms,
|
||||
ShaderPixelInputInfo &input_info,
|
||||
std::string *error) {
|
||||
auto options = MakeCompileOptions(ShaderType::Pixel);
|
||||
options.shader_hash = params.hash;
|
||||
options.shader_base = params.Base();
|
||||
options.user_data = params.user_data.data();
|
||||
options.user_data_count = static_cast<uint32_t>(params.user_data.size());
|
||||
options.scratch_dwords = input_info.scratch_size_dwords;
|
||||
options.push_constant_offset = input_info.push_constant_offset;
|
||||
options.read_specialization_memory = ReadHostTestMemory;
|
||||
options.input_info.pixel = &input_info;
|
||||
ShaderRecompiler::CompileResult result;
|
||||
if (!ShaderRecompiler::TryRecompile(params.code, options, result, error)) {
|
||||
return false;
|
||||
}
|
||||
input_info.stage.program =
|
||||
std::make_shared<const ShaderRecompiler::IR::Program>(
|
||||
std::move(result.program));
|
||||
input_info.stage.resources =
|
||||
std::make_shared<const ShaderRecompiler::IR::ResourceSnapshot>(
|
||||
std::move(result.resources));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename InputInfo>
|
||||
std::vector<uint32_t> MakeStageStaticKey(const InputInfo &input_info) {
|
||||
std::vector<uint32_t> key;
|
||||
BuildStageStaticKey(input_info, key);
|
||||
return key;
|
||||
}
|
||||
|
||||
std::vector<uint32_t>
|
||||
CfgInstructionCoverage(const ShaderRecompiler::CFG::Graph &graph,
|
||||
size_t instruction_count) {
|
||||
@@ -9107,7 +9148,7 @@ void TestNewShaderRecompilerAuxPositionExports() {
|
||||
ShaderVertexInputInfo key0{};
|
||||
ShaderVertexInputInfo key1{};
|
||||
key1.pa_cl_vs_out_cntl = 1;
|
||||
Check(ShaderGetIdVS(regs, key0, false) != ShaderGetIdVS(regs, key1, false),
|
||||
Check(MakeStageStaticKey(key0) != MakeStageStaticKey(key1),
|
||||
"PA_CL_VS_OUT_CNTL is absent from the vertex shader cache key");
|
||||
}
|
||||
|
||||
@@ -10513,8 +10554,7 @@ void TestRenderTargetReverseExportMapping() {
|
||||
reversed_info.target_export_mapping[0] = gr32.export_mapping;
|
||||
|
||||
HW::PixelShaderInfo regs{};
|
||||
Check(ShaderGetIdPS(regs, identity_info, false) !=
|
||||
ShaderGetIdPS(regs, reversed_info, false),
|
||||
Check(MakeStageStaticKey(identity_info) != MakeStageStaticKey(reversed_info),
|
||||
"pixel shader cache identity omitted the render-target export mapping");
|
||||
|
||||
regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(shader);
|
||||
@@ -10527,18 +10567,13 @@ void TestRenderTargetReverseExportMapping() {
|
||||
mappings[0] = gr32.export_mapping;
|
||||
ShaderPixelInputInfo compiled_info{};
|
||||
ShaderVertexInputInfo vertex_info{};
|
||||
std::span<const uint32_t> compiled_spirv;
|
||||
Check(
|
||||
ShaderCompileInfoPS(regs, sh, vertex_info, mappings, compiled_info,
|
||||
compiled_spirv) &&
|
||||
compiled_info.target_export_mapping[0].IsIdentity(),
|
||||
"inactive reverse MRT mapping was not normalized out of the shader "
|
||||
PrepareProgram(regs, sh, vertex_info, mappings, compiled_info);
|
||||
Check(compiled_info.target_export_mapping[0].IsIdentity(),
|
||||
"inactive reverse MRT mapping was not normalized out of the shader "
|
||||
"cache key");
|
||||
sh.target_output_mode[0] = 4;
|
||||
Check(
|
||||
ShaderCompileInfoPS(regs, sh, vertex_info, mappings, compiled_info,
|
||||
compiled_spirv) &&
|
||||
compiled_info.target_export_mapping[0] == gr32.export_mapping,
|
||||
PrepareProgram(regs, sh, vertex_info, mappings, compiled_info);
|
||||
Check(compiled_info.target_export_mapping[0] == gr32.export_mapping,
|
||||
"active reverse MRT mapping was lost before shader specialization");
|
||||
}
|
||||
|
||||
@@ -11517,15 +11552,12 @@ void TestNewShaderRecompilerPixelPipelineEntry() {
|
||||
ShaderMapUserData(regs.ps_regs.data_addr, mapped);
|
||||
|
||||
HW::ShaderRegisters sh{};
|
||||
const std::array<Prospero::ColorComponentMapping, 8> mappings{};
|
||||
ShaderVertexInputInfo vertex_info{};
|
||||
ShaderPixelInputInfo input_info{};
|
||||
std::vector<uint32_t> spirv;
|
||||
Check(ShaderCompileSpirvPS(regs, sh, input_info, spirv),
|
||||
"new pixel shader recompiler wrapper did not produce SPIR-V");
|
||||
Check(!spirv.empty(),
|
||||
"new pixel shader recompiler wrapper returned empty SPIR-V");
|
||||
Check(spirv.front() == 0x07230203u,
|
||||
"new pixel shader recompiler wrapper did not emit SPIR-V binary");
|
||||
CheckSpirvBinaryValidates(spirv);
|
||||
const auto params = PrepareProgram(regs, sh, vertex_info, mappings, input_info);
|
||||
Check(params.hash == regs.ps_regs.chksum && params.code.data() == shader,
|
||||
"pixel shader program parameters lost source identity");
|
||||
|
||||
const uint32_t vcc_load_shader[] = {
|
||||
EncodeSMovB32(106, 27), EncodeSMovB32(107, 28), EncodeSmem0(0x02, 44, 53),
|
||||
@@ -11551,10 +11583,10 @@ void TestNewShaderRecompilerPixelPipelineEntry() {
|
||||
ShaderMapUserData(vcc_regs.ps_regs.data_addr, vcc_mapped);
|
||||
|
||||
ShaderPixelInputInfo vcc_input{};
|
||||
std::vector<uint32_t> vcc_spirv;
|
||||
Check(ShaderCompileSpirvPS(vcc_regs, sh, vcc_input, vcc_spirv),
|
||||
"VCC raw-load pointer was lost");
|
||||
CheckSpirvBinaryValidates(vcc_spirv);
|
||||
const auto vcc_params =
|
||||
PrepareProgram(vcc_regs, sh, vertex_info, mappings, vcc_input);
|
||||
std::string error;
|
||||
Check(CompilePixelRuntime(vcc_params, vcc_input, &error), error.c_str());
|
||||
}
|
||||
|
||||
void TestComputeLdsAllocationIdentity() {
|
||||
@@ -11577,19 +11609,28 @@ void TestComputeLdsAllocationIdentity() {
|
||||
uint32_t expected_dwords) {
|
||||
regs.cs_regs.lds_size = encoded_lds_size;
|
||||
ShaderComputeInputInfo input_info{};
|
||||
std::span<const uint32_t> spirv;
|
||||
Check(ShaderCompileInfoCS(regs, sh, false, input_info, spirv),
|
||||
"compute LDS allocation shader did not compile");
|
||||
const auto params = PrepareProgram(regs, sh, input_info);
|
||||
Check(input_info.lds_size_dwords == expected_dwords,
|
||||
"COMPUTE_PGM_RSRC2 LDS allocation units were not decoded");
|
||||
const std::vector<uint32_t> binary(spirv.begin(), spirv.end());
|
||||
Check(MeasureSpirv(binary).workgroup_variables == 1u,
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
options.shader_hash = params.hash;
|
||||
options.shader_base = params.Base();
|
||||
options.user_data = params.user_data.data();
|
||||
options.user_data_count = static_cast<uint32_t>(params.user_data.size());
|
||||
options.input_info.compute = &input_info;
|
||||
options.wave_size = input_info.wave_size;
|
||||
options.scratch_dwords = input_info.scratch_size_dwords;
|
||||
ShaderRecompiler::CompileResult result;
|
||||
std::string error;
|
||||
Check(ShaderRecompiler::TryRecompile(shader, options, result, &error),
|
||||
error.c_str());
|
||||
Check(MeasureSpirv(result.spirv).workgroup_variables == 1u,
|
||||
"LDS shader did not declare exactly one Workgroup variable");
|
||||
Check(SpirvArrayLengthCount(binary, expected_dwords) == 1u,
|
||||
Check(SpirvArrayLengthCount(result.spirv, expected_dwords) == 1u,
|
||||
"SPIR-V workgroup array did not use the declared LDS allocation");
|
||||
Check(SpirvUnsignedLessThanBoundCount(binary, expected_dwords) == 1u,
|
||||
Check(SpirvUnsignedLessThanBoundCount(result.spirv, expected_dwords) == 1u,
|
||||
"LDS bounds check did not use the declared allocation");
|
||||
CheckSpirvBinaryValidates(binary);
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
return input_info;
|
||||
};
|
||||
|
||||
@@ -11602,21 +11643,19 @@ void TestComputeLdsAllocationIdentity() {
|
||||
};
|
||||
const auto lds_1152 = compile(decode_lds_field(lds_1152_rsrc2), 1152u);
|
||||
const auto lds_896 = compile(decode_lds_field(lds_896_rsrc2), 896u);
|
||||
Check(ShaderGetIdCS(regs, lds_1152, true) !=
|
||||
ShaderGetIdCS(regs, lds_896, true),
|
||||
Check(MakeStageStaticKey(lds_1152) != MakeStageStaticKey(lds_896),
|
||||
"compute pipeline identity omitted the LDS allocation");
|
||||
|
||||
auto split_wave = lds_896;
|
||||
split_wave.needs_lds_barriers = true;
|
||||
Check(ShaderGetIdCS(regs, lds_896, true) !=
|
||||
ShaderGetIdCS(regs, split_wave, true),
|
||||
Check(MakeStageStaticKey(lds_896) != MakeStageStaticKey(split_wave),
|
||||
"compute shader identity omitted split-wave LDS synchronization");
|
||||
|
||||
auto tg_size_disabled = lds_896;
|
||||
auto tg_size_enabled = lds_896;
|
||||
tg_size_enabled.tg_size_en = true;
|
||||
Check(ShaderGetIdCS(regs, tg_size_disabled, false) !=
|
||||
ShaderGetIdCS(regs, tg_size_enabled, false),
|
||||
Check(MakeStageStaticKey(tg_size_disabled) !=
|
||||
MakeStageStaticKey(tg_size_enabled),
|
||||
"compute shader identity omitted TG_SIZE semantics");
|
||||
|
||||
auto dispatch_disabled = lds_896;
|
||||
@@ -11625,32 +11664,42 @@ void TestComputeLdsAllocationIdentity() {
|
||||
dispatch_disabled.dispatch_threads_num[2] = 1;
|
||||
auto dispatch_enabled = dispatch_disabled;
|
||||
dispatch_enabled.dispatch_thread_dimensions = true;
|
||||
Check(ShaderGetIdCS(regs, dispatch_disabled, false) ==
|
||||
ShaderGetIdCS(regs, dispatch_enabled, false),
|
||||
"runtime dispatch enable created a compute shader variant");
|
||||
Check(MakeStageStaticKey(dispatch_disabled) !=
|
||||
MakeStageStaticKey(dispatch_enabled),
|
||||
"dispatch-dimension mode did not select a compute shader variant");
|
||||
|
||||
auto second_extent = dispatch_enabled;
|
||||
second_extent.dispatch_threads_num[0] = 1920;
|
||||
second_extent.dispatch_threads_num[1] = 1080;
|
||||
second_extent.dispatch_threads_num[2] = 4;
|
||||
Check(ShaderGetIdCS(regs, dispatch_enabled, false) ==
|
||||
ShaderGetIdCS(regs, second_extent, false),
|
||||
Check(MakeStageStaticKey(dispatch_enabled) ==
|
||||
MakeStageStaticKey(second_extent),
|
||||
"runtime dispatch extent created a compute shader variant");
|
||||
|
||||
mapped.scratch_size_dwords = 7;
|
||||
ShaderMapUserData(regs.cs_regs.data_addr, mapped);
|
||||
regs.cs_regs.lds_size = decode_lds_field(lds_896_rsrc2);
|
||||
ShaderComputeInputInfo scratch_info{};
|
||||
std::span<const uint32_t> scratch_spirv;
|
||||
Check(ShaderCompileInfoCS(regs, sh, false, scratch_info, scratch_spirv),
|
||||
"compute scratch metadata shader did not compile");
|
||||
const auto scratch_params = PrepareProgram(regs, sh, scratch_info);
|
||||
Check(scratch_info.scratch_size_dwords == 7,
|
||||
"AGC per-thread scratch size was not propagated");
|
||||
Check(scratch_info.stage.program != nullptr &&
|
||||
scratch_info.stage.program->scratch_dwords == 7,
|
||||
auto scratch_options = MakeCompileOptions(ShaderType::Compute);
|
||||
scratch_options.shader_hash = scratch_params.hash;
|
||||
scratch_options.shader_base = scratch_params.Base();
|
||||
scratch_options.user_data = scratch_params.user_data.data();
|
||||
scratch_options.user_data_count =
|
||||
static_cast<uint32_t>(scratch_params.user_data.size());
|
||||
scratch_options.input_info.compute = &scratch_info;
|
||||
scratch_options.wave_size = scratch_info.wave_size;
|
||||
scratch_options.scratch_dwords = scratch_info.scratch_size_dwords;
|
||||
ShaderRecompiler::CompileResult scratch_result;
|
||||
std::string scratch_error;
|
||||
Check(ShaderRecompiler::TryRecompile(scratch_params.code, scratch_options,
|
||||
scratch_result, &scratch_error),
|
||||
scratch_error.c_str());
|
||||
Check(scratch_result.program.scratch_dwords == 7,
|
||||
"AGC per-thread scratch size did not reach the compiler program");
|
||||
Check(ShaderGetIdCS(regs, scratch_info, true) !=
|
||||
ShaderGetIdCS(regs, lds_896, true),
|
||||
Check(MakeStageStaticKey(scratch_info) != MakeStageStaticKey(lds_896),
|
||||
"compute pipeline identity omitted the scratch allocation");
|
||||
|
||||
const uint32_t append_shader[] = {
|
||||
@@ -11810,20 +11859,18 @@ void TestPixelProgramCacheBindingIdentity() {
|
||||
const uint32_t shader_10[] = {0xbf810000u};
|
||||
HW::ShaderRegisters sh{};
|
||||
|
||||
HW::PixelShaderInfo identity_regs{};
|
||||
ShaderPixelInputInfo no_depth_export{};
|
||||
auto depth_export = no_depth_export;
|
||||
depth_export.ps_depth_export_enable = true;
|
||||
Check(ShaderGetIdPS(identity_regs, no_depth_export, false) !=
|
||||
ShaderGetIdPS(identity_regs, depth_export, false),
|
||||
Check(MakeStageStaticKey(no_depth_export) != MakeStageStaticKey(depth_export),
|
||||
"pixel shader identity omitted depth-export semantics");
|
||||
auto shifted_push = no_depth_export;
|
||||
shifted_push.push_constant_offset = 36;
|
||||
Check(ShaderGetIdPS(identity_regs, no_depth_export, false) !=
|
||||
ShaderGetIdPS(identity_regs, shifted_push, false),
|
||||
Check(MakeStageStaticKey(no_depth_export) != MakeStageStaticKey(shifted_push),
|
||||
"pixel shader identity omitted graphics push-bank placement");
|
||||
|
||||
auto check_cache_identity = [&](const uint32_t *shader, uint64_t checksum) {
|
||||
auto check_program_identity = [&](const uint32_t *shader,
|
||||
uint64_t checksum) {
|
||||
HW::PixelShaderInfo regs{};
|
||||
regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(shader);
|
||||
regs.ps_regs.chksum = checksum;
|
||||
@@ -11834,26 +11881,29 @@ void TestPixelProgramCacheBindingIdentity() {
|
||||
const std::array<Prospero::ColorComponentMapping, 8> identity_mappings{};
|
||||
ShaderVertexInputInfo vertex_info{};
|
||||
ShaderPixelInputInfo first_info{};
|
||||
std::span<const uint32_t> first_spirv;
|
||||
Check(ShaderCompileInfoPS(regs, sh, vertex_info, identity_mappings, first_info,
|
||||
first_spirv),
|
||||
"pixel program-cache fixture failed to compile");
|
||||
const auto first_params =
|
||||
PrepareProgram(regs, sh, vertex_info, identity_mappings, first_info);
|
||||
const auto first_key = MakeStageStaticKey(first_info);
|
||||
std::string error;
|
||||
Check(CompilePixelRuntime(first_params, first_info, &error), error.c_str());
|
||||
|
||||
ShaderPixelInputInfo second_info{};
|
||||
std::span<const uint32_t> second_spirv;
|
||||
Check(ShaderCompileInfoPS(regs, sh, vertex_info, identity_mappings, second_info,
|
||||
second_spirv),
|
||||
"pixel program-cache lookup failed");
|
||||
const auto second_params =
|
||||
PrepareProgram(regs, sh, vertex_info, identity_mappings, second_info);
|
||||
Check(
|
||||
first_info.stage.program != nullptr &&
|
||||
second_info.stage.program == first_info.stage.program &&
|
||||
second_spirv.data() == first_spirv.data() &&
|
||||
second_spirv.size() == first_spirv.size(),
|
||||
"pixel program cache did not reuse an identical graphics placement");
|
||||
first_params.hash == second_params.hash &&
|
||||
first_key == MakeStageStaticKey(second_info) &&
|
||||
first_info.stage.program != nullptr &&
|
||||
MaterializeProgram(first_info.stage.program, second_params, second_info) &&
|
||||
second_info.stage.program == first_info.stage.program,
|
||||
"pixel program matching did not reuse an identical graphics placement");
|
||||
return std::pair {first_params.hash, first_key};
|
||||
};
|
||||
|
||||
check_cache_identity(shader_01, 0x91a27e6300000001ull);
|
||||
check_cache_identity(shader_10, 0x91a27e6300000002ull);
|
||||
const auto request_01 = check_program_identity(shader_01, 0);
|
||||
const auto request_10 = check_program_identity(shader_10, 0);
|
||||
Check(request_01 == request_10,
|
||||
"relocated identical pixel programs did not share their source identity");
|
||||
|
||||
const uint32_t push_shader[] = {
|
||||
EncodeVop1(0x01, 0, 0), EncodeVop1(0x01, 1, 1),
|
||||
@@ -11883,24 +11933,36 @@ void TestPixelProgramCacheBindingIdentity() {
|
||||
ShaderPixelInputInfo at_zero{};
|
||||
ShaderPixelInputInfo at_36{};
|
||||
ShaderPixelInputInfo at_zero_again{};
|
||||
std::span<const uint32_t> spirv_at_zero;
|
||||
std::span<const uint32_t> spirv_at_36;
|
||||
std::span<const uint32_t> spirv_at_zero_again;
|
||||
Check(ShaderCompileInfoPS(push_regs, push_sh, vertex_at_zero, mappings,
|
||||
at_zero, spirv_at_zero) &&
|
||||
ShaderCompileInfoPS(push_regs, push_sh, vertex_at_36, mappings,
|
||||
at_36, spirv_at_36) &&
|
||||
ShaderCompileInfoPS(push_regs, push_sh, vertex_at_zero, mappings,
|
||||
at_zero_again, spirv_at_zero_again),
|
||||
"pixel program-cache placement fixture failed to compile");
|
||||
const auto params_at_zero =
|
||||
PrepareProgram(push_regs, push_sh, vertex_at_zero, mappings, at_zero);
|
||||
const auto key_at_zero = MakeStageStaticKey(at_zero);
|
||||
std::string error;
|
||||
Check(CompilePixelRuntime(params_at_zero, at_zero, &error), error.c_str());
|
||||
const auto params_at_36 =
|
||||
PrepareProgram(push_regs, push_sh, vertex_at_36, mappings, at_36);
|
||||
const auto key_at_36 = MakeStageStaticKey(at_36);
|
||||
Check(CompilePixelRuntime(params_at_36, at_36, &error), error.c_str());
|
||||
const auto params_at_zero_again =
|
||||
PrepareProgram(push_regs, push_sh, vertex_at_zero, mappings,
|
||||
at_zero_again);
|
||||
auto shifted_options = MakeCompileOptions(ShaderType::Pixel);
|
||||
shifted_options.input_info.pixel = &at_36;
|
||||
shifted_options.push_constant_offset = at_36.push_constant_offset;
|
||||
ShaderRecompiler::CompileResult shifted_result;
|
||||
std::string shifted_error;
|
||||
Check(ShaderRecompiler::TryRecompile(push_shader, shifted_options,
|
||||
shifted_result, &shifted_error),
|
||||
shifted_error.c_str());
|
||||
Check(at_zero.push_constant_offset == 0 &&
|
||||
at_36.push_constant_offset == 36 &&
|
||||
key_at_zero != key_at_36 &&
|
||||
MakeStageStaticKey(at_zero_again) == key_at_zero &&
|
||||
at_zero.stage.program != at_36.stage.program &&
|
||||
spirv_at_zero.data() != spirv_at_36.data() &&
|
||||
MaterializeProgram(at_zero.stage.program, params_at_zero_again,
|
||||
at_zero_again) &&
|
||||
at_zero_again.stage.program == at_zero.stage.program &&
|
||||
spirv_at_zero_again.data() == spirv_at_zero.data() &&
|
||||
SpirvHasMemberDecorationValue(spirv_at_36, 35u, 36u),
|
||||
"pixel program cache did not partition and reuse graphics push placement");
|
||||
SpirvHasMemberDecorationValue(shifted_result.spirv, 35u, 36u),
|
||||
"pixel program matching did not partition and reuse graphics push placement");
|
||||
}
|
||||
|
||||
void TestGraphicsPushConstantPlacement() {
|
||||
|
||||
Reference in New Issue
Block a user