mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
pipeline: create pipelines from GraphicsPipelineKey and shader modules
This commit is contained in:
@@ -595,13 +595,6 @@ void LogDrawPhase(const char* draw_name, const char* phase) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogPipelineTrace(const char* phase, uint64_t vertex_program_id, uint64_t pixel_program_id) {
|
|
||||||
if (graphics_debug_dump_enabled()) {
|
|
||||||
LOGF("PipelineTrace: %s VS=%" PRIu64 " PS=%" PRIu64 "\n", phase, vertex_program_id,
|
|
||||||
pixel_program_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void VpPrint(const char* func, const HW::ScreenViewport& vp,
|
static void VpPrint(const char* func, const HW::ScreenViewport& vp,
|
||||||
const HW::ScanModeControl& smc) {
|
const HW::ScanModeControl& smc) {
|
||||||
LOGF("%s\n", func);
|
LOGF("%s\n", func);
|
||||||
|
|||||||
@@ -681,7 +681,7 @@ void RenderExecutor::PrepareBindings(const ShaderStageRuntime& runtime,
|
|||||||
PreparedBindings& prepared) {
|
PreparedBindings& prepared) {
|
||||||
KYTY_PROFILER_FUNCTION();
|
KYTY_PROFILER_FUNCTION();
|
||||||
EXIT_IF(!runtime);
|
EXIT_IF(!runtime);
|
||||||
const auto& program = *runtime.program;
|
const auto& program = runtime.module->info;
|
||||||
const auto& snapshot = *runtime.resources;
|
const auto& snapshot = *runtime.resources;
|
||||||
prepared.runtime = &runtime;
|
prepared.runtime = &runtime;
|
||||||
prepared.gds = {nullptr, 0, VK_WHOLE_SIZE};
|
prepared.gds = {nullptr, 0, VK_WHOLE_SIZE};
|
||||||
@@ -723,7 +723,7 @@ void RenderExecutor::FindBuffers(std::span<PreparedBindings* const> stages) {
|
|||||||
for (auto* stage: stages) {
|
for (auto* stage: stages) {
|
||||||
auto& prepared = *stage;
|
auto& prepared = *stage;
|
||||||
EXIT_IF(prepared.runtime == nullptr || !*prepared.runtime);
|
EXIT_IF(prepared.runtime == nullptr || !*prepared.runtime);
|
||||||
const auto& program = *prepared.runtime->program;
|
const auto& program = prepared.runtime->module->info;
|
||||||
const auto& snapshot = *prepared.runtime->resources;
|
const auto& snapshot = *prepared.runtime->resources;
|
||||||
const auto& layout = program.bindings;
|
const auto& layout = program.bindings;
|
||||||
prepared.buffer_sources.resize(layout.descriptor_counts[static_cast<size_t>(BindingKind::Buffers)]);
|
prepared.buffer_sources.resize(layout.descriptor_counts[static_cast<size_t>(BindingKind::Buffers)]);
|
||||||
@@ -780,7 +780,7 @@ void RenderExecutor::FindBuffers(std::span<PreparedBindings* const> stages) {
|
|||||||
void RenderExecutor::RebindBuffers(PreparedBindings& prepared) {
|
void RenderExecutor::RebindBuffers(PreparedBindings& prepared) {
|
||||||
KYTY_PROFILER_FUNCTION();
|
KYTY_PROFILER_FUNCTION();
|
||||||
EXIT_IF(prepared.runtime == nullptr || !*prepared.runtime);
|
EXIT_IF(prepared.runtime == nullptr || !*prepared.runtime);
|
||||||
const auto& program = *prepared.runtime->program;
|
const auto& program = prepared.runtime->module->info;
|
||||||
const auto& snapshot = *prepared.runtime->resources;
|
const auto& snapshot = *prepared.runtime->resources;
|
||||||
const auto& layout = program.bindings;
|
const auto& layout = program.bindings;
|
||||||
EXIT_IF(prepared.buffer_sources.size() != layout.descriptor_counts[static_cast<size_t>(BindingKind::Buffers)]);
|
EXIT_IF(prepared.buffer_sources.size() != layout.descriptor_counts[static_cast<size_t>(BindingKind::Buffers)]);
|
||||||
@@ -813,7 +813,7 @@ void RenderExecutor::RebindBuffers(PreparedBindings& prepared) {
|
|||||||
void RenderExecutor::RebindImages(PreparedBindings& prepared) {
|
void RenderExecutor::RebindImages(PreparedBindings& prepared) {
|
||||||
KYTY_PROFILER_FUNCTION();
|
KYTY_PROFILER_FUNCTION();
|
||||||
EXIT_IF(prepared.runtime == nullptr || !*prepared.runtime);
|
EXIT_IF(prepared.runtime == nullptr || !*prepared.runtime);
|
||||||
const auto& program = *prepared.runtime->program;
|
const auto& program = prepared.runtime->module->info;
|
||||||
const auto& snapshot = *prepared.runtime->resources;
|
const auto& snapshot = *prepared.runtime->resources;
|
||||||
auto& images = prepared.images;
|
auto& images = prepared.images;
|
||||||
EXIT_IF(images.size() != program.info.images.size());
|
EXIT_IF(images.size() != program.info.images.size());
|
||||||
@@ -859,8 +859,8 @@ void RenderExecutor::PrepareGraphicsBindings(std::span<PreparedBindings* const>
|
|||||||
bool uses_image_heap = false;
|
bool uses_image_heap = false;
|
||||||
FindBuffers(stages);
|
FindBuffers(stages);
|
||||||
for (auto* stage: stages) {
|
for (auto* stage: stages) {
|
||||||
uses_dma |= stage->runtime->program->info.uses_dma;
|
uses_dma |= stage->runtime->module->info.info.uses_dma;
|
||||||
uses_image_heap |= stage->runtime->program->info.uses_image_heap;
|
uses_image_heap |= stage->runtime->module->info.info.uses_image_heap;
|
||||||
}
|
}
|
||||||
if (uses_dma) {
|
if (uses_dma) {
|
||||||
m_context.PrepareBda();
|
m_context.PrepareBda();
|
||||||
@@ -909,7 +909,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
: vk::ShaderStageFlags {};
|
: vk::ShaderStageFlags {};
|
||||||
for (const auto* prepared: prepared_bindings) {
|
for (const auto* prepared: prepared_bindings) {
|
||||||
EXIT_IF(prepared == nullptr || prepared->runtime == nullptr || !*prepared->runtime);
|
EXIT_IF(prepared == nullptr || prepared->runtime == nullptr || !*prepared->runtime);
|
||||||
const auto& program = *prepared->runtime->program;
|
const auto& program = prepared->runtime->module->info;
|
||||||
write_count += std::popcount(program.bindings.descriptor_mask);
|
write_count += std::popcount(program.bindings.descriptor_mask);
|
||||||
for (auto mask = program.bindings.descriptor_mask; mask != 0; mask &= mask - 1) {
|
for (auto mask = program.bindings.descriptor_mask; mask != 0; mask &= mask - 1) {
|
||||||
const auto index = std::countr_zero(mask);
|
const auto index = std::countr_zero(mask);
|
||||||
@@ -930,7 +930,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
const auto& reads = reader->runtime->resources->specialization_reads;
|
const auto& reads = reader->runtime->resources->specialization_reads;
|
||||||
if (reads.empty()) continue;
|
if (reads.empty()) continue;
|
||||||
for (const auto* writer: prepared_bindings) {
|
for (const auto* writer: prepared_bindings) {
|
||||||
if (writer->runtime->program->has_address_writes) {
|
if (writer->runtime->module->info.has_address_writes) {
|
||||||
EXIT("scalar resource reads cannot be proven disjoint from shader address writes\n");
|
EXIT("scalar resource reads cannot be proven disjoint from shader address writes\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -947,7 +947,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto* writer: prepared_bindings) {
|
for (const auto* writer: prepared_bindings) {
|
||||||
const auto& program = *writer->runtime->program;
|
const auto& program = writer->runtime->module->info;
|
||||||
for (const auto& resource: program.info.buffers) {
|
for (const auto& resource: program.info.buffers) {
|
||||||
if (!resource.written || resource.descriptor_index == UINT32_MAX) continue;
|
if (!resource.written || resource.descriptor_index == UINT32_MAX) continue;
|
||||||
const auto& written = writer->buffer_sources[resource.descriptor_index];
|
const auto& written = writer->buffer_sources[resource.descriptor_index];
|
||||||
@@ -973,7 +973,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
std::array<vk::DescriptorBufferInfo, 2> address_buffers;
|
std::array<vk::DescriptorBufferInfo, 2> address_buffers;
|
||||||
|
|
||||||
for (auto* prepared: prepared_bindings) {
|
for (auto* prepared: prepared_bindings) {
|
||||||
const auto& program = *prepared->runtime->program;
|
const auto& program = prepared->runtime->module->info;
|
||||||
auto& descriptors = *prepared;
|
auto& descriptors = *prepared;
|
||||||
const auto shader_stage = NativeShaderStage(program.stage);
|
const auto shader_stage = NativeShaderStage(program.stage);
|
||||||
const auto shader_stages = ShaderPipelineStages(shader_stage);
|
const auto shader_stages = ShaderPipelineStages(shader_stage);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "graphics/host_gpu/renderer/pipeline/blendMapping.h"
|
#include "graphics/host_gpu/renderer/pipeline/blendMapping.h"
|
||||||
#include "graphics/host_gpu/renderer/render.h"
|
#include "graphics/host_gpu/renderer/render.h"
|
||||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||||
|
#include "graphics/shader/recompiler/BufferFormat.h"
|
||||||
#include "graphics/shader/recompiler/ShaderRecompiler.h"
|
#include "graphics/shader/recompiler/ShaderRecompiler.h"
|
||||||
#include "graphics/shader/shaderCompiler.h"
|
#include "graphics/shader/shaderCompiler.h"
|
||||||
#include "kernel/memory.h"
|
#include "kernel/memory.h"
|
||||||
@@ -198,86 +199,122 @@ void PackSpecialization(const ShaderRecompiler::IR::ResourceSpecialization& spec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
// Formats with a narrower host variant drop the components the shader does not read.
|
||||||
|
vk::Format NarrowInputFormat(vk::Format format, uint32_t used_components) {
|
||||||
std::size_t PipelineCache::GraphicsPipelineKeyHash::operator()(const GraphicsPipelineKey& key) const {
|
switch (format) {
|
||||||
std::size_t hash = 0;
|
case vk::Format::eR32G32B32A32Sfloat:
|
||||||
PipelineKeyHash::Mix(hash, key.rendering.color_count);
|
switch (used_components) {
|
||||||
for (uint32_t i = 0; i < key.rendering.color_count; i++) {
|
case 1: return vk::Format::eR32Sfloat;
|
||||||
PipelineKeyHash::Mix(hash, static_cast<uint32_t>(key.rendering.color_formats[i]));
|
case 2: return vk::Format::eR32G32Sfloat;
|
||||||
|
case 3: return vk::Format::eR32G32B32Sfloat;
|
||||||
|
default: return format;
|
||||||
|
}
|
||||||
|
case vk::Format::eR32G32B32Sfloat:
|
||||||
|
switch (used_components) {
|
||||||
|
case 1: return vk::Format::eR32Sfloat;
|
||||||
|
case 2: return vk::Format::eR32G32Sfloat;
|
||||||
|
default: return format;
|
||||||
|
}
|
||||||
|
case vk::Format::eR16G16B16A16Sfloat:
|
||||||
|
switch (used_components) {
|
||||||
|
case 1: return vk::Format::eR16Sfloat;
|
||||||
|
case 2: return vk::Format::eR16G16Sfloat;
|
||||||
|
default: return format;
|
||||||
|
}
|
||||||
|
case vk::Format::eR8G8B8A8Unorm:
|
||||||
|
switch (used_components) {
|
||||||
|
case 1: return vk::Format::eR8Unorm;
|
||||||
|
case 2: return vk::Format::eR8G8Unorm;
|
||||||
|
default: return format;
|
||||||
|
}
|
||||||
|
case vk::Format::eR8G8B8A8Snorm:
|
||||||
|
return used_components == 2 ? vk::Format::eR8G8Snorm : format;
|
||||||
|
case vk::Format::eR8G8B8A8Uint:
|
||||||
|
switch (used_components) {
|
||||||
|
case 1: return vk::Format::eR8Uint;
|
||||||
|
case 2: return vk::Format::eR8G8Uint;
|
||||||
|
default: return format;
|
||||||
|
}
|
||||||
|
default: return format;
|
||||||
}
|
}
|
||||||
PipelineKeyHash::Mix(hash, static_cast<uint32_t>(key.rendering.depth_format));
|
|
||||||
PipelineKeyHash::Mix(hash, static_cast<uint32_t>(key.rendering.stencil_format));
|
|
||||||
for (const auto id: key.vertex_shader_ids) {
|
|
||||||
PipelineKeyHash::Mix(hash, id);
|
|
||||||
}
|
|
||||||
PipelineKeyHash::Mix(hash, key.ps_shader_id);
|
|
||||||
PipelineKeyHash::Mix(hash, key.vertex_input.binding_count);
|
|
||||||
for (uint32_t i = 0; i < key.vertex_input.binding_count; i++) {
|
|
||||||
PipelineKeyHash::Mix(hash, key.vertex_input.bindings[i].stride);
|
|
||||||
PipelineKeyHash::Mix(hash, key.vertex_input.bindings[i].instance);
|
|
||||||
}
|
|
||||||
PipelineKeyHash::Mix(hash, key.vertex_input.attribute_count);
|
|
||||||
for (uint32_t i = 0; i < key.vertex_input.attribute_count; i++) {
|
|
||||||
PipelineKeyHash::Mix(hash, key.vertex_input.attributes[i].offset);
|
|
||||||
PipelineKeyHash::Mix(hash, key.vertex_input.attributes[i].binding);
|
|
||||||
}
|
|
||||||
PipelineKeyHash::Mix(hash, XXH3_64bits(&key.static_params, sizeof(key.static_params)));
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PipelineCache::Module {
|
vk::Format InputFormat(const ShaderBufferResource& resource, uint32_t used_components) {
|
||||||
std::vector<uint32_t> function_code;
|
switch (resource.RawFormat()) {
|
||||||
ShaderRecompiler::IR::ResourceSpecialization specialization;
|
// Temporary: invalid PS5 buffer format 113 (VertexAttribFormat::k16_16SInt).
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo info;
|
case 113: return NarrowInputFormat(vk::Format::eR32G32B32A32Sfloat, used_components);
|
||||||
ShaderProgram handle;
|
case 121: return vk::Format::eR16G16Sfloat;
|
||||||
};
|
default: break;
|
||||||
|
|
||||||
struct PipelineCache::Program {
|
|
||||||
std::span<const uint32_t> FunctionCode() const {
|
|
||||||
return call_source
|
|
||||||
? std::span<const uint32_t>(call_source->linked->code).subspan(call_source->code.size())
|
|
||||||
: std::span<const uint32_t>{};
|
|
||||||
}
|
}
|
||||||
|
const auto format = VulkanFormat(resource.Format());
|
||||||
bool RefreshCallSource(const ShaderRecompiler::IR::SrtRuntime& runtime) {
|
if (format == vk::Format::eUndefined ||
|
||||||
const auto revision = call_source->revision;
|
ShaderRecompiler::Format::GetFormatInfo(resource.Format()).component_count == 0) {
|
||||||
ShaderRecompiler::RefreshShaderSource(*call_source, runtime);
|
EXIT("unknown vertex format: fmt = %u\n", resource.RawFormat());
|
||||||
resource_plan.source_reads = call_source->reads;
|
|
||||||
return revision != call_source->revision;
|
|
||||||
}
|
}
|
||||||
|
return NarrowInputFormat(format, used_components);
|
||||||
|
}
|
||||||
|
|
||||||
template <bool HasCalls>
|
// The host format of each vertex input attribute, narrowed to the components the stage reads.
|
||||||
Module* FindModule(const ShaderRecompiler::IR::SrtRuntime& runtime, uint32_t push_data_cursor) {
|
std::vector<vk::Format> VertexInputFormats(const ShaderVertexInputInfo& input_info,
|
||||||
EXIT_IF(!ShaderRecompiler::IR::MaterializeResources(
|
const ShaderRecompiler::IR::CompiledShaderInfo& program) {
|
||||||
resource_plan, runtime, resources, specialization));
|
std::vector<vk::Format> formats(input_info.resources_num);
|
||||||
for (auto& candidate: modules) {
|
for (int index = 0; index < input_info.resources_num; index++) {
|
||||||
const auto& layout = candidate.info.bindings;
|
const auto registers_num = input_info.resources_dst[index].registers_num;
|
||||||
if (layout.push_data_start_dword != ShaderRecompiler::IR::PushData::StartFor(
|
EXIT_IF(registers_num < 1 || registers_num > 4);
|
||||||
push_data_cursor, layout.ShaderDataDwords()) ||
|
const auto fetched = program.info.vertex_fetch_components[index];
|
||||||
candidate.specialization != specialization) {
|
formats[index] = InputFormat(input_info.resources[index],
|
||||||
continue;
|
fetched > 0 ? fetched : static_cast<uint32_t>(registers_num));
|
||||||
}
|
}
|
||||||
if constexpr (HasCalls) {
|
return formats;
|
||||||
if (!std::ranges::equal(candidate.function_code, FunctionCode())) continue;
|
}
|
||||||
}
|
|
||||||
return &candidate;
|
} // namespace
|
||||||
|
|
||||||
|
bool GraphicsPipelineKey::operator==(const GraphicsPipelineKey& other) const {
|
||||||
|
return std::memcmp(this, &other, sizeof(*this)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t PipelineCache::GraphicsPipelineKeyHash::operator()(const GraphicsPipelineKey& key) const {
|
||||||
|
return XXH3_64bits(&key, sizeof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::span<const uint32_t> PipelineCache::Program::FunctionCode() const {
|
||||||
|
return call_source
|
||||||
|
? std::span<const uint32_t>(call_source->linked->code).subspan(call_source->code.size())
|
||||||
|
: std::span<const uint32_t>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PipelineCache::Program::RefreshCallSource(const ShaderRecompiler::IR::SrtRuntime& runtime) {
|
||||||
|
const auto revision = call_source->revision;
|
||||||
|
ShaderRecompiler::RefreshShaderSource(*call_source, runtime);
|
||||||
|
resource_plan.source_reads = call_source->reads;
|
||||||
|
return revision != call_source->revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool HasCalls>
|
||||||
|
ShaderModule* PipelineCache::Program::FindModule(const ShaderRecompiler::IR::SrtRuntime& runtime,
|
||||||
|
uint32_t push_data_cursor) {
|
||||||
|
EXIT_IF(!ShaderRecompiler::IR::MaterializeResources(resource_plan, runtime, resources,
|
||||||
|
specialization));
|
||||||
|
for (auto& candidate: modules) {
|
||||||
|
const auto& layout = candidate.info.bindings;
|
||||||
|
if (layout.push_data_start_dword != ShaderRecompiler::IR::PushData::StartFor(
|
||||||
|
push_data_cursor, layout.ShaderDataDwords()) ||
|
||||||
|
candidate.specialization != specialization) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
return nullptr;
|
if constexpr (HasCalls) {
|
||||||
|
if (!std::ranges::equal(candidate.function_code, FunctionCode())) continue;
|
||||||
|
}
|
||||||
|
return &candidate;
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<ShaderRecompiler::ShaderSource> call_source;
|
ShaderModule& PipelineCache::CompileModule(Program& program, const ProgramKey& key,
|
||||||
ShaderRecompiler::IR::ResourcePlan resource_plan;
|
ShaderRecompiler::CompileOptions options,
|
||||||
ShaderRecompiler::IR::ResourceSnapshot resources;
|
ShaderRecompiler::TranslateResult translated,
|
||||||
ShaderRecompiler::IR::ResourceSpecialization specialization;
|
uint32_t push_data_cursor) {
|
||||||
std::vector<Module> modules;
|
|
||||||
bool skip_dispatch = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
PipelineCache::Module& PipelineCache::CompileModule(Program& program, const ProgramKey& key,
|
|
||||||
ShaderRecompiler::CompileOptions options,
|
|
||||||
ShaderRecompiler::TranslateResult translated,
|
|
||||||
uint32_t push_data_cursor) {
|
|
||||||
Common::DebugCounters::ScopedTimer timer(Common::DebugCounters::Counter::ShadersCompiled,
|
Common::DebugCounters::ScopedTimer timer(Common::DebugCounters::Counter::ShadersCompiled,
|
||||||
Common::DebugCounters::Counter::ShaderCompileNs,
|
Common::DebugCounters::Counter::ShaderCompileNs,
|
||||||
Common::DebugCounters::Peak::ShaderCompileNs);
|
Common::DebugCounters::Peak::ShaderCompileNs);
|
||||||
@@ -302,19 +339,27 @@ PipelineCache::Module& PipelineCache::CompileModule(Program& program, const Prog
|
|||||||
const auto* stage = ShaderRecompiler::StageName(key.stage);
|
const auto* stage = ShaderRecompiler::StageName(key.stage);
|
||||||
DumpShader(result.spirv, fmt::format("{}_{:016x}_{:016x}.spv", stage, key.hash, id));
|
DumpShader(result.spirv, fmt::format("{}_{:016x}_{:016x}.spv", stage, key.hash, id));
|
||||||
ValidateShaderSpirv(stage, key.hash, result.spirv, profile.maintenance8);
|
ValidateShaderSpirv(stage, key.hash, result.spirv, profile.maintenance8);
|
||||||
const auto module = CompileSPV(result.spirv, m_graphics.device);
|
auto& module = program.modules.emplace_back(ShaderModule {
|
||||||
EXIT_IF(module == nullptr);
|
.id = id,
|
||||||
return program.modules.emplace_back(Module {
|
.module = CompileSPV(result.spirv, m_graphics.device),
|
||||||
.function_code = {function_code.begin(), function_code.end()},
|
|
||||||
.specialization = program.specialization,
|
|
||||||
.info = std::move(info),
|
.info = std::move(info),
|
||||||
.handle = {.id = id, .module = module},
|
.specialization = program.specialization,
|
||||||
|
.function_code = {function_code.begin(), function_code.end()},
|
||||||
});
|
});
|
||||||
|
EXIT_IF(module.module == nullptr);
|
||||||
|
// The inputs of these come from the stage's static key.
|
||||||
|
if (key.stage == ShaderType::Vertex || key.stage == ShaderType::Local) {
|
||||||
|
module.vertex_formats = VertexInputFormats(*options.input_info.vertex, module.info);
|
||||||
|
} else if (key.stage == ShaderType::Pixel &&
|
||||||
|
options.input_info.pixel->parameter_mode == ShaderPixelParameterMode::Rectangle) {
|
||||||
|
module.rect_parameters = RectListParameters(*options.input_info.pixel, module.info);
|
||||||
|
}
|
||||||
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename InputInfo>
|
template <typename InputInfo>
|
||||||
ShaderProgram PipelineCache::GetProgram(const ShaderParams& params, InputInfo& input_info,
|
const ShaderModule* PipelineCache::GetProgram(const ShaderParams& params, InputInfo& input_info,
|
||||||
uint32_t& push_data_cursor) {
|
uint32_t& push_data_cursor) {
|
||||||
const auto user_data = std::span(params.user_data).first(params.user_data_count);
|
const auto user_data = std::span(params.user_data).first(params.user_data_count);
|
||||||
ShaderRecompiler::IR::SrtRuntime runtime {
|
ShaderRecompiler::IR::SrtRuntime runtime {
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
@@ -348,18 +393,16 @@ ShaderProgram PipelineCache::GetProgram(const ShaderParams& params, InputInfo& i
|
|||||||
m_lookup_key.user_data_count = params.user_data_count;
|
m_lookup_key.user_data_count = params.user_data_count;
|
||||||
BuildStageStaticKey(input_info, m_lookup_key.static_state);
|
BuildStageStaticKey(input_info, m_lookup_key.static_state);
|
||||||
auto entry = m_program_cache.find(m_lookup_key);
|
auto entry = m_program_cache.find(m_lookup_key);
|
||||||
const auto bind = [&](const Module& module) {
|
const auto bind = [&](const ShaderModule& module) {
|
||||||
input_info.stage = {.program = &module.info,
|
input_info.stage = {.module = &module, .resources = &entry->second.resources};
|
||||||
.resources = &entry->second->resources,
|
|
||||||
.handle = &module.handle};
|
|
||||||
module.info.bindings.AdvancePushData(push_data_cursor);
|
module.info.bindings.AdvancePushData(push_data_cursor);
|
||||||
return module.handle;
|
return &module;
|
||||||
};
|
};
|
||||||
bool source_changed = false;
|
bool source_changed = false;
|
||||||
if (entry != m_program_cache.end()) {
|
if (entry != m_program_cache.end()) {
|
||||||
auto& cached = *entry->second;
|
auto& cached = entry->second;
|
||||||
if (cached.skip_dispatch) return {};
|
if (cached.skip_dispatch) return nullptr;
|
||||||
Module* module = nullptr;
|
ShaderModule* module = nullptr;
|
||||||
if (cached.call_source) {
|
if (cached.call_source) {
|
||||||
source_changed = cached.RefreshCallSource(runtime);
|
source_changed = cached.RefreshCallSource(runtime);
|
||||||
if (!source_changed) module = cached.FindModule<true>(runtime, push_data_cursor);
|
if (!source_changed) module = cached.FindModule<true>(runtime, push_data_cursor);
|
||||||
@@ -383,12 +426,11 @@ ShaderProgram PipelineCache::GetProgram(const ShaderParams& params, InputInfo& i
|
|||||||
PipelineCacheLog("!!! TEMPORARY COMPUTE DISPATCH SKIP !!! shader=0x{:016x} pc=0x{:08x} "
|
PipelineCacheLog("!!! TEMPORARY COMPUTE DISPATCH SKIP !!! shader=0x{:016x} pc=0x{:08x} "
|
||||||
"reason=unsupported GPU-selected callable target; rendering is incomplete",
|
"reason=unsupported GPU-selected callable target; rendering is incomplete",
|
||||||
params.hash, source.unsupported_call_pc);
|
params.hash, source.unsupported_call_pc);
|
||||||
m_program_cache.emplace(m_lookup_key, std::make_unique<Program>())
|
m_program_cache.emplace(m_lookup_key, Program {.skip_dispatch = true});
|
||||||
.first->second->skip_dispatch = true;
|
return nullptr;
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto* current = entry == m_program_cache.end() ? &source : entry->second->call_source.get();
|
auto* current = entry == m_program_cache.end() ? &source : entry->second.call_source.get();
|
||||||
ShaderRecompiler::TranslateResult translated;
|
ShaderRecompiler::TranslateResult translated;
|
||||||
if (current != nullptr) {
|
if (current != nullptr) {
|
||||||
if (!current->calls.empty()) {
|
if (!current->calls.empty()) {
|
||||||
@@ -405,18 +447,20 @@ ShaderProgram PipelineCache::GetProgram(const ShaderParams& params, InputInfo& i
|
|||||||
auto retained = !source.calls.empty()
|
auto retained = !source.calls.empty()
|
||||||
? std::make_unique<ShaderRecompiler::ShaderSource>(std::move(source))
|
? std::make_unique<ShaderRecompiler::ShaderSource>(std::move(source))
|
||||||
: nullptr;
|
: nullptr;
|
||||||
entry = m_program_cache.emplace(m_lookup_key, std::make_unique<Program>(
|
entry = m_program_cache.emplace(m_lookup_key, Program {
|
||||||
std::move(retained), ShaderRecompiler::IR::ExtractResourcePlan(translated.program))).first;
|
.call_source = std::move(retained),
|
||||||
|
.resource_plan = ShaderRecompiler::IR::ExtractResourcePlan(translated.program),
|
||||||
|
}).first;
|
||||||
|
auto& program = entry->second;
|
||||||
EXIT_IF(!ShaderRecompiler::IR::MaterializeResources(
|
EXIT_IF(!ShaderRecompiler::IR::MaterializeResources(
|
||||||
entry->second->resource_plan, runtime, entry->second->resources,
|
program.resource_plan, runtime, program.resources, program.specialization));
|
||||||
entry->second->specialization));
|
|
||||||
} else if (source_changed) {
|
} else if (source_changed) {
|
||||||
entry->second->resource_plan = ShaderRecompiler::IR::ExtractResourcePlan(translated.program);
|
entry->second.resource_plan = ShaderRecompiler::IR::ExtractResourcePlan(translated.program);
|
||||||
if (const auto* module = entry->second->FindModule<true>(runtime, push_data_cursor)) {
|
if (const auto* module = entry->second.FindModule<true>(runtime, push_data_cursor)) {
|
||||||
return bind(*module);
|
return bind(*module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bind(CompileModule(*entry->second, entry->first, options, std::move(translated),
|
return bind(CompileModule(entry->second, entry->first, options, std::move(translated),
|
||||||
push_data_cursor));
|
push_data_cursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,8 +484,8 @@ PipelineCache::~PipelineCache() {
|
|||||||
destroy(m_graphics_pipelines);
|
destroy(m_graphics_pipelines);
|
||||||
destroy(m_compute_pipelines);
|
destroy(m_compute_pipelines);
|
||||||
for (const auto& program: m_program_cache | std::views::values) {
|
for (const auto& program: m_program_cache | std::views::values) {
|
||||||
for (const auto& module: program->modules) {
|
for (const auto& module: program.modules) {
|
||||||
m_graphics.device.destroyShaderModule(module.handle.module, nullptr);
|
m_graphics.device.destroyShaderModule(module.module, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_driver_cache != nullptr) {
|
if (m_driver_cache != nullptr) {
|
||||||
@@ -766,8 +810,8 @@ void PipelineCache::GetGraphicsPrograms(const CommandBuffer& command, DrawRender
|
|||||||
uint32_t push_data_cursor = ShaderRecompiler::IR::PushData::GraphicsDrawDwords(
|
uint32_t push_data_cursor = ShaderRecompiler::IR::PushData::GraphicsDrawDwords(
|
||||||
mesh_active, object_primitive_id, last_stage.user_clip_planes);
|
mesh_active, object_primitive_id, last_stage.user_clip_planes);
|
||||||
if (pixel_active) {
|
if (pixel_active) {
|
||||||
GetProgram(pixel_params, pixel_info, push_data_cursor);
|
const auto& pixel_module = *GetProgram(pixel_params, pixel_info, push_data_cursor);
|
||||||
for (const auto& output: pixel_info.stage.program->info.outputs) {
|
for (const auto& output: pixel_module.info.info.outputs) {
|
||||||
if (output.kind == ShaderRecompiler::IR::StageOutputKind::Mrt ||
|
if (output.kind == ShaderRecompiler::IR::StageOutputKind::Mrt ||
|
||||||
output.kind == ShaderRecompiler::IR::StageOutputKind::ObjectPrimitiveId) {
|
output.kind == ShaderRecompiler::IR::StageOutputKind::ObjectPrimitiveId) {
|
||||||
state.mrt_mask |= 1u << output.location;
|
state.mrt_mask |= 1u << output.location;
|
||||||
@@ -780,8 +824,8 @@ void PipelineCache::GetGraphicsPrograms(const CommandBuffer& command, DrawRender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderProgram PipelineCache::GetComputeProgram(const HW::ComputeShaderInfo& regs,
|
const ShaderModule* PipelineCache::GetComputeProgram(const HW::ComputeShaderInfo& regs,
|
||||||
ShaderComputeInputInfo& input_info) {
|
ShaderComputeInputInfo& input_info) {
|
||||||
input_info.host_subgroup_size = m_graphics.SupportsComputeWave64() ? 64u : 32u;
|
input_info.host_subgroup_size = m_graphics.SupportsComputeWave64() ? 64u : 32u;
|
||||||
const auto params = PrepareProgram(regs, input_info);
|
const auto params = PrepareProgram(regs, input_info);
|
||||||
input_info.lds_storage = input_info.lds_size_dwords * 4u >
|
input_info.lds_storage = input_info.lds_size_dwords * 4u >
|
||||||
@@ -790,38 +834,38 @@ ShaderProgram PipelineCache::GetComputeProgram(const HW::ComputeShaderInfo& regs
|
|||||||
return GetProgram(params, input_info, push_data_cursor);
|
return GetProgram(params, input_info, push_data_cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other) const noexcept {
|
|
||||||
return std::memcmp(this, &other, sizeof(*this)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(const CommandBuffer& command,
|
PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(const CommandBuffer& command,
|
||||||
const DrawRenderState& state) {
|
const DrawRenderState& state) {
|
||||||
const auto* colors = state.color_info;
|
const auto* colors = state.color_info;
|
||||||
const auto& depth = state.depth_info;
|
const auto& depth = state.depth_info;
|
||||||
const auto vertex_info = state.VertexStages();
|
const auto vertex_info = state.VertexStages();
|
||||||
const auto& ps_input_info = state.ps_input_info;
|
const auto& ps_input_info = state.ps_input_info;
|
||||||
const auto& vs_input_info = vertex_info.front();
|
const auto& vs_input_info = vertex_info.front();
|
||||||
const auto* vertex_program = vs_input_info.stage.handle;
|
|
||||||
const auto* pixel_program = state.ps_input_info.stage.handle;
|
|
||||||
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Gfx)", profiler::colors::DeepOrangeA200);
|
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Gfx)", profiler::colors::DeepOrangeA200);
|
||||||
|
|
||||||
EXIT_IF(vertex_program == nullptr);
|
const bool ps_active = state.ps_active;
|
||||||
const bool ps_active = state.ps_active;
|
const bool tessellation = vertex_info.size() == 3;
|
||||||
EXIT_IF(ps_active && pixel_program == nullptr);
|
std::array<const ShaderModule*, 4> stages {};
|
||||||
|
for (uint32_t i = 0; i < vertex_info.size(); i++) {
|
||||||
|
stages[i] = vertex_info[i].stage.module;
|
||||||
|
}
|
||||||
|
if (ps_active) {
|
||||||
|
stages[3] = ps_input_info.stage.module;
|
||||||
|
}
|
||||||
|
EXIT_IF(stages[0] == nullptr || (ps_active && stages[3] == nullptr));
|
||||||
|
const bool mesh = stages[0]->info.stage == ShaderType::Mesh;
|
||||||
const auto color_count = state.color_count;
|
const auto color_count = state.color_count;
|
||||||
|
|
||||||
auto& ctx = command.GetRegisters();
|
auto& ctx = command.GetRegisters();
|
||||||
|
|
||||||
const HW::ModeControl& mc = ctx.GetModeControl();
|
const HW::ModeControl& mc = ctx.GetModeControl();
|
||||||
|
|
||||||
const auto vs_id = vertex_program->id;
|
|
||||||
const auto ps_id = ps_active ? pixel_program->id : 0;
|
|
||||||
|
|
||||||
GraphicsPipelineKey key {};
|
GraphicsPipelineKey key {};
|
||||||
for (uint32_t i = 0; i < vertex_info.size(); i++) {
|
for (uint32_t i = 0; i < stages.size(); i++) {
|
||||||
key.vertex_shader_ids[i] = vertex_info[i].stage.handle->id;
|
if (stages[i] != nullptr) {
|
||||||
|
key.stage_ids[i] = stages[i]->id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
key.ps_shader_id = ps_id;
|
|
||||||
auto& static_params = key.static_params;
|
auto& static_params = key.static_params;
|
||||||
auto& rendering = key.rendering;
|
auto& rendering = key.rendering;
|
||||||
rendering.color_count = 0;
|
rendering.color_count = 0;
|
||||||
@@ -943,8 +987,15 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(const CommandBuffer&
|
|||||||
static_params.provoking_vtx_last = mc.provoking_vtx_last;
|
static_params.provoking_vtx_last = mc.provoking_vtx_last;
|
||||||
static_params.polygon_mode =
|
static_params.polygon_mode =
|
||||||
ResolvePolygonMode(mc, static_params.cull_front, static_params.cull_back);
|
ResolvePolygonMode(mc, static_params.cull_front, static_params.cull_back);
|
||||||
|
if (tessellation) {
|
||||||
|
static_params.patch_control_points =
|
||||||
|
static_cast<uint8_t>(vs_input_info.tess.input_control_points);
|
||||||
|
} else if (!mesh && static_params.topology == vk::PrimitiveTopology::ePatchList) {
|
||||||
|
// Rectangle lists expand through generated tessellation stages.
|
||||||
|
static_params.patch_control_points = 3;
|
||||||
|
}
|
||||||
|
|
||||||
if (vs_input_info.stage.program->stage != ShaderType::Mesh) {
|
if (!mesh) {
|
||||||
EXIT_IF(vs_input_info.buffers_num < 0 ||
|
EXIT_IF(vs_input_info.buffers_num < 0 ||
|
||||||
vs_input_info.buffers_num > ShaderVertexInputInfo::RES_MAX ||
|
vs_input_info.buffers_num > ShaderVertexInputInfo::RES_MAX ||
|
||||||
vs_input_info.resources_num < 0 ||
|
vs_input_info.resources_num < 0 ||
|
||||||
@@ -979,22 +1030,16 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(const CommandBuffer&
|
|||||||
ShaderDbgDumpInputInfo(ps_input_info);
|
ShaderDbgDumpInputInfo(ps_input_info);
|
||||||
}
|
}
|
||||||
LOGF("PipelineTrace: shader modules VS=%" PRIu64 " module=%p PS=%" PRIu64 " module=%p\n",
|
LOGF("PipelineTrace: shader modules VS=%" PRIu64 " module=%p PS=%" PRIu64 " module=%p\n",
|
||||||
vs_id, static_cast<void*>(vertex_program->module), ps_id,
|
key.stage_ids[0], static_cast<void*>(stages[0]->module), key.stage_ids[3],
|
||||||
ps_active ? static_cast<void*>(pixel_program->module) : nullptr);
|
ps_active ? static_cast<void*>(stages[3]->module) : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPipelineTrace("CreatePipelineInternal begin", vs_id, ps_id);
|
|
||||||
{
|
{
|
||||||
Common::DebugCounters::ScopedTimer timer(Common::DebugCounters::Counter::PipelinesCreated,
|
Common::DebugCounters::ScopedTimer timer(Common::DebugCounters::Counter::PipelinesCreated,
|
||||||
Common::DebugCounters::Counter::PipelineCreateNs,
|
Common::DebugCounters::Counter::PipelineCreateNs,
|
||||||
Common::DebugCounters::Peak::PipelineCreateNs);
|
Common::DebugCounters::Peak::PipelineCreateNs);
|
||||||
CreatePipelineInternal(m_graphics, pipeline, rendering, key.vertex_input, state,
|
CreatePipelineInternal(m_graphics, pipeline, key, stages, m_driver_cache);
|
||||||
static_params, m_driver_cache);
|
|
||||||
}
|
}
|
||||||
LogPipelineTrace("CreatePipelineInternal done", vs_id, ps_id);
|
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
|
|
||||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
|
|
||||||
CheckpointDriverCache();
|
CheckpointDriverCache();
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
@@ -1003,10 +1048,10 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(const CommandBuffer&
|
|||||||
PipelineCache::Pipeline& PipelineCache::GetComputePipeline(const ShaderComputeInputInfo& input_info) {
|
PipelineCache::Pipeline& PipelineCache::GetComputePipeline(const ShaderComputeInputInfo& input_info) {
|
||||||
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100);
|
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100);
|
||||||
|
|
||||||
EXIT_IF(input_info.stage.handle == nullptr);
|
EXIT_IF(input_info.stage.module == nullptr);
|
||||||
const auto& compute_program = *input_info.stage.handle;
|
const auto& module = *input_info.stage.module;
|
||||||
|
|
||||||
auto [iter, inserted] = m_compute_pipelines.try_emplace(compute_program.id);
|
auto [iter, inserted] = m_compute_pipelines.try_emplace(module.id);
|
||||||
auto& pipeline = iter->second;
|
auto& pipeline = iter->second;
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
return pipeline;
|
return pipeline;
|
||||||
@@ -1020,12 +1065,8 @@ PipelineCache::Pipeline& PipelineCache::GetComputePipeline(const ShaderComputeIn
|
|||||||
Common::DebugCounters::ScopedTimer timer(Common::DebugCounters::Counter::PipelinesCreated,
|
Common::DebugCounters::ScopedTimer timer(Common::DebugCounters::Counter::PipelinesCreated,
|
||||||
Common::DebugCounters::Counter::PipelineCreateNs,
|
Common::DebugCounters::Counter::PipelineCreateNs,
|
||||||
Common::DebugCounters::Peak::PipelineCreateNs);
|
Common::DebugCounters::Peak::PipelineCreateNs);
|
||||||
CreatePipelineInternal(m_graphics, pipeline, input_info, compute_program.module,
|
CreatePipelineInternal(m_graphics, pipeline, module, m_driver_cache);
|
||||||
m_driver_cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
|
|
||||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
|
|
||||||
CheckpointDriverCache();
|
CheckpointDriverCache();
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
||||||
#include "graphics/host_gpu/renderer/renderTarget.h"
|
#include "graphics/host_gpu/renderer/renderTarget.h"
|
||||||
#include "graphics/host_gpu/vulkanCommon.h"
|
#include "graphics/host_gpu/vulkanCommon.h"
|
||||||
|
#include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h"
|
||||||
|
#include "graphics/shader/rectListShader.h"
|
||||||
#include "graphics/shader/shader.h"
|
#include "graphics/shader/shader.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -27,6 +29,7 @@ class CommandBuffer;
|
|||||||
|
|
||||||
namespace ShaderRecompiler {
|
namespace ShaderRecompiler {
|
||||||
struct CompileOptions;
|
struct CompileOptions;
|
||||||
|
struct ShaderSource;
|
||||||
struct TranslateResult;
|
struct TranslateResult;
|
||||||
} // namespace ShaderRecompiler
|
} // namespace ShaderRecompiler
|
||||||
|
|
||||||
@@ -40,6 +43,8 @@ struct PipelineStaticParameters {
|
|||||||
bool negative_one_to_one = false;
|
bool negative_one_to_one = false;
|
||||||
bool depth_clip_enable = true;
|
bool depth_clip_enable = true;
|
||||||
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
|
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
|
||||||
|
// 0 without tessellation, 3 for a rectangle list, else the input control points.
|
||||||
|
uint8_t patch_control_points = 0;
|
||||||
bool primitive_restart_enable = false;
|
bool primitive_restart_enable = false;
|
||||||
uint32_t samples = 1;
|
uint32_t samples = 1;
|
||||||
bool sample_shading_enable = false;
|
bool sample_shading_enable = false;
|
||||||
@@ -58,51 +63,59 @@ struct PipelineStaticParameters {
|
|||||||
uint8_t alpha_destblend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
uint8_t alpha_destblend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||||
bool separate_alpha_blend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
bool separate_alpha_blend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||||
bool blend_enable[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
bool blend_enable[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||||
|
|
||||||
bool operator==(const PipelineStaticParameters& other) const noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
static_assert(std::is_trivially_copyable_v<PipelineStaticParameters>);
|
|
||||||
static_assert(std::is_standard_layout_v<PipelineStaticParameters>);
|
|
||||||
static_assert(alignof(PipelineStaticParameters) == 1);
|
|
||||||
static_assert(sizeof(PipelineStaticParameters) == 117);
|
|
||||||
|
|
||||||
struct PipelineRenderingState {
|
struct PipelineRenderingState {
|
||||||
std::array<vk::Format, RENDER_COLOR_ATTACHMENTS_MAX> color_formats {};
|
std::array<vk::Format, RENDER_COLOR_ATTACHMENTS_MAX> color_formats {};
|
||||||
vk::Format depth_format = vk::Format::eUndefined;
|
vk::Format depth_format = vk::Format::eUndefined;
|
||||||
vk::Format stencil_format = vk::Format::eUndefined;
|
vk::Format stencil_format = vk::Format::eUndefined;
|
||||||
uint32_t color_count = 0;
|
uint32_t color_count = 0;
|
||||||
|
|
||||||
bool operator==(const PipelineRenderingState&) const = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PipelineVertexInputState {
|
struct PipelineVertexInputState {
|
||||||
struct Binding {
|
struct Binding {
|
||||||
uint32_t stride = 0;
|
uint32_t stride = 0;
|
||||||
bool instance = false;
|
uint8_t instance = 0;
|
||||||
bool operator==(const Binding&) const = default;
|
|
||||||
};
|
};
|
||||||
struct Attribute {
|
struct Attribute {
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
uint8_t binding = 0;
|
uint8_t binding = 0;
|
||||||
bool operator==(const Attribute&) const = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<Binding, ShaderVertexInputInfo::RES_MAX> bindings {};
|
std::array<Binding, ShaderVertexInputInfo::RES_MAX> bindings {};
|
||||||
std::array<Attribute, ShaderVertexInputInfo::RES_MAX> attributes {};
|
std::array<Attribute, ShaderVertexInputInfo::RES_MAX> attributes {};
|
||||||
uint8_t binding_count = 0;
|
uint8_t binding_count = 0;
|
||||||
uint8_t attribute_count = 0;
|
uint8_t attribute_count = 0;
|
||||||
|
|
||||||
bool operator==(const PipelineVertexInputState&) const = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShaderProgram {
|
// Everything a graphics pipeline is made of besides the stage modules its ids name. Aligned so
|
||||||
uint64_t id = 0;
|
// that rendering.color_formats can be passed to Vulkan.
|
||||||
vk::ShaderModule module = nullptr;
|
struct alignas(4) GraphicsPipelineKey {
|
||||||
|
// VS, LS or mesh; HS; TES; PS. 0 marks an absent stage.
|
||||||
|
std::array<uint64_t, 4> stage_ids {};
|
||||||
|
PipelineRenderingState rendering;
|
||||||
|
PipelineVertexInputState vertex_input;
|
||||||
|
PipelineStaticParameters static_params;
|
||||||
|
|
||||||
explicit operator bool() const { return module != nullptr; }
|
bool operator==(const GraphicsPipelineKey& other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
// Keys are compared and hashed as bytes.
|
||||||
|
static_assert(std::has_unique_object_representations_v<GraphicsPipelineKey>);
|
||||||
|
|
||||||
|
// A compiled stage with what pipeline creation needs from it besides the key.
|
||||||
|
struct ShaderModule {
|
||||||
|
uint64_t id = 0;
|
||||||
|
vk::ShaderModule module = nullptr;
|
||||||
|
ShaderRecompiler::IR::CompiledShaderInfo info;
|
||||||
|
ShaderRecompiler::IR::ResourceSpecialization specialization;
|
||||||
|
std::vector<uint32_t> function_code;
|
||||||
|
// VS or LS: the host format of each vertex input attribute.
|
||||||
|
std::vector<vk::Format> vertex_formats;
|
||||||
|
// Rectangle-list PS: the parameters it reads.
|
||||||
|
std::vector<RectListParameter> rect_parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A draw's topology, shader stages (from PipelineCache::GetGraphicsPrograms) and targets.
|
// A draw's topology, shader stages (from PipelineCache::GetGraphicsPrograms) and targets.
|
||||||
@@ -141,16 +154,30 @@ public:
|
|||||||
|
|
||||||
// Reads the shaders and registers bound in `command` into the state's shader stages.
|
// Reads the shaders and registers bound in `command` into the state's shader stages.
|
||||||
void GetGraphicsPrograms(const CommandBuffer& command, DrawRenderState& state);
|
void GetGraphicsPrograms(const CommandBuffer& command, DrawRenderState& state);
|
||||||
// An empty program skips the dispatch.
|
// Null skips the dispatch.
|
||||||
ShaderProgram GetComputeProgram(const HW::ComputeShaderInfo& regs,
|
const ShaderModule* GetComputeProgram(const HW::ComputeShaderInfo& regs,
|
||||||
ShaderComputeInputInfo& input_info);
|
ShaderComputeInputInfo& input_info);
|
||||||
|
|
||||||
Pipeline& GetGraphicsPipeline(const CommandBuffer& command, const DrawRenderState& state);
|
Pipeline& GetGraphicsPipeline(const CommandBuffer& command, const DrawRenderState& state);
|
||||||
Pipeline& GetComputePipeline(const ShaderComputeInputInfo& input_info);
|
Pipeline& GetComputePipeline(const ShaderComputeInputInfo& input_info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Module;
|
friend struct PipelineCacheTestAccess;
|
||||||
struct Program;
|
|
||||||
|
struct Program {
|
||||||
|
std::unique_ptr<ShaderRecompiler::ShaderSource> call_source;
|
||||||
|
ShaderRecompiler::IR::ResourcePlan resource_plan;
|
||||||
|
ShaderRecompiler::IR::ResourceSnapshot resources;
|
||||||
|
ShaderRecompiler::IR::ResourceSpecialization specialization;
|
||||||
|
std::vector<ShaderModule> modules;
|
||||||
|
bool skip_dispatch = false;
|
||||||
|
|
||||||
|
[[nodiscard]] std::span<const uint32_t> FunctionCode() const;
|
||||||
|
bool RefreshCallSource(const ShaderRecompiler::IR::SrtRuntime& runtime);
|
||||||
|
template <bool HasCalls>
|
||||||
|
ShaderModule* FindModule(const ShaderRecompiler::IR::SrtRuntime& runtime,
|
||||||
|
uint32_t push_data_cursor);
|
||||||
|
};
|
||||||
|
|
||||||
struct ProgramKey {
|
struct ProgramKey {
|
||||||
ShaderType stage = ShaderType::Unknown;
|
ShaderType stage = ShaderType::Unknown;
|
||||||
@@ -166,34 +193,13 @@ private:
|
|||||||
std::size_t operator()(const ProgramKey& key) const { return key.hash; }
|
std::size_t operator()(const ProgramKey& key) const { return key.hash; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GraphicsPipelineKey {
|
|
||||||
PipelineRenderingState rendering;
|
|
||||||
std::array<uint64_t, 3> vertex_shader_ids {};
|
|
||||||
uint64_t ps_shader_id = 0;
|
|
||||||
PipelineVertexInputState vertex_input;
|
|
||||||
PipelineStaticParameters static_params;
|
|
||||||
|
|
||||||
bool operator==(const GraphicsPipelineKey& other) const {
|
|
||||||
return rendering == other.rendering && vertex_shader_ids == other.vertex_shader_ids &&
|
|
||||||
ps_shader_id == other.ps_shader_id && vertex_input == other.vertex_input &&
|
|
||||||
static_params == other.static_params;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GraphicsPipelineKeyHash {
|
struct GraphicsPipelineKeyHash {
|
||||||
std::size_t operator()(const GraphicsPipelineKey& key) const;
|
std::size_t operator()(const GraphicsPipelineKey& key) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
GraphicContext& m_graphics;
|
GraphicContext& m_graphics;
|
||||||
ShaderRecompiler::IR::ImageHeapSource* m_image_heap;
|
ShaderRecompiler::IR::ImageHeapSource* m_image_heap;
|
||||||
std::unordered_map<ProgramKey, std::unique_ptr<Program>, ProgramKeyHash> m_program_cache;
|
std::unordered_map<ProgramKey, Program, ProgramKeyHash> m_program_cache;
|
||||||
ProgramKey m_lookup_key;
|
ProgramKey m_lookup_key;
|
||||||
vk::PipelineCache m_driver_cache = nullptr;
|
vk::PipelineCache m_driver_cache = nullptr;
|
||||||
std::filesystem::path m_driver_cache_path;
|
std::filesystem::path m_driver_cache_path;
|
||||||
@@ -203,25 +209,23 @@ private:
|
|||||||
std::unordered_map<uint64_t, Pipeline> m_compute_pipelines;
|
std::unordered_map<uint64_t, Pipeline> m_compute_pipelines;
|
||||||
|
|
||||||
template <typename InputInfo>
|
template <typename InputInfo>
|
||||||
ShaderProgram GetProgram(const ShaderParams& params, InputInfo& input_info,
|
const ShaderModule* GetProgram(const ShaderParams& params, InputInfo& input_info,
|
||||||
uint32_t& push_data_cursor);
|
uint32_t& push_data_cursor);
|
||||||
Module& CompileModule(Program& program, const ProgramKey& key,
|
ShaderModule& CompileModule(Program& program, const ProgramKey& key,
|
||||||
ShaderRecompiler::CompileOptions options,
|
ShaderRecompiler::CompileOptions options,
|
||||||
ShaderRecompiler::TranslateResult translated, uint32_t push_data_cursor);
|
ShaderRecompiler::TranslateResult translated,
|
||||||
|
uint32_t push_data_cursor);
|
||||||
void InitializeDriverCache();
|
void InitializeDriverCache();
|
||||||
void CheckpointDriverCache();
|
void CheckpointDriverCache();
|
||||||
};
|
};
|
||||||
|
|
||||||
void LogPipelineTrace(const char* phase, uint64_t vertex_program_id, uint64_t pixel_program_id);
|
// Stages are indexed like GraphicsPipelineKey::stage_ids.
|
||||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
||||||
const PipelineRenderingState& rendering,
|
const GraphicsPipelineKey& key,
|
||||||
const PipelineVertexInputState& vertex_input,
|
const std::array<const ShaderModule*, 4>& stages,
|
||||||
const DrawRenderState& state,
|
vk::PipelineCache driver_cache);
|
||||||
const PipelineStaticParameters& static_params,
|
|
||||||
vk::PipelineCache driver_cache);
|
|
||||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
||||||
const ShaderComputeInputInfo& input_info,
|
const ShaderModule& module, vk::PipelineCache driver_cache);
|
||||||
vk::ShaderModule compute_module, vk::PipelineCache driver_cache);
|
|
||||||
|
|
||||||
} // namespace Libs::Graphics
|
} // namespace Libs::Graphics
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "graphics/host_gpu/renderer/pipeline/pipelineCache.h"
|
||||||
#include "graphics/shader/shader.h"
|
#include "graphics/shader/shader.h"
|
||||||
#include "graphics/shader/shaderBindings.h"
|
#include "graphics/shader/shaderBindings.h"
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ vk::BufferMemoryBarrier MakeGdsDependency(vk::Buffer buffer) {
|
|||||||
|
|
||||||
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) {
|
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) {
|
||||||
EXIT_IF(!runtime);
|
EXIT_IF(!runtime);
|
||||||
const auto& program = *runtime.program;
|
const auto& program = runtime.module->info;
|
||||||
const auto& resources = *runtime.resources;
|
const auto& resources = *runtime.resources;
|
||||||
EXIT_IF(resources.buffers.size() != program.info.buffers.size());
|
EXIT_IF(resources.buffers.size() != program.info.buffers.size());
|
||||||
// Address writes reach memory outside the bound buffer descriptors.
|
// Address writes reach memory outside the bound buffer descriptors.
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||||
#include "graphics/host_gpu/renderer/renderTarget.h"
|
#include "graphics/host_gpu/renderer/renderTarget.h"
|
||||||
#include "graphics/host_gpu/vulkanCommon.h"
|
#include "graphics/host_gpu/vulkanCommon.h"
|
||||||
#include "graphics/shader/recompiler/BufferFormat.h"
|
|
||||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||||
#include "graphics/shader/rectListShader.h"
|
#include "graphics/shader/rectListShader.h"
|
||||||
#include "graphics/shader/shader.h"
|
#include "graphics/shader/shader.h"
|
||||||
@@ -21,124 +20,11 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <limits>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Libs::Graphics {
|
namespace Libs::Graphics {
|
||||||
|
|
||||||
// IDK: maybe we can remove it?
|
|
||||||
constexpr uint8_t kTemporaryVertexAttribFormat113 =
|
|
||||||
static_cast<uint8_t>(Prospero::VertexAttribFormat::k16_16SInt);
|
|
||||||
constexpr uint32_t kTemporaryPs5BufferFormat121 = 121u;
|
|
||||||
|
|
||||||
static bool NarrowInputFormat(vk::Format& format, uint32_t& size, uint32_t used_components) {
|
|
||||||
if (used_components == 0 || used_components >= size) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
size = used_components;
|
|
||||||
return true;
|
|
||||||
case vk::Format::eR8G8B8A8Snorm:
|
|
||||||
if (used_components != 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
size = used_components;
|
|
||||||
return true;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format, uint32_t& size,
|
|
||||||
uint32_t used_components) {
|
|
||||||
const auto fmt = res.Format();
|
|
||||||
const auto raw_format = res.RawFormat();
|
|
||||||
if (raw_format == kTemporaryVertexAttribFormat113) {
|
|
||||||
static bool logged_113 = false;
|
|
||||||
if (!logged_113) {
|
|
||||||
LOGF("InputFormat: temporary: accepting invalid PS5 buffer format 113 as "
|
|
||||||
"vk::Format::eR32G32B32A32Sfloat\n");
|
|
||||||
logged_113 = true;
|
|
||||||
}
|
|
||||||
format = vk::Format::eR32G32B32A32Sfloat;
|
|
||||||
size = 4;
|
|
||||||
if (NarrowInputFormat(format, size, used_components)) {
|
|
||||||
LOGF("InputFormat: narrowing fmt=%u to %s for used_components=%u\n", raw_format,
|
|
||||||
vk::to_string(format).c_str(), used_components);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (raw_format == kTemporaryPs5BufferFormat121) {
|
|
||||||
static bool logged_121 = false;
|
|
||||||
if (!logged_121) {
|
|
||||||
LOGF("InputFormat: accepting PS5 buffer format 121 as vk::Format::eR16G16Sfloat\n");
|
|
||||||
logged_121 = true;
|
|
||||||
}
|
|
||||||
format = vk::Format::eR16G16Sfloat;
|
|
||||||
size = 2;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
format = VulkanFormat(fmt);
|
|
||||||
size = ShaderRecompiler::Format::GetFormatInfo(fmt).component_count;
|
|
||||||
if (format == vk::Format::eUndefined || size == 0) {
|
|
||||||
EXIT("unknown vertex format: fmt = %u\n", raw_format);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NarrowInputFormat(format, size, used_components)) {
|
|
||||||
static std::atomic<uint64_t> log_count = 0;
|
|
||||||
auto log_id = log_count.fetch_add(1);
|
|
||||||
if (log_id < 32) {
|
|
||||||
LOGF("VertexInput: narrowed vertex format to %" PRIu32
|
|
||||||
" component(s) for shader fetch\n",
|
|
||||||
used_components);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static vk::BlendFactor GetBlendFactor(uint32_t factor) {
|
static vk::BlendFactor GetBlendFactor(uint32_t factor) {
|
||||||
switch (static_cast<Prospero::BlendFactor>(factor)) {
|
switch (static_cast<Prospero::BlendFactor>(factor)) {
|
||||||
case Prospero::BlendFactor::kZero: return vk::BlendFactor::eZero;
|
case Prospero::BlendFactor::kZero: return vk::BlendFactor::eZero;
|
||||||
@@ -242,30 +128,27 @@ static void CreateDescriptorLayout(GraphicContext& graphics, PipelineCache::Pipe
|
|||||||
|
|
||||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
||||||
const PipelineRenderingState& rendering,
|
const GraphicsPipelineKey& key,
|
||||||
const PipelineVertexInputState& vertex_input,
|
const std::array<const ShaderModule*, 4>& stages,
|
||||||
const DrawRenderState& state,
|
vk::PipelineCache driver_cache) {
|
||||||
const PipelineStaticParameters& static_params,
|
const auto& rendering = key.rendering;
|
||||||
vk::PipelineCache driver_cache) {
|
const auto& vertex_input = key.vertex_input;
|
||||||
const auto vertex_info = state.VertexStages();
|
const auto& static_params = key.static_params;
|
||||||
const auto& vs_input_info = vertex_info.front();
|
const auto& vertex = *stages[0];
|
||||||
const auto* ps_input_info = state.ps_active ? &state.ps_input_info : nullptr;
|
const auto* pixel = stages[3];
|
||||||
const auto& vertex_program = *vs_input_info.stage.handle;
|
const bool with_depth = rendering.depth_format != vk::Format::eUndefined ||
|
||||||
const auto* pixel_program = state.ps_input_info.stage.handle;
|
rendering.stencil_format != vk::Format::eUndefined;
|
||||||
const bool tessellation = vertex_info.size() == 3;
|
const bool mesh = vertex.info.stage == ShaderType::Mesh;
|
||||||
const bool ps_active = state.ps_active;
|
|
||||||
const bool with_depth = rendering.depth_format != vk::Format::eUndefined ||
|
|
||||||
rendering.stencil_format != vk::Format::eUndefined;
|
|
||||||
const bool mesh = vs_input_info.stage.program->stage == ShaderType::Mesh;
|
|
||||||
EXIT_NOT_IMPLEMENTED(mesh && !graphics.mesh_shader_enabled);
|
EXIT_NOT_IMPLEMENTED(mesh && !graphics.mesh_shader_enabled);
|
||||||
const bool rect_list =
|
const bool rect_list = static_params.patch_control_points != 0 && stages[1] == nullptr;
|
||||||
!mesh && !tessellation && static_params.topology == vk::PrimitiveTopology::ePatchList;
|
|
||||||
|
|
||||||
vk::ShaderModule tess_control_shader_module = nullptr;
|
vk::ShaderModule tess_control_shader_module = nullptr;
|
||||||
vk::ShaderModule tess_eval_shader_module = nullptr;
|
vk::ShaderModule tess_eval_shader_module = nullptr;
|
||||||
|
|
||||||
if (rect_list) {
|
if (rect_list) {
|
||||||
const auto shaders = BuildRectListShaders(vs_input_info, ps_input_info);
|
std::span<const RectListParameter> parameters;
|
||||||
|
if (pixel != nullptr) parameters = pixel->rect_parameters;
|
||||||
|
const auto shaders = BuildRectListShaders(parameters, vertex.info.param_export_mask);
|
||||||
tess_control_shader_module = CompileSPV(shaders.control, graphics.device);
|
tess_control_shader_module = CompileSPV(shaders.control, graphics.device);
|
||||||
if (graphics_debug_dump_enabled()) {
|
if (graphics_debug_dump_enabled()) {
|
||||||
LOGF("PipelineTrace: vkCreateShaderModule RectList TCS done module=%p\n",
|
LOGF("PipelineTrace: vkCreateShaderModule RectList TCS done module=%p\n",
|
||||||
@@ -284,11 +167,12 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
|
|
||||||
vk::PipelineShaderStageCreateInfo shader_stages[4] {};
|
vk::PipelineShaderStageCreateInfo shader_stages[4] {};
|
||||||
uint32_t shader_stage_count = 0;
|
uint32_t shader_stage_count = 0;
|
||||||
for (uint32_t i = 0; i < vertex_info.size(); i++) {
|
for (const auto* stage: stages) {
|
||||||
shader_stages[shader_stage_count++] = {.stage =
|
if (stage != nullptr) {
|
||||||
NativeShaderStage(vertex_info[i].logical_stage),
|
shader_stages[shader_stage_count++] = {.stage = NativeShaderStage(stage->info.stage),
|
||||||
.module = vertex_info[i].stage.handle->module,
|
.module = stage->module,
|
||||||
.pName = "main"};
|
.pName = "main"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (rect_list) {
|
if (rect_list) {
|
||||||
shader_stages[shader_stage_count++] = {.stage =
|
shader_stages[shader_stage_count++] = {.stage =
|
||||||
@@ -300,11 +184,6 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
.module = tess_eval_shader_module,
|
.module = tess_eval_shader_module,
|
||||||
.pName = "main"};
|
.pName = "main"};
|
||||||
}
|
}
|
||||||
if (ps_active) {
|
|
||||||
shader_stages[shader_stage_count++] = {.stage = vk::ShaderStageFlagBits::eFragment,
|
|
||||||
.module = pixel_program->module,
|
|
||||||
.pName = "main"};
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::VertexInputAttributeDescription input_attr[ShaderVertexInputInfo::RES_MAX] {};
|
vk::VertexInputAttributeDescription input_attr[ShaderVertexInputInfo::RES_MAX] {};
|
||||||
vk::VertexInputBindingDescription input_desc[ShaderVertexInputInfo::RES_MAX] {};
|
vk::VertexInputBindingDescription input_desc[ShaderVertexInputInfo::RES_MAX] {};
|
||||||
@@ -320,46 +199,7 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
input_attr[index].binding = vertex_input.attributes[index].binding;
|
input_attr[index].binding = vertex_input.attributes[index].binding;
|
||||||
input_attr[index].location = index;
|
input_attr[index].location = index;
|
||||||
input_attr[index].offset = vertex_input.attributes[index].offset;
|
input_attr[index].offset = vertex_input.attributes[index].offset;
|
||||||
|
input_attr[index].format = vertex.vertex_formats[index];
|
||||||
uint32_t attr_size = 4;
|
|
||||||
const auto registers_num = vs_input_info.resources_dst[index].registers_num;
|
|
||||||
const auto compiled_components =
|
|
||||||
vs_input_info.stage.program->info.vertex_fetch_components[index];
|
|
||||||
const auto used_components =
|
|
||||||
compiled_components > 0 ? static_cast<int>(compiled_components) : registers_num;
|
|
||||||
GetInputFormat(vs_input_info.resources[index], input_attr[index].format, attr_size,
|
|
||||||
static_cast<uint32_t>(used_components));
|
|
||||||
|
|
||||||
if (graphics_debug_dump_enabled()) {
|
|
||||||
static std::atomic_uint log_count = 0;
|
|
||||||
const auto log_id = log_count.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
if (log_id < 128) {
|
|
||||||
LOGF("VertexInputState[%u]: attr=%u binding=%u offset=%u stride=%u fmt=%d "
|
|
||||||
"src_fmt=%u dst=v%u regs=%u"
|
|
||||||
" 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[input_attr[index].binding].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>(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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
logged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EXIT_IF(registers_num < 1 || registers_num > 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::PipelineVertexInputStateCreateInfo vertex_input_info {};
|
vk::PipelineVertexInputStateCreateInfo vertex_input_info {};
|
||||||
@@ -467,16 +307,13 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
|
|
||||||
std::vector<vk::DescriptorSetLayoutBinding> descriptor_bindings;
|
std::vector<vk::DescriptorSetLayoutBinding> descriptor_bindings;
|
||||||
vk::ShaderStageFlags graphics_stages = vk::ShaderStageFlagBits::eFragment;
|
vk::ShaderStageFlags graphics_stages = vk::ShaderStageFlagBits::eFragment;
|
||||||
for (const auto& stage: vertex_info) {
|
for (const auto* stage: stages) {
|
||||||
const auto native_stage = NativeShaderStage(stage.logical_stage);
|
if (stage != nullptr) {
|
||||||
AddLayoutBindings(descriptor_bindings, *stage.stage.program, native_stage);
|
const auto native_stage = NativeShaderStage(stage->info.stage);
|
||||||
pipeline.uses_image_heap |= stage.stage.program->info.uses_image_heap;
|
AddLayoutBindings(descriptor_bindings, stage->info, native_stage);
|
||||||
graphics_stages |= native_stage;
|
pipeline.uses_image_heap |= stage->info.info.uses_image_heap;
|
||||||
}
|
graphics_stages |= native_stage;
|
||||||
if (ps_active) {
|
}
|
||||||
AddLayoutBindings(descriptor_bindings, *ps_input_info->stage.program,
|
|
||||||
vk::ShaderStageFlagBits::eFragment);
|
|
||||||
pipeline.uses_image_heap |= ps_input_info->stage.program->info.uses_image_heap;
|
|
||||||
}
|
}
|
||||||
CreateDescriptorLayout(graphics, pipeline, descriptor_bindings);
|
CreateDescriptorLayout(graphics, pipeline, descriptor_bindings);
|
||||||
const vk::PushConstantRange push_constants {graphics_stages, 0,
|
const vk::PushConstantRange push_constants {graphics_stages, 0,
|
||||||
@@ -494,7 +331,7 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
if (graphics_debug_dump_enabled()) {
|
if (graphics_debug_dump_enabled()) {
|
||||||
LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=%" PRIu64 " PS=%" PRIu64
|
LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=%" PRIu64 " PS=%" PRIu64
|
||||||
" set_layouts=1 push_constants=%" PRIu32 "\n",
|
" set_layouts=1 push_constants=%" PRIu32 "\n",
|
||||||
vertex_program.id, ps_active ? pixel_program->id : 0, 1u);
|
key.stage_ids[0], key.stage_ids[3], 1u);
|
||||||
}
|
}
|
||||||
auto result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
|
auto result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
|
||||||
&pipeline.pipeline_layout);
|
&pipeline.pipeline_layout);
|
||||||
@@ -504,8 +341,6 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
}
|
}
|
||||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
|
|
||||||
|
|
||||||
vk::PipelineDepthStencilStateCreateInfo depth_stencil_info {};
|
vk::PipelineDepthStencilStateCreateInfo depth_stencil_info {};
|
||||||
|
|
||||||
std::vector<vk::DynamicState> dynamic_states {
|
std::vector<vk::DynamicState> dynamic_states {
|
||||||
@@ -551,9 +386,9 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
pipeline_info.pVertexInputState = mesh ? nullptr : &vertex_input_info;
|
pipeline_info.pVertexInputState = mesh ? nullptr : &vertex_input_info;
|
||||||
pipeline_info.pInputAssemblyState = mesh ? nullptr : &input_assembly;
|
pipeline_info.pInputAssemblyState = mesh ? nullptr : &input_assembly;
|
||||||
vk::PipelineTessellationStateCreateInfo tessellation_state {};
|
vk::PipelineTessellationStateCreateInfo tessellation_state {};
|
||||||
tessellation_state.patchControlPoints =
|
tessellation_state.patchControlPoints = static_params.patch_control_points;
|
||||||
tessellation ? vs_input_info.tess.input_control_points : 3u;
|
pipeline_info.pTessellationState =
|
||||||
pipeline_info.pTessellationState = (rect_list || tessellation) ? &tessellation_state : nullptr;
|
static_params.patch_control_points != 0 ? &tessellation_state : nullptr;
|
||||||
pipeline_info.pViewportState = &viewport_state;
|
pipeline_info.pViewportState = &viewport_state;
|
||||||
pipeline_info.pRasterizationState = &rasterizer;
|
pipeline_info.pRasterizationState = &rasterizer;
|
||||||
pipeline_info.pMultisampleState = &multisampling;
|
pipeline_info.pMultisampleState = &multisampling;
|
||||||
@@ -569,7 +404,7 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=%" PRIu64 " PS=%" PRIu64
|
LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=%" PRIu64 " PS=%" PRIu64
|
||||||
" topology=%" PRIu32 " color_mask=0x%08" PRIx32
|
" topology=%" PRIu32 " color_mask=0x%08" PRIx32
|
||||||
" depth=%s blend=%s dyn_states=%" PRIu32 "\n",
|
" depth=%s blend=%s dyn_states=%" PRIu32 "\n",
|
||||||
vertex_program.id, ps_active ? pixel_program->id : 0,
|
key.stage_ids[0], key.stage_ids[3],
|
||||||
static_cast<uint32_t>(static_params.topology), static_params.color_mask[0],
|
static_cast<uint32_t>(static_params.topology), static_params.color_mask[0],
|
||||||
(with_depth ? "true" : "false"), (static_params.blend_enable[0] ? "true" : "false"),
|
(with_depth ? "true" : "false"), (static_params.blend_enable[0] ? "true" : "false"),
|
||||||
dynamic_state.dynamicStateCount);
|
dynamic_state.dynamicStateCount);
|
||||||
@@ -582,29 +417,18 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
}
|
}
|
||||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
|
graphics.device.destroyShaderModule(tess_control_shader_module, nullptr);
|
||||||
|
graphics.device.destroyShaderModule(tess_eval_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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
|
||||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
||||||
const ShaderComputeInputInfo& input_info,
|
const ShaderModule& module, vk::PipelineCache driver_cache) {
|
||||||
vk::ShaderModule compute_module, vk::PipelineCache driver_cache) {
|
|
||||||
EXIT_IF(compute_module == nullptr);
|
|
||||||
|
|
||||||
vk::PipelineShaderStageCreateInfo comp_shader_stage_info {};
|
vk::PipelineShaderStageCreateInfo comp_shader_stage_info {};
|
||||||
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo comp_subgroup_size {};
|
vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo comp_subgroup_size {};
|
||||||
comp_shader_stage_info.stage = vk::ShaderStageFlagBits::eCompute;
|
comp_shader_stage_info.stage = vk::ShaderStageFlagBits::eCompute;
|
||||||
comp_shader_stage_info.module = compute_module;
|
comp_shader_stage_info.module = module.module;
|
||||||
comp_shader_stage_info.pName = "main";
|
comp_shader_stage_info.pName = "main";
|
||||||
EXIT_IF(!input_info.stage);
|
const auto wave_size = module.info.wave_size;
|
||||||
const auto wave_size = input_info.stage.program->wave_size;
|
|
||||||
if (graphics.compute_subgroup_size_control_enabled &&
|
if (graphics.compute_subgroup_size_control_enabled &&
|
||||||
wave_size >= graphics.min_subgroup_size && wave_size <= graphics.max_subgroup_size) {
|
wave_size >= graphics.min_subgroup_size && wave_size <= graphics.max_subgroup_size) {
|
||||||
comp_subgroup_size.requiredSubgroupSize = wave_size;
|
comp_subgroup_size.requiredSubgroupSize = wave_size;
|
||||||
@@ -612,9 +436,8 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<vk::DescriptorSetLayoutBinding> descriptor_bindings;
|
std::vector<vk::DescriptorSetLayoutBinding> descriptor_bindings;
|
||||||
AddLayoutBindings(descriptor_bindings, *input_info.stage.program,
|
AddLayoutBindings(descriptor_bindings, module.info, vk::ShaderStageFlagBits::eCompute);
|
||||||
vk::ShaderStageFlagBits::eCompute);
|
pipeline.uses_image_heap = module.info.info.uses_image_heap;
|
||||||
pipeline.uses_image_heap = input_info.stage.program->info.uses_image_heap;
|
|
||||||
CreateDescriptorLayout(graphics, pipeline, descriptor_bindings);
|
CreateDescriptorLayout(graphics, pipeline, descriptor_bindings);
|
||||||
const vk::PushConstantRange push_constants {vk::ShaderStageFlagBits::eCompute, 0,
|
const vk::PushConstantRange push_constants {vk::ShaderStageFlagBits::eCompute, 0,
|
||||||
ShaderRecompiler::IR::NativePushConstantSize};
|
ShaderRecompiler::IR::NativePushConstantSize};
|
||||||
@@ -628,18 +451,12 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
|
|
||||||
EXIT_IF(pipeline.pipeline_layout != nullptr);
|
EXIT_IF(pipeline.pipeline_layout != nullptr);
|
||||||
|
|
||||||
LOGF("PipelineTrace: vkCreatePipelineLayout CS begin set_layouts=1 push_constants=%u\n",
|
|
||||||
1u);
|
|
||||||
auto result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
|
auto result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
|
||||||
&pipeline.pipeline_layout);
|
&pipeline.pipeline_layout);
|
||||||
LOGF("PipelineTrace: vkCreatePipelineLayout CS done result=%s layout=%p\n",
|
|
||||||
vk::to_string(result).c_str(), static_cast<void*>(pipeline.pipeline_layout));
|
|
||||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
|
|
||||||
|
|
||||||
vk::ComputePipelineCreateInfo info {};
|
vk::ComputePipelineCreateInfo info {};
|
||||||
if (input_info.stage.program->info.uses_gds) {
|
if (module.info.info.uses_gds) {
|
||||||
info.flags = vk::PipelineCreateFlagBits::eDispatchBase;
|
info.flags = vk::PipelineCreateFlagBits::eDispatchBase;
|
||||||
}
|
}
|
||||||
info.stage = comp_shader_stage_info;
|
info.stage = comp_shader_stage_info;
|
||||||
@@ -648,15 +465,9 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
|||||||
|
|
||||||
EXIT_IF(pipeline.pipeline != nullptr);
|
EXIT_IF(pipeline.pipeline != nullptr);
|
||||||
|
|
||||||
LOGF("PipelineTrace: vkCreateComputePipelines begin layout=%p\n",
|
|
||||||
static_cast<void*>(pipeline.pipeline_layout));
|
|
||||||
result = graphics.device.createComputePipelines(driver_cache, 1, &info, nullptr,
|
result = graphics.device.createComputePipelines(driver_cache, 1, &info, nullptr,
|
||||||
&pipeline.pipeline);
|
&pipeline.pipeline);
|
||||||
LOGF("PipelineTrace: vkCreateComputePipelines done result=%s pipeline=%p\n",
|
|
||||||
vk::to_string(result).c_str(), static_cast<void*>(pipeline.pipeline));
|
|
||||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline == nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libs::Graphics
|
} // namespace Libs::Graphics
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ static bool FillSourcesDisjoint(std::span<const ShaderRecompiler::IR::Descriptor
|
|||||||
|
|
||||||
bool RenderExecutor::TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input,
|
bool RenderExecutor::TryConsumeComputeMetaClear(const ShaderComputeInputInfo& input,
|
||||||
const CommandBuffer& buffer) {
|
const CommandBuffer& buffer) {
|
||||||
const auto& program = *input.stage.program;
|
const auto& program = input.stage.module->info;
|
||||||
const auto& resources = *input.stage.resources;
|
const auto& resources = *input.stage.resources;
|
||||||
if (resources.buffers.size() != program.info.buffers.size()) {
|
if (resources.buffers.size() != program.info.buffers.size()) {
|
||||||
EXIT("compute runtime buffer count does not match shader metadata\n");
|
EXIT("compute runtime buffer count does not match shader metadata\n");
|
||||||
@@ -135,7 +135,7 @@ bool ResolveComputeBufferFill(const ShaderComputeInputInfo& input, uint32_t grou
|
|||||||
bool RenderExecutor::TryConsumeComputeFill(const ShaderComputeInputInfo& input,
|
bool RenderExecutor::TryConsumeComputeFill(const ShaderComputeInputInfo& input,
|
||||||
CommandBuffer& command, uint32_t group_x,
|
CommandBuffer& command, uint32_t group_x,
|
||||||
uint32_t group_y, uint32_t group_z, uint32_t mode) {
|
uint32_t group_y, uint32_t group_z, uint32_t mode) {
|
||||||
const auto& program = *input.stage.program;
|
const auto& program = input.stage.module->info;
|
||||||
const auto& resources = *input.stage.resources;
|
const auto& resources = *input.stage.resources;
|
||||||
const auto& fill = resources.uniform_fill;
|
const auto& fill = resources.uniform_fill;
|
||||||
auto& cache = command.GetContext().GetTextureCache();
|
auto& cache = command.GetContext().GetTextureCache();
|
||||||
@@ -208,7 +208,7 @@ bool RenderExecutor::TryConsumeComputeFill(const ShaderComputeInputInfo& input,
|
|||||||
if (logged_clears.fetch_add(1, std::memory_order_relaxed) < 32) {
|
if (logged_clears.fetch_add(1, std::memory_order_relaxed) < 32) {
|
||||||
LOGF("GraphicsRenderDispatchDirect: compute %s shader=0x%016" PRIx64
|
LOGF("GraphicsRenderDispatchDirect: compute %s shader=0x%016" PRIx64
|
||||||
" addr=0x%016" PRIx64 " size=0x%016" PRIx64 " value=0x%08" PRIx32 "\n",
|
" addr=0x%016" PRIx64 " size=0x%016" PRIx64 " value=0x%08" PRIx32 "\n",
|
||||||
image_clear ? "image clear" : "buffer fill", input.stage.program->shader_hash,
|
image_clear ? "image clear" : "buffer fill", input.stage.module->info.shader_hash,
|
||||||
descriptor.Base48(), size, packed_clear);
|
descriptor.Base48(), size, packed_clear);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -216,7 +216,7 @@ bool RenderExecutor::TryConsumeComputeFill(const ShaderComputeInputInfo& input,
|
|||||||
|
|
||||||
static void BindSharedMemory(RenderContext& context, ShaderComputeInputInfo& input,
|
static void BindSharedMemory(RenderContext& context, ShaderComputeInputInfo& input,
|
||||||
PreparedBindings& bindings, uint64_t indirect_args = 0) {
|
PreparedBindings& bindings, uint64_t indirect_args = 0) {
|
||||||
if (input.stage.program->bindings.descriptor_counts[
|
if (input.stage.module->info.bindings.descriptor_counts[
|
||||||
static_cast<size_t>(ShaderRecompiler::IR::DescriptorBindingKind::SharedMemory)] == 0) {
|
static_cast<size_t>(ShaderRecompiler::IR::DescriptorBindingKind::SharedMemory)] == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -317,7 +317,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
input_info.dispatch_threads_num[2] = thread_group_z;
|
input_info.dispatch_threads_num[2] = thread_group_z;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& program = *input_info.stage.program;
|
const auto& program = input_info.stage.module->info;
|
||||||
const auto& resources = *input_info.stage.resources;
|
const auto& resources = *input_info.stage.resources;
|
||||||
if (resources.specialization_reads.empty() &&
|
if (resources.specialization_reads.empty() &&
|
||||||
(TryConsumeComputeMetaClear(input_info, buffer) ||
|
(TryConsumeComputeMetaClear(input_info, buffer) ||
|
||||||
@@ -504,7 +504,7 @@ void RenderExecutor::DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
PrepareBindings(input_info.stage, bindings);
|
PrepareBindings(input_info.stage, bindings);
|
||||||
PreparedBindings* descriptor_stage = &bindings;
|
PreparedBindings* descriptor_stage = &bindings;
|
||||||
FindBuffers(std::span {&descriptor_stage, 1u});
|
FindBuffers(std::span {&descriptor_stage, 1u});
|
||||||
const auto& program = *input_info.stage.program;
|
const auto& program = input_info.stage.module->info;
|
||||||
if (program.info.uses_dma) {
|
if (program.info.uses_dma) {
|
||||||
m_context.PrepareBda();
|
m_context.PrepareBda();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ std::pair<int32_t, uint32_t> ResolveDrawOffsets(uint32_t index_offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
EXIT_IF(!vs_input_info.stage);
|
EXIT_IF(!vs_input_info.stage);
|
||||||
const auto& program = *vs_input_info.stage.program;
|
const auto& program = vs_input_info.stage.module->info;
|
||||||
const auto& resources = *vs_input_info.stage.resources;
|
const auto& resources = *vs_input_info.stage.resources;
|
||||||
if (index_offset == 0 &&
|
if (index_offset == 0 &&
|
||||||
program.info.vertex_offset_sgpr >= static_cast<int32_t>(program.user_data_base)) {
|
program.info.vertex_offset_sgpr >= static_cast<int32_t>(program.user_data_base)) {
|
||||||
@@ -197,7 +197,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
|
|||||||
const auto& dc = ctx.GetDepthControl();
|
const auto& dc = ctx.GetDepthControl();
|
||||||
const auto& vp = ctx.GetScreenViewport();
|
const auto& vp = ctx.GetScreenViewport();
|
||||||
const auto& vp0 = vp.viewports[0];
|
const auto& vp0 = vp.viewports[0];
|
||||||
const auto& ps_resources = ps_input_info.stage.program->info;
|
const auto& ps_resources = ps_input_info.stage.module->info.info;
|
||||||
const auto sampled_images = std::count_if(
|
const auto sampled_images = std::count_if(
|
||||||
ps_resources.images.begin(), ps_resources.images.end(), [](const auto& image) {
|
ps_resources.images.begin(), ps_resources.images.end(), [](const auto& image) {
|
||||||
return image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
return image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
@@ -320,7 +320,7 @@ static void UpdateGraphicsDynamicState(const CommandBuffer& buffer, DynamicState
|
|||||||
const auto& ctx = buffer.GetRegisters();
|
const auto& ctx = buffer.GetRegisters();
|
||||||
const auto& vp = ctx.GetScreenViewport();
|
const auto& vp = ctx.GetScreenViewport();
|
||||||
const vk::Extent2D framebuffer_extent {rendering.width, rendering.height};
|
const vk::Extent2D framebuffer_extent {rendering.width, rendering.height};
|
||||||
const auto& outputs = vs_input_info.stage.program->info.outputs;
|
const auto& outputs = vs_input_info.stage.module->info.info.outputs;
|
||||||
const bool indexed_viewports =
|
const bool indexed_viewports =
|
||||||
std::any_of(outputs.begin(), outputs.end(), [](const auto& output) {
|
std::any_of(outputs.begin(), outputs.end(), [](const auto& output) {
|
||||||
return output.kind == ShaderRecompiler::IR::StageOutputKind::ViewportIndex;
|
return output.kind == ShaderRecompiler::IR::StageOutputKind::ViewportIndex;
|
||||||
@@ -1054,7 +1054,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto vertex_stages = state.VertexStages();
|
const auto vertex_stages = state.VertexStages();
|
||||||
const bool mesh_active = state.vertex_info[0].stage.program->stage == ShaderType::Mesh;
|
const bool mesh_active = state.vertex_info[0].stage.module->info.stage == ShaderType::Mesh;
|
||||||
uint32_t mesh_groups = 0;
|
uint32_t mesh_groups = 0;
|
||||||
if (mesh_active) {
|
if (mesh_active) {
|
||||||
const auto& mesh = state.vertex_info[0].mesh;
|
const auto& mesh = state.vertex_info[0].mesh;
|
||||||
@@ -1241,7 +1241,7 @@ static std::optional<DrawEmitInfo> ResolveDrawEmit(const HW::UserConfig&
|
|||||||
uint32_t first_instance,
|
uint32_t first_instance,
|
||||||
const DrawIndirectArgs& indirect) {
|
const DrawIndirectArgs& indirect) {
|
||||||
if (indirect.address != 0) {
|
if (indirect.address != 0) {
|
||||||
if (vs.stage.program->stage == ShaderType::Mesh ||
|
if (vs.stage.module->info.stage == ShaderType::Mesh ||
|
||||||
ucfg.GetPrimType() == Prospero::PrimitiveType::kQuadListLegacy) {
|
ucfg.GetPrimType() == Prospero::PrimitiveType::kQuadListLegacy) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -1423,7 +1423,7 @@ bool RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, const D
|
|||||||
|
|
||||||
const bool rect_list = Prospero::IsRectList(ucfg.GetPrimType());
|
const bool rect_list = Prospero::IsRectList(ucfg.GetPrimType());
|
||||||
if (rect_list && state.vertex_info[0].buffers_num == 0 &&
|
if (rect_list && state.vertex_info[0].buffers_num == 0 &&
|
||||||
state.vertex_info[0].stage.program->param_export_mask == 0 &&
|
state.vertex_info[0].stage.module->info.param_export_mask == 0 &&
|
||||||
state.ps_input_info.input_num != 0) {
|
state.ps_input_info.input_num != 0) {
|
||||||
if (graphics_debug_dump_enabled()) {
|
if (graphics_debug_dump_enabled()) {
|
||||||
LOGF("DrawIndexAuto: skipping rect-list draw with no VS param exports and PS inputs: "
|
LOGF("DrawIndexAuto: skipping rect-list draw with no VS param exports and PS inputs: "
|
||||||
|
|||||||
@@ -18,45 +18,9 @@ using ShaderRecompiler::Spirv::Builder;
|
|||||||
|
|
||||||
constexpr uint32_t SpirvVersion15 = 0x00010500u;
|
constexpr uint32_t SpirvVersion15 = 0x00010500u;
|
||||||
|
|
||||||
struct Parameter {
|
|
||||||
uint32_t input_location = 0;
|
|
||||||
uint32_t output_location = 0;
|
|
||||||
bool flat = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Parameter> GetParameters(const ShaderVertexInputInfo& vertex_info,
|
|
||||||
const ShaderPixelInputInfo* pixel_info) {
|
|
||||||
if (pixel_info == nullptr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
EXIT_IF(pixel_info->input_num > ShaderVertexInputInfo::RES_MAX);
|
|
||||||
EXIT_IF(pixel_info->stage.program == nullptr);
|
|
||||||
|
|
||||||
std::vector<uint32_t> active_inputs;
|
|
||||||
for (const auto& input: pixel_info->stage.program->info.inputs) {
|
|
||||||
if (input.kind == ShaderRecompiler::IR::StageInputKind::Parameter) {
|
|
||||||
active_inputs.push_back(input.location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Parameter> parameters;
|
|
||||||
std::array<bool, 32> output_locations {};
|
|
||||||
for (const auto input: active_inputs) {
|
|
||||||
const auto input_location = ShaderPixelParameterMappedLocation(*pixel_info, input);
|
|
||||||
const auto output_location = ShaderPixelParameterLocation(*pixel_info, active_inputs, input);
|
|
||||||
if ((vertex_info.stage.program->param_export_mask & (1u << input_location)) != 0 &&
|
|
||||||
!output_locations[output_location]) {
|
|
||||||
parameters.push_back({input_location, output_location,
|
|
||||||
ShaderPixelParameterIsFlat(*pixel_info, input)});
|
|
||||||
output_locations[output_location] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RectListEmitter {
|
class RectListEmitter {
|
||||||
public:
|
public:
|
||||||
RectListEmitter(const std::vector<Parameter>& parameters_, spv::ExecutionModel model)
|
RectListEmitter(const std::vector<RectListParameter>& parameters_, spv::ExecutionModel model)
|
||||||
: parameters(parameters_) {
|
: parameters(parameters_) {
|
||||||
builder.AddMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
builder.AddMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
||||||
|
|
||||||
@@ -315,42 +279,68 @@ private:
|
|||||||
Result(spv::OpFAdd, vec4_float_type, p1, p2));
|
Result(spv::OpFAdd, vec4_float_type, p1, p2));
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder builder {SpirvVersion15};
|
Builder builder {SpirvVersion15};
|
||||||
const std::vector<Parameter>& parameters;
|
const std::vector<RectListParameter>& parameters;
|
||||||
std::vector<uint32_t> interfaces;
|
std::vector<uint32_t> interfaces;
|
||||||
std::vector<uint32_t> inputs;
|
std::vector<uint32_t> inputs;
|
||||||
std::vector<uint32_t> outputs;
|
std::vector<uint32_t> outputs;
|
||||||
uint32_t main = 0;
|
uint32_t main = 0;
|
||||||
uint32_t void_type = 0;
|
uint32_t void_type = 0;
|
||||||
uint32_t bool_type = 0;
|
uint32_t bool_type = 0;
|
||||||
uint32_t uint_type = 0;
|
uint32_t uint_type = 0;
|
||||||
uint32_t int_type = 0;
|
uint32_t int_type = 0;
|
||||||
uint32_t float_type = 0;
|
uint32_t float_type = 0;
|
||||||
uint32_t vec2_bool_type = 0;
|
uint32_t vec2_bool_type = 0;
|
||||||
uint32_t vec2_float_type = 0;
|
uint32_t vec2_float_type = 0;
|
||||||
uint32_t vec3_float_type = 0;
|
uint32_t vec3_float_type = 0;
|
||||||
uint32_t vec4_float_type = 0;
|
uint32_t vec4_float_type = 0;
|
||||||
uint32_t function_type = 0;
|
uint32_t function_type = 0;
|
||||||
uint32_t per_vertex_type = 0;
|
uint32_t per_vertex_type = 0;
|
||||||
uint32_t ptr_input_float = 0;
|
uint32_t ptr_input_float = 0;
|
||||||
uint32_t ptr_input_vec4_float = 0;
|
uint32_t ptr_input_vec4_float = 0;
|
||||||
uint32_t ptr_output_float = 0;
|
uint32_t ptr_output_float = 0;
|
||||||
uint32_t ptr_output_vec4_float = 0;
|
uint32_t ptr_output_vec4_float = 0;
|
||||||
uint32_t gl_in = 0;
|
uint32_t gl_in = 0;
|
||||||
uint32_t gl_out = 0;
|
uint32_t gl_out = 0;
|
||||||
uint32_t tess_inner = 0;
|
uint32_t tess_inner = 0;
|
||||||
uint32_t tess_outer = 0;
|
uint32_t tess_outer = 0;
|
||||||
uint32_t tess_coord = 0;
|
uint32_t tess_coord = 0;
|
||||||
uint32_t invocation_id = 0;
|
uint32_t invocation_id = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
RectListShaders BuildRectListShaders(const ShaderVertexInputInfo& vertex_info,
|
std::vector<RectListParameter> RectListParameters(
|
||||||
const ShaderPixelInputInfo* pixel_info) {
|
const ShaderPixelInputInfo& pixel_info, const ShaderRecompiler::IR::CompiledShaderInfo& program) {
|
||||||
const auto parameters = GetParameters(vertex_info, pixel_info);
|
EXIT_IF(pixel_info.input_num > ShaderVertexInputInfo::RES_MAX);
|
||||||
RectListEmitter control(parameters, spv::ExecutionModelTessellationControl);
|
std::vector<uint32_t> active_inputs;
|
||||||
RectListEmitter evaluation(parameters, spv::ExecutionModelTessellationEvaluation);
|
for (const auto& input: program.info.inputs) {
|
||||||
|
if (input.kind == ShaderRecompiler::IR::StageInputKind::Parameter) {
|
||||||
|
active_inputs.push_back(input.location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<RectListParameter> parameters;
|
||||||
|
for (const auto input: active_inputs) {
|
||||||
|
parameters.push_back({ShaderPixelParameterMappedLocation(pixel_info, input),
|
||||||
|
ShaderPixelParameterLocation(pixel_info, active_inputs, input),
|
||||||
|
ShaderPixelParameterIsFlat(pixel_info, input)});
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectListShaders BuildRectListShaders(std::span<const RectListParameter> parameters,
|
||||||
|
uint32_t param_export_mask) {
|
||||||
|
std::vector<RectListParameter> exported;
|
||||||
|
std::array<bool, 32> output_locations {};
|
||||||
|
for (const auto& parameter: parameters) {
|
||||||
|
if ((param_export_mask & (1u << parameter.input_location)) != 0 &&
|
||||||
|
!output_locations[parameter.output_location]) {
|
||||||
|
exported.push_back(parameter);
|
||||||
|
output_locations[parameter.output_location] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RectListEmitter control(exported, spv::ExecutionModelTessellationControl);
|
||||||
|
RectListEmitter evaluation(exported, spv::ExecutionModelTessellationEvaluation);
|
||||||
return {control.EmitControl(), evaluation.EmitEvaluation()};
|
return {control.EmitControl(), evaluation.EmitEvaluation()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,20 +2,35 @@
|
|||||||
#define EMULATOR_SRC_GRAPHICS_SHADER_RECTLISTSHADER_H_
|
#define EMULATOR_SRC_GRAPHICS_SHADER_RECTLISTSHADER_H_
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Libs::Graphics {
|
namespace Libs::Graphics {
|
||||||
|
|
||||||
struct ShaderPixelInputInfo;
|
struct ShaderPixelInputInfo;
|
||||||
struct ShaderVertexInputInfo;
|
|
||||||
|
namespace ShaderRecompiler::IR {
|
||||||
|
struct CompiledShaderInfo;
|
||||||
|
} // namespace ShaderRecompiler::IR
|
||||||
|
|
||||||
|
// A pixel parameter the generated stages forward from vertex export input_location.
|
||||||
|
struct RectListParameter {
|
||||||
|
uint32_t input_location = 0;
|
||||||
|
uint32_t output_location = 0;
|
||||||
|
bool flat = false;
|
||||||
|
};
|
||||||
|
|
||||||
struct RectListShaders {
|
struct RectListShaders {
|
||||||
std::vector<uint32_t> control;
|
std::vector<uint32_t> control;
|
||||||
std::vector<uint32_t> evaluation;
|
std::vector<uint32_t> evaluation;
|
||||||
};
|
};
|
||||||
|
|
||||||
RectListShaders BuildRectListShaders(const ShaderVertexInputInfo& vertex_info,
|
// Every parameter a rectangle-list pixel program reads.
|
||||||
const ShaderPixelInputInfo* pixel_info);
|
std::vector<RectListParameter> RectListParameters(
|
||||||
|
const ShaderPixelInputInfo& pixel_info, const ShaderRecompiler::IR::CompiledShaderInfo& program);
|
||||||
|
// Forwards the parameters the vertex stage exports, one per output location.
|
||||||
|
RectListShaders BuildRectListShaders(std::span<const RectListParameter> parameters,
|
||||||
|
uint32_t param_export_mask);
|
||||||
|
|
||||||
} // namespace Libs::Graphics
|
} // namespace Libs::Graphics
|
||||||
|
|
||||||
|
|||||||
@@ -34,19 +34,14 @@ enum class ShaderType {
|
|||||||
TessellationEvaluation
|
TessellationEvaluation
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace ShaderRecompiler::IR {
|
struct ShaderModule;
|
||||||
struct CompiledShaderInfo;
|
|
||||||
} // namespace ShaderRecompiler::IR
|
|
||||||
|
|
||||||
struct ShaderProgram;
|
|
||||||
|
|
||||||
struct ShaderStageRuntime {
|
struct ShaderStageRuntime {
|
||||||
const ShaderRecompiler::IR::CompiledShaderInfo* program = nullptr;
|
const ShaderModule* module = nullptr;
|
||||||
const ShaderRecompiler::IR::ResourceSnapshot* resources = nullptr;
|
const ShaderRecompiler::IR::ResourceSnapshot* resources = nullptr;
|
||||||
const ShaderProgram* handle = nullptr;
|
|
||||||
|
|
||||||
[[nodiscard]] explicit operator bool() const {
|
[[nodiscard]] explicit operator bool() const {
|
||||||
return program != nullptr && resources != nullptr;
|
return module != nullptr && resources != nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <ranges>
|
||||||
#include <semaphore>
|
#include <semaphore>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <span>
|
#include <span>
|
||||||
@@ -447,7 +448,7 @@ struct RenderExecutorTestAccess {
|
|||||||
std::vector<vk::DescriptorSetLayoutBinding> layout_bindings;
|
std::vector<vk::DescriptorSetLayoutBinding> layout_bindings;
|
||||||
bool compute = false;
|
bool compute = false;
|
||||||
for (const auto *prepared : stages) {
|
for (const auto *prepared : stages) {
|
||||||
const auto &program = *prepared->runtime->program;
|
const auto &program = prepared->runtime->module->info;
|
||||||
compute |= program.stage == ShaderType::Compute;
|
compute |= program.stage == ShaderType::Compute;
|
||||||
const auto shader_stage = program.stage == ShaderType::Vertex
|
const auto shader_stage = program.stage == ShaderType::Vertex
|
||||||
? vk::ShaderStageFlagBits::eVertex
|
? vk::ShaderStageFlagBits::eVertex
|
||||||
@@ -498,7 +499,7 @@ struct RenderExecutorTestAccess {
|
|||||||
PreparedBindings &bindings) {
|
PreparedBindings &bindings) {
|
||||||
std::array<PreparedBindings *, 1> stages{&bindings};
|
std::array<PreparedBindings *, 1> stages{&bindings};
|
||||||
auto pipeline = CreateDescriptorPipeline(executor, stages);
|
auto pipeline = CreateDescriptorPipeline(executor, stages);
|
||||||
const auto bind_point = bindings.runtime->program->stage == ShaderType::Compute
|
const auto bind_point = bindings.runtime->module->info.stage == ShaderType::Compute
|
||||||
? vk::PipelineBindPoint::eCompute
|
? vk::PipelineBindPoint::eCompute
|
||||||
: vk::PipelineBindPoint::eGraphics;
|
: vk::PipelineBindPoint::eGraphics;
|
||||||
executor.CommitBindings(buffer, bind_point, pipeline, stages);
|
executor.CommitBindings(buffer, bind_point, pipeline, stages);
|
||||||
@@ -583,6 +584,33 @@ struct RenderExecutorTestAccess {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PipelineCacheTestAccess {
|
||||||
|
// Replaces each graphics pipeline whose stage ids name compiled modules with one created
|
||||||
|
// from only its key and those modules. The GPU must be idle. Returns how many it replaced.
|
||||||
|
static uint32_t RecreateGraphicsPipelines(PipelineCache &cache) {
|
||||||
|
std::unordered_map<uint64_t, const ShaderModule *> modules{{0, nullptr}}; // Id 0: absent.
|
||||||
|
for (const auto &program : cache.m_program_cache | std::views::values)
|
||||||
|
for (const auto &module : program.modules) modules.emplace(module.id, &module);
|
||||||
|
auto &device = cache.m_graphics.device;
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (auto &[key, pipeline] : cache.m_graphics_pipelines) {
|
||||||
|
// Test-owned modules are not in the cache.
|
||||||
|
if (!std::ranges::all_of(key.stage_ids, [&](uint64_t id) { return modules.contains(id); }))
|
||||||
|
continue;
|
||||||
|
std::array<const ShaderModule *, 4> stages{};
|
||||||
|
for (size_t i = 0; i < stages.size(); i++) stages[i] = modules.at(key.stage_ids[i]);
|
||||||
|
PipelineCache::Pipeline recreated;
|
||||||
|
CreatePipelineInternal(cache.m_graphics, recreated, key, stages, nullptr);
|
||||||
|
device.destroyPipeline(pipeline.pipeline, nullptr);
|
||||||
|
device.destroyPipelineLayout(pipeline.pipeline_layout, nullptr);
|
||||||
|
device.destroyDescriptorSetLayout(pipeline.descriptor_set_layout, nullptr);
|
||||||
|
pipeline = recreated;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using u32 = uint32_t;
|
using u32 = uint32_t;
|
||||||
@@ -1509,18 +1537,12 @@ void CheckRectListShaders() {
|
|||||||
program.info.inputs.push_back(
|
program.info.inputs.push_back(
|
||||||
{ShaderRecompiler::IR::StageInputKind::Parameter, 1, 4, "in_param_1"});
|
{ShaderRecompiler::IR::StageInputKind::Parameter, 1, 4, "in_param_1"});
|
||||||
|
|
||||||
ShaderVertexInputInfo vertex{};
|
constexpr uint32_t param_export_mask = 1u;
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo vertex_program{.param_export_mask = 1u};
|
|
||||||
ShaderRecompiler::IR::ResourceSnapshot empty_snapshot;
|
|
||||||
vertex.stage.program = &vertex_program;
|
|
||||||
vertex.stage.resources = &empty_snapshot;
|
|
||||||
ShaderPixelInputInfo pixel{};
|
ShaderPixelInputInfo pixel{};
|
||||||
pixel.parameter_mode = ShaderPixelParameterMode::Rectangle;
|
pixel.parameter_mode = ShaderPixelParameterMode::Rectangle;
|
||||||
pixel.input_num = 2;
|
pixel.input_num = 2;
|
||||||
pixel.interpolator_settings[0] = 0x400u;
|
pixel.interpolator_settings[0] = 0x400u;
|
||||||
pixel.interpolator_settings[1] = 0;
|
pixel.interpolator_settings[1] = 0;
|
||||||
pixel.stage.program = &program;
|
|
||||||
pixel.stage.resources = &empty_snapshot;
|
|
||||||
std::vector<uint32_t> perspective_specialization;
|
std::vector<uint32_t> perspective_specialization;
|
||||||
BuildStageStaticKey(pixel, perspective_specialization);
|
BuildStageStaticKey(pixel, perspective_specialization);
|
||||||
pixel.ps_no_perspective = true;
|
pixel.ps_no_perspective = true;
|
||||||
@@ -1539,7 +1561,8 @@ void CheckRectListShaders() {
|
|||||||
"duplicate pixel mappings must receive distinct effective output "
|
"duplicate pixel mappings must receive distinct effective output "
|
||||||
"locations");
|
"locations");
|
||||||
|
|
||||||
const auto shaders = BuildRectListShaders(vertex, &pixel);
|
const auto shaders =
|
||||||
|
BuildRectListShaders(RectListParameters(pixel, program), param_export_mask);
|
||||||
Require(name, "SPIR-V version",
|
Require(name, "SPIR-V version",
|
||||||
shaders.control.size() > 1 && shaders.control[1] == 0x00010500u &&
|
shaders.control.size() > 1 && shaders.control[1] == 0x00010500u &&
|
||||||
shaders.evaluation.size() > 1 &&
|
shaders.evaluation.size() > 1 &&
|
||||||
@@ -1588,7 +1611,8 @@ void CheckRectListShaders() {
|
|||||||
for (const auto flat : {0u, 0x400u}) {
|
for (const auto flat : {0u, 0x400u}) {
|
||||||
pixel.interpolator_settings[0] = flat;
|
pixel.interpolator_settings[0] = flat;
|
||||||
pixel.interpolator_settings[1] = flat;
|
pixel.interpolator_settings[1] = flat;
|
||||||
const auto shared = BuildRectListShaders(vertex, &pixel);
|
const auto shared =
|
||||||
|
BuildRectListShaders(RectListParameters(pixel, program), param_export_mask);
|
||||||
ValidateSpirv(name, shared.control);
|
ValidateSpirv(name, shared.control);
|
||||||
ValidateSpirv(name, shared.evaluation);
|
ValidateSpirv(name, shared.evaluation);
|
||||||
Require(name, "same-mode alias disassembly",
|
Require(name, "same-mode alias disassembly",
|
||||||
@@ -1604,7 +1628,7 @@ void CheckRectListShaders() {
|
|||||||
"the shared location in each rectangle-list stage");
|
"the shared location in each rectangle-list stage");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto position_only = BuildRectListShaders(vertex, nullptr);
|
const auto position_only = BuildRectListShaders({}, param_export_mask);
|
||||||
ValidateSpirv(name, position_only.control);
|
ValidateSpirv(name, position_only.control);
|
||||||
ValidateSpirv(name, position_only.evaluation);
|
ValidateSpirv(name, position_only.evaluation);
|
||||||
}
|
}
|
||||||
@@ -2210,22 +2234,24 @@ public:
|
|||||||
HW::Shader shaders{};
|
HW::Shader shaders{};
|
||||||
scheduler.Begin(registers, user_config, shaders);
|
scheduler.Begin(registers, user_config, shaders);
|
||||||
|
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo vertex_program{};
|
ShaderModule vertex_module;
|
||||||
|
auto &vertex_program = vertex_module.info;
|
||||||
vertex_program.stage = ShaderType::Vertex;
|
vertex_program.stage = ShaderType::Vertex;
|
||||||
vertex_program.bindings.push_data_start_dword = 2;
|
vertex_program.bindings.push_data_start_dword = 2;
|
||||||
vertex_program.info.user_data_registers = {0, 1};
|
vertex_program.info.user_data_registers = {0, 1};
|
||||||
vertex_program.bindings.memory_offset_dword = 2;
|
vertex_program.bindings.memory_offset_dword = 2;
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo pixel_program{};
|
ShaderModule pixel_module;
|
||||||
|
auto &pixel_program = pixel_module.info;
|
||||||
pixel_program.stage = ShaderType::Pixel;
|
pixel_program.stage = ShaderType::Pixel;
|
||||||
pixel_program.bindings.push_data_start_dword = 0;
|
pixel_program.bindings.push_data_start_dword = 0;
|
||||||
pixel_program.info.user_data_registers = {0, 1};
|
pixel_program.info.user_data_registers = {0, 1};
|
||||||
pixel_program.bindings.memory_offset_dword = 2;
|
pixel_program.bindings.memory_offset_dword = 2;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot vertex_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot vertex_snapshot;
|
||||||
vertex_snapshot.user_data = {0x11111111u, 0x22222222u};
|
vertex_snapshot.user_data = {0x11111111u, 0x22222222u};
|
||||||
ShaderStageRuntime vertex_runtime{&vertex_program, &vertex_snapshot};
|
ShaderStageRuntime vertex_runtime{&vertex_module, &vertex_snapshot};
|
||||||
ShaderRecompiler::IR::ResourceSnapshot pixel_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot pixel_snapshot;
|
||||||
pixel_snapshot.user_data = {0x33333333u, 0x44444444u};
|
pixel_snapshot.user_data = {0x33333333u, 0x44444444u};
|
||||||
ShaderStageRuntime pixel_runtime{&pixel_program, &pixel_snapshot};
|
ShaderStageRuntime pixel_runtime{&pixel_module, &pixel_snapshot};
|
||||||
PreparedBindings vertex;
|
PreparedBindings vertex;
|
||||||
PreparedBindings pixel;
|
PreparedBindings pixel;
|
||||||
auto &executor = context.GetRenderExecutor();
|
auto &executor = context.GetRenderExecutor();
|
||||||
@@ -5520,8 +5546,9 @@ public:
|
|||||||
"test HTile entries were not registered in their initial state");
|
"test HTile entries were not registered in their initial state");
|
||||||
|
|
||||||
const auto MakeInput = [](uint64_t address, bool read, bool written,
|
const auto MakeInput = [](uint64_t address, bool read, bool written,
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo &program,
|
ShaderModule &module,
|
||||||
ShaderRecompiler::IR::ResourceSnapshot &snapshot) {
|
ShaderRecompiler::IR::ResourceSnapshot &snapshot) {
|
||||||
|
auto &program = module.info;
|
||||||
program.stage = ShaderType::Compute;
|
program.stage = ShaderType::Compute;
|
||||||
ShaderRecompiler::IR::BufferResource resource{};
|
ShaderRecompiler::IR::BufferResource resource{};
|
||||||
resource.read = read;
|
resource.read = read;
|
||||||
@@ -5541,14 +5568,14 @@ public:
|
|||||||
value.dword_count = 4;
|
value.dword_count = 4;
|
||||||
std::copy_n(descriptor.fields, value.dword_count, value.dwords.begin());
|
std::copy_n(descriptor.fields, value.dword_count, value.dwords.begin());
|
||||||
ShaderComputeInputInfo input{};
|
ShaderComputeInputInfo input{};
|
||||||
input.stage.program = &program;
|
input.stage.module = &module;
|
||||||
snapshot.buffers.push_back(value);
|
snapshot.buffers.push_back(value);
|
||||||
input.stage.resources = &snapshot;
|
input.stage.resources = &snapshot;
|
||||||
return input;
|
return input;
|
||||||
};
|
};
|
||||||
auto &executor = context.GetRenderExecutor();
|
auto &executor = context.GetRenderExecutor();
|
||||||
auto &command = scheduler.Current();
|
auto &command = scheduler.Current();
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo read_only_program{};
|
ShaderModule read_only_program;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot read_only_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot read_only_snapshot;
|
||||||
const auto read_only_input =
|
const auto read_only_input =
|
||||||
MakeInput(read_only_meta, true, false, read_only_program,
|
MakeInput(read_only_meta, true, false, read_only_program,
|
||||||
@@ -5561,7 +5588,7 @@ public:
|
|||||||
!texture_cache.IsMetaCleared(read_only_meta, 0),
|
!texture_cache.IsMetaCleared(read_only_meta, 0),
|
||||||
"a metadata read-only dispatch changed logical clear state");
|
"a metadata read-only dispatch changed logical clear state");
|
||||||
|
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo read_write_program{};
|
ShaderModule read_write_program;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot read_write_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot read_write_snapshot;
|
||||||
const auto read_write_input =
|
const auto read_write_input =
|
||||||
MakeInput(read_write_meta, true, true, read_write_program,
|
MakeInput(read_write_meta, true, true, read_write_program,
|
||||||
@@ -5574,7 +5601,7 @@ public:
|
|||||||
!texture_cache.IsMetaCleared(read_write_meta, 0),
|
!texture_cache.IsMetaCleared(read_write_meta, 0),
|
||||||
"a metadata read/modify/write dispatch was replaced by a clear");
|
"a metadata read/modify/write dispatch was replaced by a clear");
|
||||||
|
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo write_only_program{};
|
ShaderModule write_only_program;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot write_only_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot write_only_snapshot;
|
||||||
const auto write_only_input =
|
const auto write_only_input =
|
||||||
MakeInput(write_only_meta, false, true, write_only_program,
|
MakeInput(write_only_meta, false, true, write_only_program,
|
||||||
@@ -11099,9 +11126,9 @@ public:
|
|||||||
ShaderComputeInputInfo input{};
|
ShaderComputeInputInfo input{};
|
||||||
const auto program = context.GetPipelineCache().GetComputeProgram(
|
const auto program = context.GetPipelineCache().GetComputeProgram(
|
||||||
shaders.GetCs(), input);
|
shaders.GetCs(), input);
|
||||||
if (original_id == 0) original_id = program.id;
|
if (original_id == 0) original_id = program->id;
|
||||||
Require(name, "exact function identity",
|
Require(name, "exact function identity",
|
||||||
(program.id == original_id) == (test.value == 41),
|
(program->id == original_id) == (test.value == 41),
|
||||||
"helper bytes were stale or identical relocated/restored code recompiled");
|
"helper bytes were stale or identical relocated/restored code recompiled");
|
||||||
Require(name, "current code dependency",
|
Require(name, "current code dependency",
|
||||||
std::ranges::find(input.stage.resources->specialization_reads,
|
std::ranges::find(input.stage.resources->specialization_reads,
|
||||||
@@ -11191,9 +11218,9 @@ public:
|
|||||||
ShaderComputeInputInfo input{};
|
ShaderComputeInputInfo input{};
|
||||||
const auto program = context.GetPipelineCache().GetComputeProgram(
|
const auto program = context.GetPipelineCache().GetComputeProgram(
|
||||||
shaders.GetCs(), input);
|
shaders.GetCs(), input);
|
||||||
if (phase == 1) original_vector_id = program.id;
|
if (phase == 1) original_vector_id = program->id;
|
||||||
if (phase >= 2)
|
if (phase >= 2)
|
||||||
Require(name, "ordered helper identity", (program.id == original_vector_id) == (phase == 3),
|
Require(name, "ordered helper identity", (program->id == original_vector_id) == (phase == 3),
|
||||||
"swapped helper targets reused stale code or restored targets recompiled");
|
"swapped helper targets reused stale code or restored targets recompiled");
|
||||||
const auto& reads = input.stage.resources->specialization_reads;
|
const auto& reads = input.stage.resources->specialization_reads;
|
||||||
for (u32 i = 0; i < (call_count == 1 ? 1u : 2u); ++i)
|
for (u32 i = 0; i < (call_count == 1 ? 1u : 2u); ++i)
|
||||||
@@ -11689,7 +11716,7 @@ public:
|
|||||||
Prospero::BufferFormat::k32UInt, Prospero::ImageType::kColor2D,
|
Prospero::BufferFormat::k32UInt, Prospero::ImageType::kColor2D,
|
||||||
{8, 1, 1}, 1, 4, 1);
|
{8, 1, 1}, 1, 4, 1);
|
||||||
const auto image = textures.FindImage(image_desc);
|
const auto image = textures.FindImage(image_desc);
|
||||||
ShaderProgram previous_program;
|
uint64_t previous_id = 0;
|
||||||
for (const auto count : {3u, 7u}) {
|
for (const auto count : {3u, 7u}) {
|
||||||
cache.FillBuffer(count_output, 16u * sizeof(u32), sentinel, false);
|
cache.FillBuffer(count_output, 16u * sizeof(u32), sentinel, false);
|
||||||
shaders.SetCsShader({.data_addr = reinterpret_cast<uint64_t>(writer.data()),
|
shaders.SetCsShader({.data_addr = reinterpret_cast<uint64_t>(writer.data()),
|
||||||
@@ -11734,11 +11761,11 @@ public:
|
|||||||
ShaderComputeInputInfo input{};
|
ShaderComputeInputInfo input{};
|
||||||
const auto program = context.GetPipelineCache().GetComputeProgram(
|
const auto program = context.GetPipelineCache().GetComputeProgram(
|
||||||
shaders.GetCs(), input);
|
shaders.GetCs(), input);
|
||||||
if (previous_program.id != 0) {
|
if (previous_id != 0) {
|
||||||
Require(name, "count permutation reuse", program.id == previous_program.id,
|
Require(name, "count permutation reuse", program->id == previous_id,
|
||||||
"a changing GPU count compiled a new shader permutation");
|
"a changing GPU count compiled a new shader permutation");
|
||||||
}
|
}
|
||||||
previous_program = program;
|
previous_id = program->id;
|
||||||
Require(name, "clean count repeat",
|
Require(name, "clean count repeat",
|
||||||
CpOpDispatchIndirect(processor, 0xc0021600u, packet.data(), 0, 0) == 3 &&
|
CpOpDispatchIndirect(processor, 0xc0021600u, packet.data(), 0, 0) == 3 &&
|
||||||
scheduler.CurrentTick() == clean_tick,
|
scheduler.CurrentTick() == clean_tick,
|
||||||
@@ -11818,29 +11845,29 @@ public:
|
|||||||
shaders.GetCs(), input);
|
shaders.GetCs(), input);
|
||||||
Require(name, "workgroup table refresh and coalescing",
|
Require(name, "workgroup table refresh and coalescing",
|
||||||
input.workgroup_counts[2] == test.groups &&
|
input.workgroup_counts[2] == test.groups &&
|
||||||
input.stage.program->info.images.size() == 1 &&
|
input.stage.module->info.info.images.size() == 1 &&
|
||||||
input.stage.program->info.images[0].indirect_resources.empty() &&
|
input.stage.module->info.info.images[0].indirect_resources.empty() &&
|
||||||
input.stage.resources->images.size() == 1 &&
|
input.stage.resources->images.size() == 1 &&
|
||||||
std::equal(std::begin(sharp.fields), std::end(sharp.fields),
|
std::equal(std::begin(sharp.fields), std::end(sharp.fields),
|
||||||
input.stage.resources->images[0].dwords.begin()) &&
|
input.stage.resources->images[0].dwords.begin()) &&
|
||||||
!input.stage.program->info.buffers.empty(),
|
!input.stage.module->info.info.buffers.empty(),
|
||||||
"workgroup bounds, refreshed sharp, or live descriptor dimension reads were lost");
|
"workgroup bounds, refreshed sharp, or live descriptor dimension reads were lost");
|
||||||
Require(name, "workgroup table program reuse",
|
Require(name, "workgroup table program reuse",
|
||||||
table_program_id == 0 || program.id == table_program_id,
|
table_program_id == 0 || program->id == table_program_id,
|
||||||
"changing the workgroup count or identical sharp values recompiled the shader");
|
"changing the workgroup count or identical sharp values recompiled the shader");
|
||||||
table_program_id = program.id;
|
table_program_id = program->id;
|
||||||
const auto *snapshot = input.stage.resources;
|
const auto *snapshot = input.stage.resources;
|
||||||
const auto *image_storage = snapshot->images.data();
|
const auto *image_storage = snapshot->images.data();
|
||||||
const auto flattened_capacity = snapshot->flattened_srt.capacity();
|
const auto flattened_capacity = snapshot->flattened_srt.capacity();
|
||||||
const auto repeated = context.GetPipelineCache().GetComputeProgram(
|
const auto repeated = context.GetPipelineCache().GetComputeProgram(
|
||||||
shaders.GetCs(), input);
|
shaders.GetCs(), input);
|
||||||
Require(name, "workgroup table cache-hit storage reuse",
|
Require(name, "workgroup table cache-hit storage reuse",
|
||||||
repeated.id == program.id && input.stage.resources == snapshot &&
|
repeated->id == program->id && input.stage.resources == snapshot &&
|
||||||
snapshot->images.data() == image_storage &&
|
snapshot->images.data() == image_storage &&
|
||||||
snapshot->flattened_srt.capacity() == flattened_capacity,
|
snapshot->flattened_srt.capacity() == flattened_capacity,
|
||||||
"a repeated descriptor table hit replaced its snapshot or storage");
|
"a repeated descriptor table hit replaced its snapshot or storage");
|
||||||
auto binding = RenderExecutorTestAccess::ResolveTexture(
|
auto binding = RenderExecutorTestAccess::ResolveTexture(
|
||||||
context.GetRenderExecutor(), input.stage.program->info.images[0],
|
context.GetRenderExecutor(), input.stage.module->info.info.images[0],
|
||||||
input.stage.resources->images[0]);
|
input.stage.resources->images[0]);
|
||||||
const auto target = textures.FindImage(binding.desc);
|
const auto target = textures.FindImage(binding.desc);
|
||||||
TextureCacheTestAccess::ClearImage(textures, scheduler.Current(), target,
|
TextureCacheTestAccess::ClearImage(textures, scheduler.Current(), target,
|
||||||
@@ -12073,11 +12100,11 @@ public:
|
|||||||
input.workgroup_counts[1] = input.workgroup_counts[2] = 1u;
|
input.workgroup_counts[1] = input.workgroup_counts[2] = 1u;
|
||||||
(void)context.GetPipelineCache().GetComputeProgram(
|
(void)context.GetPipelineCache().GetComputeProgram(
|
||||||
shaders.GetCs(), input);
|
shaders.GetCs(), input);
|
||||||
const auto &info = input.stage.program->info;
|
const auto &info = input.stage.module->info.info;
|
||||||
const auto root = std::ranges::find_if(info.buffers, [](const auto &buffer) {
|
const auto root = std::ranges::find_if(info.buffers, [](const auto &buffer) {
|
||||||
return buffer.indirect_resources.size() == material_rows;
|
return buffer.indirect_resources.size() == material_rows;
|
||||||
});
|
});
|
||||||
const auto &bindings = input.stage.program->bindings;
|
const auto &bindings = input.stage.module->info.bindings;
|
||||||
const auto native_count = bindings.descriptor_counts[
|
const auto native_count = bindings.descriptor_counts[
|
||||||
static_cast<size_t>(ShaderRecompiler::IR::DescriptorBindingKind::Buffers)];
|
static_cast<size_t>(ShaderRecompiler::IR::DescriptorBindingKind::Buffers)];
|
||||||
Require(name, "native material descriptor array",
|
Require(name, "native material descriptor array",
|
||||||
@@ -14331,14 +14358,15 @@ public:
|
|||||||
};
|
};
|
||||||
const auto make_buffer_program =
|
const auto make_buffer_program =
|
||||||
[](ShaderType stage, ShaderRecompiler::IR::BufferResource resource) {
|
[](ShaderType stage, ShaderRecompiler::IR::BufferResource resource) {
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo program{};
|
ShaderModule module;
|
||||||
|
auto &program = module.info;
|
||||||
program.stage = stage;
|
program.stage = stage;
|
||||||
resource.descriptor_index = 0;
|
resource.descriptor_index = 0;
|
||||||
program.info.buffers.push_back(resource);
|
program.info.buffers.push_back(resource);
|
||||||
program.bindings.descriptor_counts[0] = 1;
|
program.bindings.descriptor_counts[0] = 1;
|
||||||
program.bindings.descriptor_mask = 1;
|
program.bindings.descriptor_mask = 1;
|
||||||
program.bindings.push_data_start_dword = 0;
|
program.bindings.push_data_start_dword = 0;
|
||||||
return program;
|
return module;
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -14441,7 +14469,7 @@ public:
|
|||||||
bindings.buffers[0].buffer == owner.Handle() &&
|
bindings.buffers[0].buffer == owner.Handle() &&
|
||||||
bindings.buffers[0].offset + 2 == owner.Offset(buffer_address) &&
|
bindings.buffers[0].offset + 2 == owner.Offset(buffer_address) &&
|
||||||
bindings.buffers[0].range == 14 &&
|
bindings.buffers[0].range == 14 &&
|
||||||
bindings.shader_data[buffer_program.bindings.memory_offset_dword] == 2,
|
bindings.shader_data[buffer_program.info.bindings.memory_offset_dword] == 2,
|
||||||
"native binding lost the byte adjustment or rounded the final halfword range");
|
"native binding lost the byte adjustment or rounded the final halfword range");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14449,7 +14477,8 @@ public:
|
|||||||
constexpr uint64_t address = base + allocation_size - 0x4000 + 12;
|
constexpr uint64_t address = base + allocation_size - 0x4000 + 12;
|
||||||
constexpr uint64_t mapped_tail = base + allocation_size - address;
|
constexpr uint64_t mapped_tail = base + allocation_size - address;
|
||||||
auto writer = make_buffer_program(ShaderType::Vertex, {.written = true});
|
auto writer = make_buffer_program(ShaderType::Vertex, {.written = true});
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo reader{};
|
ShaderModule reader_module;
|
||||||
|
auto &reader = reader_module.info;
|
||||||
reader.stage = ShaderType::Pixel;
|
reader.stage = ShaderType::Pixel;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot writer_snapshot, reader_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot writer_snapshot, reader_snapshot;
|
||||||
ShaderBufferResource descriptor{};
|
ShaderBufferResource descriptor{};
|
||||||
@@ -14459,7 +14488,7 @@ public:
|
|||||||
std::copy_n(descriptor.fields, 4, value.dwords.begin());
|
std::copy_n(descriptor.fields, 4, value.dwords.begin());
|
||||||
value.dword_count = 4;
|
value.dword_count = 4;
|
||||||
ShaderStageRuntime writer_runtime{&writer, &writer_snapshot};
|
ShaderStageRuntime writer_runtime{&writer, &writer_snapshot};
|
||||||
ShaderStageRuntime reader_runtime{&reader, &reader_snapshot};
|
ShaderStageRuntime reader_runtime{&reader_module, &reader_snapshot};
|
||||||
PreparedBindings writer_bindings, reader_bindings;
|
PreparedBindings writer_bindings, reader_bindings;
|
||||||
const auto check_range = [&](uint64_t expected, const char *description) {
|
const auto check_range = [&](uint64_t expected, const char *description) {
|
||||||
executor.PrepareBindings(writer_runtime, writer_bindings);
|
executor.PrepareBindings(writer_runtime, writer_bindings);
|
||||||
@@ -14490,8 +14519,8 @@ public:
|
|||||||
value.dwords[2] = 0x300;
|
value.dwords[2] = 0x300;
|
||||||
check_range(0x300, "finite write preserves its declared range");
|
check_range(0x300, "finite write preserves its declared range");
|
||||||
value.dwords[2] = UINT32_MAX;
|
value.dwords[2] = UINT32_MAX;
|
||||||
writer.info.buffers[0].written = false;
|
writer.info.info.buffers[0].written = false;
|
||||||
writer.info.buffers[0].read = true;
|
writer.info.info.buffers[0].read = true;
|
||||||
check_range(mapped_tail, "read-only sentinel preserves mapped tail");
|
check_range(mapped_tail, "read-only sentinel preserves mapped tail");
|
||||||
auto &graphics = context.GetGraphics();
|
auto &graphics = context.GetGraphics();
|
||||||
auto &storage_limit = graphics.physical_device_properties.limits.maxStorageBufferRange;
|
auto &storage_limit = graphics.physical_device_properties.limits.maxStorageBufferRange;
|
||||||
@@ -14538,7 +14567,8 @@ public:
|
|||||||
texture_cache.MarkGpuWritten(depth_id);
|
texture_cache.MarkGpuWritten(depth_id);
|
||||||
expected = 0xffff;
|
expected = 0xffff;
|
||||||
}
|
}
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo program{};
|
ShaderModule module;
|
||||||
|
auto &program = module.info;
|
||||||
program.stage = ShaderType::Compute;
|
program.stage = ShaderType::Compute;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot snapshot;
|
||||||
// PPSA24156 binds one-texel R8/R16 allocations as 3D, then 2D.
|
// PPSA24156 binds one-texel R8/R16 allocations as 3D, then 2D.
|
||||||
@@ -14560,7 +14590,7 @@ public:
|
|||||||
DstSel(4, 4, 4, 1) | (static_cast<u32>(type) << 28u),
|
DstSel(4, 4, 4, 1) | (static_cast<u32>(type) << 28u),
|
||||||
0, 0x00700000u, 0, 0};
|
0, 0x00700000u, 0, 0};
|
||||||
}
|
}
|
||||||
ShaderStageRuntime runtime{&program, &snapshot};
|
ShaderStageRuntime runtime{&module, &snapshot};
|
||||||
PreparedBindings bindings;
|
PreparedBindings bindings;
|
||||||
executor.PrepareBindings(runtime, bindings);
|
executor.PrepareBindings(runtime, bindings);
|
||||||
Require(name, "overlapping dimension discovery",
|
Require(name, "overlapping dimension discovery",
|
||||||
@@ -14683,11 +14713,12 @@ public:
|
|||||||
null_program.info.images.back().mip_mode = ShaderRecompiler::IR::ImageMipMode::Dynamic;
|
null_program.info.images.back().mip_mode = ShaderRecompiler::IR::ImageMipMode::Dynamic;
|
||||||
null_program.info.images.back().mip_count = 3;
|
null_program.info.images.back().mip_count = 3;
|
||||||
set_image_bindings(null_program);
|
set_image_bindings(null_program);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo null_info{};
|
ShaderModule null_module;
|
||||||
|
auto &null_info = null_module.info;
|
||||||
null_info.stage = null_program.stage;
|
null_info.stage = null_program.stage;
|
||||||
null_info.info = std::move(null_program.info);
|
null_info.info = std::move(null_program.info);
|
||||||
null_info.bindings = std::move(null_program.bindings);
|
null_info.bindings = std::move(null_program.bindings);
|
||||||
ShaderStageRuntime null_runtime{&null_info, &null_snapshot};
|
ShaderStageRuntime null_runtime{&null_module, &null_snapshot};
|
||||||
PreparedBindings null_bindings;
|
PreparedBindings null_bindings;
|
||||||
executor.PrepareBindings(null_runtime, null_bindings);
|
executor.PrepareBindings(null_runtime, null_bindings);
|
||||||
executor.RebindImages(null_bindings);
|
executor.RebindImages(null_bindings);
|
||||||
@@ -14923,7 +14954,8 @@ public:
|
|||||||
tail4 == std::vector<u32>{tail_backing_value},
|
tail4 == std::vector<u32>{tail_backing_value},
|
||||||
"expanding a shared mip tail lost GPU writes or the added mip's backing bytes");
|
"expanding a shared mip tail lost GPU writes or the added mip's backing bytes");
|
||||||
PreparedBindings mipped_prepared{};
|
PreparedBindings mipped_prepared{};
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo mipped_program{};
|
ShaderModule mipped_module;
|
||||||
|
auto &mipped_program = mipped_module.info;
|
||||||
mipped_program.info.images.push_back(storage_resource);
|
mipped_program.info.images.push_back(storage_resource);
|
||||||
mipped_program.info.images.push_back(mipped_storage_resource);
|
mipped_program.info.images.push_back(mipped_storage_resource);
|
||||||
mipped_program.info.images.push_back(storage_resource);
|
mipped_program.info.images.push_back(storage_resource);
|
||||||
@@ -14933,7 +14965,7 @@ public:
|
|||||||
mipped_storage_descriptor,
|
mipped_storage_descriptor,
|
||||||
overwide_mipped_storage_descriptor,
|
overwide_mipped_storage_descriptor,
|
||||||
overwide_mipped_storage_descriptor};
|
overwide_mipped_storage_descriptor};
|
||||||
ShaderStageRuntime mipped_runtime{&mipped_program, &mipped_snapshot};
|
ShaderStageRuntime mipped_runtime{&mipped_module, &mipped_snapshot};
|
||||||
mipped_prepared.runtime = &mipped_runtime;
|
mipped_prepared.runtime = &mipped_runtime;
|
||||||
mipped_prepared.images.push_back(
|
mipped_prepared.images.push_back(
|
||||||
std::move(plain_mipped_storage_binding));
|
std::move(plain_mipped_storage_binding));
|
||||||
@@ -15114,7 +15146,8 @@ public:
|
|||||||
views[2] != views[3] && views[1] == views.back(),
|
views[2] != views[3] && views[1] == views.back(),
|
||||||
"different texture clamps aliased or identical clamped views "
|
"different texture clamps aliased or identical clamped views "
|
||||||
"were not reused");
|
"were not reused");
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo gather_info{};
|
ShaderModule gather_module;
|
||||||
|
auto &gather_info = gather_module.info;
|
||||||
gather_info.stage = ShaderType::Compute;
|
gather_info.stage = ShaderType::Compute;
|
||||||
gather_info.info = lod_program.program.info;
|
gather_info.info = lod_program.program.info;
|
||||||
gather_info.info.images[0].mip_mode =
|
gather_info.info.images[0].mip_mode =
|
||||||
@@ -15122,7 +15155,7 @@ public:
|
|||||||
gather_info.info.images[0].mip_count = 4;
|
gather_info.info.images[0].mip_count = 4;
|
||||||
auto gather_snapshot = lod_program.resources;
|
auto gather_snapshot = lod_program.resources;
|
||||||
gather_snapshot.images[0] = lod_descriptor;
|
gather_snapshot.images[0] = lod_descriptor;
|
||||||
ShaderStageRuntime gather_runtime{&gather_info, &gather_snapshot};
|
ShaderStageRuntime gather_runtime{&gather_module, &gather_snapshot};
|
||||||
PreparedBindings gather_bindings;
|
PreparedBindings gather_bindings;
|
||||||
executor.PrepareBindings(gather_runtime, gather_bindings);
|
executor.PrepareBindings(gather_runtime, gather_bindings);
|
||||||
executor.RebindImages(gather_bindings);
|
executor.RebindImages(gather_bindings);
|
||||||
@@ -15277,11 +15310,12 @@ public:
|
|||||||
|
|
||||||
ShaderRecompiler::IR::ResourceSnapshot storage_snapshot{};
|
ShaderRecompiler::IR::ResourceSnapshot storage_snapshot{};
|
||||||
storage_snapshot.images.push_back(storage_descriptor);
|
storage_snapshot.images.push_back(storage_descriptor);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo storage_info{};
|
ShaderModule storage_module;
|
||||||
|
auto &storage_info = storage_module.info;
|
||||||
storage_info.stage = storage_program.stage;
|
storage_info.stage = storage_program.stage;
|
||||||
storage_info.info = std::move(storage_program.info);
|
storage_info.info = std::move(storage_program.info);
|
||||||
storage_info.bindings = std::move(storage_program.bindings);
|
storage_info.bindings = std::move(storage_program.bindings);
|
||||||
ShaderStageRuntime storage_runtime{&storage_info, &storage_snapshot};
|
ShaderStageRuntime storage_runtime{&storage_module, &storage_snapshot};
|
||||||
PreparedBindings storage_discovery;
|
PreparedBindings storage_discovery;
|
||||||
executor.PrepareBindings(storage_runtime, storage_discovery);
|
executor.PrepareBindings(storage_runtime, storage_discovery);
|
||||||
const auto storage_id = storage_discovery.images[0].image_id;
|
const auto storage_id = storage_discovery.images[0].image_id;
|
||||||
@@ -15308,11 +15342,12 @@ public:
|
|||||||
set_image_bindings(sampled_program);
|
set_image_bindings(sampled_program);
|
||||||
ShaderRecompiler::IR::ResourceSnapshot sampled_snapshot{};
|
ShaderRecompiler::IR::ResourceSnapshot sampled_snapshot{};
|
||||||
sampled_snapshot.images.push_back(storage_descriptor);
|
sampled_snapshot.images.push_back(storage_descriptor);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo sampled_info{};
|
ShaderModule sampled_module;
|
||||||
|
auto &sampled_info = sampled_module.info;
|
||||||
sampled_info.stage = sampled_program.stage;
|
sampled_info.stage = sampled_program.stage;
|
||||||
sampled_info.info = std::move(sampled_program.info);
|
sampled_info.info = std::move(sampled_program.info);
|
||||||
sampled_info.bindings = std::move(sampled_program.bindings);
|
sampled_info.bindings = std::move(sampled_program.bindings);
|
||||||
ShaderStageRuntime sampled_runtime{&sampled_info, &sampled_snapshot};
|
ShaderStageRuntime sampled_runtime{&sampled_module, &sampled_snapshot};
|
||||||
|
|
||||||
constexpr uint64_t ordered_sampled_address = base + 0x10000;
|
constexpr uint64_t ordered_sampled_address = base + 0x10000;
|
||||||
const uint32_t ordered_sampled_value = 0x89abcdefu;
|
const uint32_t ordered_sampled_value = 0x89abcdefu;
|
||||||
@@ -15332,7 +15367,7 @@ public:
|
|||||||
ordered_descriptor.dword_count = 8;
|
ordered_descriptor.dword_count = 8;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot ordered_snapshot{};
|
ShaderRecompiler::IR::ResourceSnapshot ordered_snapshot{};
|
||||||
ordered_snapshot.images.push_back(ordered_descriptor);
|
ordered_snapshot.images.push_back(ordered_descriptor);
|
||||||
ShaderStageRuntime ordered_sampled_runtime{sampled_runtime.program,
|
ShaderStageRuntime ordered_sampled_runtime{sampled_runtime.module,
|
||||||
&ordered_snapshot};
|
&ordered_snapshot};
|
||||||
auto ordered_bindings = RenderExecutorTestAccess::PrepareGraphicsBindings(
|
auto ordered_bindings = RenderExecutorTestAccess::PrepareGraphicsBindings(
|
||||||
executor, storage_runtime, ordered_sampled_runtime, true);
|
executor, storage_runtime, ordered_sampled_runtime, true);
|
||||||
@@ -15387,23 +15422,25 @@ public:
|
|||||||
vertex_sampled_program.resource_tracking_complete = true;
|
vertex_sampled_program.resource_tracking_complete = true;
|
||||||
vertex_sampled_program.info.images.push_back(sampled_resource);
|
vertex_sampled_program.info.images.push_back(sampled_resource);
|
||||||
set_image_bindings(vertex_sampled_program);
|
set_image_bindings(vertex_sampled_program);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo vertex_sampled_info{};
|
ShaderModule vertex_sampled_module;
|
||||||
|
auto &vertex_sampled_info = vertex_sampled_module.info;
|
||||||
vertex_sampled_info.stage = vertex_sampled_program.stage;
|
vertex_sampled_info.stage = vertex_sampled_program.stage;
|
||||||
vertex_sampled_info.info = std::move(vertex_sampled_program.info);
|
vertex_sampled_info.info = std::move(vertex_sampled_program.info);
|
||||||
vertex_sampled_info.bindings =
|
vertex_sampled_info.bindings =
|
||||||
std::move(vertex_sampled_program.bindings);
|
std::move(vertex_sampled_program.bindings);
|
||||||
ShaderStageRuntime vertex_sampled_runtime{
|
ShaderStageRuntime vertex_sampled_runtime{
|
||||||
&vertex_sampled_info, sampled_runtime.resources};
|
&vertex_sampled_module, sampled_runtime.resources};
|
||||||
ShaderRecompiler::IR::Program pixel_storage_program{};
|
ShaderRecompiler::IR::Program pixel_storage_program{};
|
||||||
pixel_storage_program.stage = ShaderType::Pixel;
|
pixel_storage_program.stage = ShaderType::Pixel;
|
||||||
pixel_storage_program.resource_tracking_complete = true;
|
pixel_storage_program.resource_tracking_complete = true;
|
||||||
pixel_storage_program.info.images.push_back(storage_resource);
|
pixel_storage_program.info.images.push_back(storage_resource);
|
||||||
set_image_bindings(pixel_storage_program);
|
set_image_bindings(pixel_storage_program);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo pixel_storage_info{};
|
ShaderModule pixel_storage_module;
|
||||||
|
auto &pixel_storage_info = pixel_storage_module.info;
|
||||||
pixel_storage_info.stage = pixel_storage_program.stage;
|
pixel_storage_info.stage = pixel_storage_program.stage;
|
||||||
pixel_storage_info.info = std::move(pixel_storage_program.info);
|
pixel_storage_info.info = std::move(pixel_storage_program.info);
|
||||||
pixel_storage_info.bindings = std::move(pixel_storage_program.bindings);
|
pixel_storage_info.bindings = std::move(pixel_storage_program.bindings);
|
||||||
ShaderStageRuntime pixel_storage_runtime{&pixel_storage_info,
|
ShaderStageRuntime pixel_storage_runtime{&pixel_storage_module,
|
||||||
storage_runtime.resources};
|
storage_runtime.resources};
|
||||||
auto writable_alias_bindings =
|
auto writable_alias_bindings =
|
||||||
RenderExecutorTestAccess::PrepareGraphicsBindings(
|
RenderExecutorTestAccess::PrepareGraphicsBindings(
|
||||||
@@ -15476,13 +15513,14 @@ public:
|
|||||||
split_ir.resource_tracking_complete = true;
|
split_ir.resource_tracking_complete = true;
|
||||||
split_ir.info.images = {storage_resource, sampled_resource};
|
split_ir.info.images = {storage_resource, sampled_resource};
|
||||||
set_image_bindings(split_ir);
|
set_image_bindings(split_ir);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo split_program{};
|
ShaderModule split_module;
|
||||||
|
auto &split_program = split_module.info;
|
||||||
split_program.stage = split_ir.stage;
|
split_program.stage = split_ir.stage;
|
||||||
split_program.info = std::move(split_ir.info);
|
split_program.info = std::move(split_ir.info);
|
||||||
split_program.bindings = std::move(split_ir.bindings);
|
split_program.bindings = std::move(split_ir.bindings);
|
||||||
PreparedBindings split_bindings{};
|
PreparedBindings split_bindings{};
|
||||||
ShaderRecompiler::IR::ResourceSnapshot split_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot split_snapshot;
|
||||||
ShaderStageRuntime split_runtime{&split_program, &split_snapshot};
|
ShaderStageRuntime split_runtime{&split_module, &split_snapshot};
|
||||||
split_bindings.runtime = &split_runtime;
|
split_bindings.runtime = &split_runtime;
|
||||||
split_bindings.images.push_back(
|
split_bindings.images.push_back(
|
||||||
{split_id, texture_cache.FindTexture(split_id, split_storage_desc),
|
{split_id, texture_cache.FindTexture(split_id, split_storage_desc),
|
||||||
@@ -15569,12 +15607,13 @@ public:
|
|||||||
depth_views_ir.resource_tracking_complete = true;
|
depth_views_ir.resource_tracking_complete = true;
|
||||||
depth_views_ir.info.images = {sampled_resource, sampled_resource};
|
depth_views_ir.info.images = {sampled_resource, sampled_resource};
|
||||||
set_image_bindings(depth_views_ir);
|
set_image_bindings(depth_views_ir);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo depth_views_program{};
|
ShaderModule depth_views_module;
|
||||||
|
auto &depth_views_program = depth_views_module.info;
|
||||||
depth_views_program.stage = depth_views_ir.stage;
|
depth_views_program.stage = depth_views_ir.stage;
|
||||||
depth_views_program.info = std::move(depth_views_ir.info);
|
depth_views_program.info = std::move(depth_views_ir.info);
|
||||||
depth_views_program.bindings = std::move(depth_views_ir.bindings);
|
depth_views_program.bindings = std::move(depth_views_ir.bindings);
|
||||||
ShaderRecompiler::IR::ResourceSnapshot depth_views_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot depth_views_snapshot;
|
||||||
ShaderStageRuntime depth_views_runtime{&depth_views_program, &depth_views_snapshot};
|
ShaderStageRuntime depth_views_runtime{&depth_views_module, &depth_views_snapshot};
|
||||||
PreparedBindings depth_views_binding{};
|
PreparedBindings depth_views_binding{};
|
||||||
depth_views_binding.runtime = &depth_views_runtime;
|
depth_views_binding.runtime = &depth_views_runtime;
|
||||||
depth_views_binding.images.push_back(
|
depth_views_binding.images.push_back(
|
||||||
@@ -15909,8 +15948,8 @@ public:
|
|||||||
registers.SetDepthClearValue(0.375f);
|
registers.SetDepthClearValue(0.375f);
|
||||||
ShaderRecompiler::IR::ResourceSnapshot bounds_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot bounds_snapshot;
|
||||||
bounds_snapshot.images.push_back(sampled_depth_value);
|
bounds_snapshot.images.push_back(sampled_depth_value);
|
||||||
ShaderStageRuntime bounds_vertex{&vertex_sampled_info, &bounds_snapshot};
|
ShaderStageRuntime bounds_vertex{&vertex_sampled_module, &bounds_snapshot};
|
||||||
ShaderStageRuntime bounds_pixel{&sampled_info, &bounds_snapshot};
|
ShaderStageRuntime bounds_pixel{&sampled_module, &bounds_snapshot};
|
||||||
const auto depth_texels = depth_only.desc.info.extent.width *
|
const auto depth_texels = depth_only.desc.info.extent.width *
|
||||||
depth_only.desc.info.extent.height;
|
depth_only.desc.info.extent.height;
|
||||||
const auto depth_bytes = depth_texels * sizeof(uint32_t);
|
const auto depth_bytes = depth_texels * sizeof(uint32_t);
|
||||||
@@ -16326,9 +16365,9 @@ public:
|
|||||||
shared_depth_value.dword_count = 8;
|
shared_depth_value.dword_count = 8;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot shared_depth_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot shared_depth_snapshot;
|
||||||
shared_depth_snapshot.images.push_back(shared_depth_value);
|
shared_depth_snapshot.images.push_back(shared_depth_value);
|
||||||
ShaderStageRuntime shared_depth_vertex{&vertex_sampled_info,
|
ShaderStageRuntime shared_depth_vertex{&vertex_sampled_module,
|
||||||
&shared_depth_snapshot};
|
&shared_depth_snapshot};
|
||||||
ShaderStageRuntime shared_depth_pixel{&sampled_info,
|
ShaderStageRuntime shared_depth_pixel{&sampled_module,
|
||||||
&shared_depth_snapshot};
|
&shared_depth_snapshot};
|
||||||
for (const bool stencil_write : {true, false}) {
|
for (const bool stencil_write : {true, false}) {
|
||||||
registers.SetDepthRenderTarget(phased_depth_target);
|
registers.SetDepthRenderTarget(phased_depth_target);
|
||||||
@@ -16500,7 +16539,8 @@ public:
|
|||||||
(static_cast<uint32_t>(Prospero::ImageType::kColor2DArray) << 28u);
|
(static_cast<uint32_t>(Prospero::ImageType::kColor2DArray) << 28u);
|
||||||
array_texture.fields[4] = 1;
|
array_texture.fields[4] = 1;
|
||||||
|
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo array_program{};
|
ShaderModule array_module;
|
||||||
|
auto &array_program = array_module.info;
|
||||||
array_program.stage = ShaderType::Compute;
|
array_program.stage = ShaderType::Compute;
|
||||||
ShaderRecompiler::IR::ImageResource array_resource{};
|
ShaderRecompiler::IR::ImageResource array_resource{};
|
||||||
array_resource.resource_class =
|
array_resource.resource_class =
|
||||||
@@ -16517,7 +16557,7 @@ public:
|
|||||||
array_descriptor.dword_count = 8;
|
array_descriptor.dword_count = 8;
|
||||||
ShaderRecompiler::IR::ResourceSnapshot array_snapshot{};
|
ShaderRecompiler::IR::ResourceSnapshot array_snapshot{};
|
||||||
array_snapshot.images.push_back(array_descriptor);
|
array_snapshot.images.push_back(array_descriptor);
|
||||||
ShaderStageRuntime array_runtime{&array_program, &array_snapshot};
|
ShaderStageRuntime array_runtime{&array_module, &array_snapshot};
|
||||||
|
|
||||||
PreparedBindings array_binding;
|
PreparedBindings array_binding;
|
||||||
executor.PrepareBindings(array_runtime, array_binding);
|
executor.PrepareBindings(array_runtime, array_binding);
|
||||||
@@ -16684,7 +16724,8 @@ public:
|
|||||||
std::end(colliding_msaa_texture.fields),
|
std::end(colliding_msaa_texture.fields),
|
||||||
colliding_msaa_descriptor.dwords.begin());
|
colliding_msaa_descriptor.dwords.begin());
|
||||||
colliding_msaa_descriptor.dword_count = 8;
|
colliding_msaa_descriptor.dword_count = 8;
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo colliding_msaa_program{};
|
ShaderModule colliding_msaa_module;
|
||||||
|
auto &colliding_msaa_program = colliding_msaa_module.info;
|
||||||
colliding_msaa_program.stage = ShaderType::Compute;
|
colliding_msaa_program.stage = ShaderType::Compute;
|
||||||
auto colliding_msaa_resource = array_resource;
|
auto colliding_msaa_resource = array_resource;
|
||||||
colliding_msaa_resource.dimension =
|
colliding_msaa_resource.dimension =
|
||||||
@@ -16693,7 +16734,7 @@ public:
|
|||||||
ShaderRecompiler::IR::ResourceSnapshot colliding_msaa_snapshot{};
|
ShaderRecompiler::IR::ResourceSnapshot colliding_msaa_snapshot{};
|
||||||
colliding_msaa_snapshot.images.push_back(colliding_msaa_descriptor);
|
colliding_msaa_snapshot.images.push_back(colliding_msaa_descriptor);
|
||||||
ShaderStageRuntime colliding_msaa_runtime{
|
ShaderStageRuntime colliding_msaa_runtime{
|
||||||
&colliding_msaa_program, &colliding_msaa_snapshot};
|
&colliding_msaa_module, &colliding_msaa_snapshot};
|
||||||
PreparedBindings colliding_msaa_binding;
|
PreparedBindings colliding_msaa_binding;
|
||||||
executor.PrepareBindings(colliding_msaa_runtime, colliding_msaa_binding);
|
executor.PrepareBindings(colliding_msaa_runtime, colliding_msaa_binding);
|
||||||
executor.RebindImages(colliding_msaa_binding);
|
executor.RebindImages(colliding_msaa_binding);
|
||||||
@@ -16744,7 +16785,8 @@ public:
|
|||||||
std::copy(std::begin(msaa_texture.fields), std::end(msaa_texture.fields),
|
std::copy(std::begin(msaa_texture.fields), std::end(msaa_texture.fields),
|
||||||
msaa_descriptor.dwords.begin());
|
msaa_descriptor.dwords.begin());
|
||||||
msaa_descriptor.dword_count = 8;
|
msaa_descriptor.dword_count = 8;
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo msaa_program{};
|
ShaderModule msaa_module;
|
||||||
|
auto &msaa_program = msaa_module.info;
|
||||||
msaa_program.stage = ShaderType::Compute;
|
msaa_program.stage = ShaderType::Compute;
|
||||||
auto msaa_resource = array_resource;
|
auto msaa_resource = array_resource;
|
||||||
msaa_resource.dimension =
|
msaa_resource.dimension =
|
||||||
@@ -16752,7 +16794,7 @@ public:
|
|||||||
msaa_program.info.images.push_back(msaa_resource);
|
msaa_program.info.images.push_back(msaa_resource);
|
||||||
ShaderRecompiler::IR::ResourceSnapshot msaa_snapshot{};
|
ShaderRecompiler::IR::ResourceSnapshot msaa_snapshot{};
|
||||||
msaa_snapshot.images.push_back(msaa_descriptor);
|
msaa_snapshot.images.push_back(msaa_descriptor);
|
||||||
ShaderStageRuntime msaa_runtime{&msaa_program, &msaa_snapshot};
|
ShaderStageRuntime msaa_runtime{&msaa_module, &msaa_snapshot};
|
||||||
PreparedBindings msaa_binding;
|
PreparedBindings msaa_binding;
|
||||||
executor.PrepareBindings(msaa_runtime, msaa_binding);
|
executor.PrepareBindings(msaa_runtime, msaa_binding);
|
||||||
executor.RebindImages(msaa_binding);
|
executor.RebindImages(msaa_binding);
|
||||||
@@ -16784,7 +16826,8 @@ public:
|
|||||||
std::end(msaa_array_texture.fields),
|
std::end(msaa_array_texture.fields),
|
||||||
msaa_array_descriptor.dwords.begin());
|
msaa_array_descriptor.dwords.begin());
|
||||||
msaa_array_descriptor.dword_count = 8;
|
msaa_array_descriptor.dword_count = 8;
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo msaa_array_program{};
|
ShaderModule msaa_array_module;
|
||||||
|
auto &msaa_array_program = msaa_array_module.info;
|
||||||
msaa_array_program.stage = ShaderType::Compute;
|
msaa_array_program.stage = ShaderType::Compute;
|
||||||
auto msaa_array_resource = array_resource;
|
auto msaa_array_resource = array_resource;
|
||||||
msaa_array_resource.dimension =
|
msaa_array_resource.dimension =
|
||||||
@@ -16792,7 +16835,7 @@ public:
|
|||||||
msaa_array_program.info.images.push_back(msaa_array_resource);
|
msaa_array_program.info.images.push_back(msaa_array_resource);
|
||||||
ShaderRecompiler::IR::ResourceSnapshot msaa_array_snapshot{};
|
ShaderRecompiler::IR::ResourceSnapshot msaa_array_snapshot{};
|
||||||
msaa_array_snapshot.images.push_back(msaa_array_descriptor);
|
msaa_array_snapshot.images.push_back(msaa_array_descriptor);
|
||||||
ShaderStageRuntime msaa_array_runtime{&msaa_array_program, &msaa_array_snapshot};
|
ShaderStageRuntime msaa_array_runtime{&msaa_array_module, &msaa_array_snapshot};
|
||||||
PreparedBindings msaa_array_binding;
|
PreparedBindings msaa_array_binding;
|
||||||
executor.PrepareBindings(msaa_array_runtime, msaa_array_binding);
|
executor.PrepareBindings(msaa_array_runtime, msaa_array_binding);
|
||||||
executor.RebindImages(msaa_array_binding);
|
executor.RebindImages(msaa_array_binding);
|
||||||
@@ -17033,7 +17076,8 @@ public:
|
|||||||
DstSel(4, 5, 6, 7) | (static_cast<uint32_t>(linear) << 20u) |
|
DstSel(4, 5, 6, 7) | (static_cast<uint32_t>(linear) << 20u) |
|
||||||
(static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u);
|
(static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u);
|
||||||
|
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo program{};
|
ShaderModule module;
|
||||||
|
auto &program = module.info;
|
||||||
program.stage = ShaderType::Compute;
|
program.stage = ShaderType::Compute;
|
||||||
ShaderRecompiler::IR::ImageResource stencil_resource{};
|
ShaderRecompiler::IR::ImageResource stencil_resource{};
|
||||||
stencil_resource.resource_class =
|
stencil_resource.resource_class =
|
||||||
@@ -17050,7 +17094,7 @@ public:
|
|||||||
descriptor.dwords.begin());
|
descriptor.dwords.begin());
|
||||||
descriptor.dword_count = 8;
|
descriptor.dword_count = 8;
|
||||||
snapshot.images.push_back(descriptor);
|
snapshot.images.push_back(descriptor);
|
||||||
ShaderStageRuntime runtime{&program, &snapshot};
|
ShaderStageRuntime runtime{&module, &snapshot};
|
||||||
|
|
||||||
PreparedBindings prepared;
|
PreparedBindings prepared;
|
||||||
context.GetRenderExecutor().PrepareBindings(runtime, prepared);
|
context.GetRenderExecutor().PrepareBindings(runtime, prepared);
|
||||||
@@ -17139,10 +17183,10 @@ public:
|
|||||||
"captured stencil shader could not resolve its clear byte");
|
"captured stencil shader could not resolve its clear byte");
|
||||||
ShaderRecompiler::IR::ApplyResourceSpecialization(stencil_translated.program,
|
ShaderRecompiler::IR::ApplyResourceSpecialization(stencil_translated.program,
|
||||||
stencil_specialization);
|
stencil_specialization);
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo stencil_program{};
|
ShaderModule stencil_program;
|
||||||
stencil_program.stage = ShaderType::Compute;
|
stencil_program.info.stage = ShaderType::Compute;
|
||||||
stencil_program.info = std::move(stencil_translated.program.info);
|
stencil_program.info.info = std::move(stencil_translated.program.info);
|
||||||
stencil_compute.stage.program = &stencil_program;
|
stencil_compute.stage.module = &stencil_program;
|
||||||
vk::ClearValue stencil_initial{};
|
vk::ClearValue stencil_initial{};
|
||||||
stencil_initial.depthStencil = vk::ClearDepthStencilValue{0.625f, 0x91};
|
stencil_initial.depthStencil = vk::ClearDepthStencilValue{0.625f, 0x91};
|
||||||
TextureCacheTestAccess::ClearImage(texture_cache, scheduler.Current(), depth_id,
|
TextureCacheTestAccess::ClearImage(texture_cache, scheduler.Current(), depth_id,
|
||||||
@@ -18294,19 +18338,20 @@ public:
|
|||||||
AppendEnd(&test.fragment_code);
|
AppendEnd(&test.fragment_code);
|
||||||
auto fragment = CompileFragmentCase(test);
|
auto fragment = CompileFragmentCase(test);
|
||||||
const auto vertex_spirv = TestSpv::MakePassthroughVertexSpirv(false);
|
const auto vertex_spirv = TestSpv::MakePassthroughVertexSpirv(false);
|
||||||
ShaderProgram vertex_shader{1, CreateShaderModule(name, vertex_spirv)};
|
ShaderModule vertex_shader{.id = 1, .module = CreateShaderModule(name, vertex_spirv)};
|
||||||
ShaderProgram pixel_shader{2, CreateShaderModule(name, fragment.spirv)};
|
vertex_shader.info.stage = ShaderType::Vertex;
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo vertex_program{};
|
vertex_shader.info.info.vertex_fetch_components[0] = 2;
|
||||||
vertex_program.stage = ShaderType::Vertex;
|
vertex_shader.info.info.vertex_fetch_components[1] = packed_vertex_color ? 3 : 4;
|
||||||
vertex_program.info.vertex_fetch_components[0] = 2;
|
// No narrower host format covers the components the stage reads from either attribute.
|
||||||
vertex_program.info.vertex_fetch_components[1] = packed_vertex_color ? 3 : 4;
|
vertex_shader.vertex_formats = {VulkanFormat(Prospero::BufferFormat::k32_32Float),
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo pixel_program{};
|
VulkanFormat(color_format)};
|
||||||
pixel_program.stage = ShaderType::Pixel;
|
ShaderModule pixel_shader{.id = 2, .module = CreateShaderModule(name, fragment.spirv)};
|
||||||
pixel_program.info = fragment.program.info;
|
pixel_shader.info.stage = ShaderType::Pixel;
|
||||||
pixel_program.bindings = fragment.program.bindings;
|
pixel_shader.info.info = fragment.program.info;
|
||||||
|
pixel_shader.info.bindings = fragment.program.bindings;
|
||||||
ShaderVertexInputInfo vertex{};
|
ShaderVertexInputInfo vertex{};
|
||||||
ShaderRecompiler::IR::ResourceSnapshot vertex_snapshot;
|
ShaderRecompiler::IR::ResourceSnapshot vertex_snapshot;
|
||||||
vertex.stage.program = &vertex_program;
|
vertex.stage.module = &vertex_shader;
|
||||||
vertex.stage.resources = &vertex_snapshot;
|
vertex.stage.resources = &vertex_snapshot;
|
||||||
vertex.resources_num = 2;
|
vertex.resources_num = 2;
|
||||||
vertex.buffers_num = 1;
|
vertex.buffers_num = 1;
|
||||||
@@ -18317,10 +18362,10 @@ public:
|
|||||||
vertex.resources[i].fields[3] = DstSel(4, 5, 6, 7) |
|
vertex.resources[i].fields[3] = DstSel(4, 5, 6, 7) |
|
||||||
(static_cast<uint32_t>(format) << 12u);
|
(static_cast<uint32_t>(format) << 12u);
|
||||||
vertex.resources_dst[i].registers_num =
|
vertex.resources_dst[i].registers_num =
|
||||||
i == 0 ? 2 : vertex_program.info.vertex_fetch_components[1];
|
i == 0 ? 2 : vertex_shader.info.info.vertex_fetch_components[1];
|
||||||
}
|
}
|
||||||
ShaderPixelInputInfo pixel{};
|
ShaderPixelInputInfo pixel{};
|
||||||
pixel.stage.program = &pixel_program;
|
pixel.stage.module = &pixel_shader;
|
||||||
pixel.stage.resources = &fragment.resources;
|
pixel.stage.resources = &fragment.resources;
|
||||||
|
|
||||||
RenderColorInfo color{};
|
RenderColorInfo color{};
|
||||||
@@ -18368,8 +18413,6 @@ public:
|
|||||||
DrawRenderState state{.depth_info = depth, .color_info = {color}, .color_count = 1,
|
DrawRenderState state{.depth_info = depth, .color_info = {color}, .color_count = 1,
|
||||||
.topology = topology, .ps_active = true,
|
.topology = topology, .ps_active = true,
|
||||||
.vertex_info = {vertex}, .ps_input_info = pixel};
|
.vertex_info = {vertex}, .ps_input_info = pixel};
|
||||||
state.vertex_info[0].stage.handle = &vertex_shader;
|
|
||||||
state.ps_input_info.stage.handle = &pixel_shader;
|
|
||||||
return context.GetPipelineCache().GetGraphicsPipeline(scheduler.Current(), state);
|
return context.GetPipelineCache().GetGraphicsPipeline(scheduler.Current(), state);
|
||||||
};
|
};
|
||||||
auto &filled = pipeline(true, 2, 2);
|
auto &filled = pipeline(true, 2, 2);
|
||||||
@@ -18723,8 +18766,6 @@ public:
|
|||||||
.code_size_bytes = static_cast<uint32_t>(native_pixel.size() * sizeof(u32))});
|
.code_size_bytes = static_cast<uint32_t>(native_pixel.size() * sizeof(u32))});
|
||||||
shaders.SetEsShaderBase(vertex_address);
|
shaders.SetEsShaderBase(vertex_address);
|
||||||
shaders.SetPsShaderBase(pixel_address);
|
shaders.SetPsShaderBase(pixel_address);
|
||||||
const auto owned_vertex_shader = vertex_shader;
|
|
||||||
const auto owned_pixel_shader = pixel_shader;
|
|
||||||
depth.stencil_test_enable = false;
|
depth.stencil_test_enable = false;
|
||||||
registers.SetViewportTransformControl(0x300);
|
registers.SetViewportTransformControl(0x300);
|
||||||
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriList);
|
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriList);
|
||||||
@@ -18738,8 +18779,6 @@ public:
|
|||||||
const auto native = refresh();
|
const auto native = refresh();
|
||||||
vertex = native.vertex_info[0];
|
vertex = native.vertex_info[0];
|
||||||
pixel = native.ps_input_info;
|
pixel = native.ps_input_info;
|
||||||
vertex_shader = *vertex.stage.handle;
|
|
||||||
pixel_shader = *pixel.stage.handle;
|
|
||||||
};
|
};
|
||||||
const auto silent = refresh();
|
const auto silent = refresh();
|
||||||
registers.SetDepthShaderControl({.shader_kill_enable = true});
|
registers.SetDepthShaderControl({.shader_kill_enable = true});
|
||||||
@@ -18763,7 +18802,7 @@ public:
|
|||||||
depth_writing.ps_active && depth_writing.mrt_mask == 0 &&
|
depth_writing.ps_active && depth_writing.mrt_mask == 0 &&
|
||||||
writing.ps_active && writing.mrt_mask == 1u && partial.mrt_mask == 1u &&
|
writing.ps_active && writing.mrt_mask == 1u && partial.mrt_mask == 1u &&
|
||||||
writing.VertexStages().size() == 1 &&
|
writing.VertexStages().size() == 1 &&
|
||||||
writing.vertex_info[0].stage.handle != nullptr,
|
writing.vertex_info[0].stage.module != nullptr,
|
||||||
"pixel activity or its MRT mask ignored the color outputs or depth side effects");
|
"pixel activity or its MRT mask ignored the color outputs or depth side effects");
|
||||||
std::array<uint64_t, 2> wave_ids{};
|
std::array<uint64_t, 2> wave_ids{};
|
||||||
std::array<std::vector<u32>, 2> wave_keys;
|
std::array<std::vector<u32>, 2> wave_keys;
|
||||||
@@ -18774,17 +18813,17 @@ public:
|
|||||||
registers.SetPsInControl(wave.control);
|
registers.SetPsInControl(wave.control);
|
||||||
native_programs();
|
native_programs();
|
||||||
Require(name, "pixel wave metadata propagation",
|
Require(name, "pixel wave metadata propagation",
|
||||||
pixel.input_num == 8 && pixel.stage.program->wave_size == wave.width,
|
pixel.input_num == 8 && pixel.stage.module->info.wave_size == wave.width,
|
||||||
"SPI_PS_IN_CONTROL width did not reach the compiled pixel program");
|
"SPI_PS_IN_CONTROL width did not reach the compiled pixel program");
|
||||||
const auto index = static_cast<uint32_t>(wave.width == 32);
|
const auto index = static_cast<uint32_t>(wave.width == 32);
|
||||||
std::vector<u32> key;
|
std::vector<u32> key;
|
||||||
BuildStageStaticKey(pixel, key);
|
BuildStageStaticKey(pixel, key);
|
||||||
if (wave_ids[index] != 0) {
|
if (wave_ids[index] != 0) {
|
||||||
Require(name, "pixel wave cache reuse",
|
Require(name, "pixel wave cache reuse",
|
||||||
pixel_shader.id == wave_ids[index] && key == wave_keys[index],
|
pixel.stage.module->id == wave_ids[index] && key == wave_keys[index],
|
||||||
"restoring wave64 did not reuse its original program");
|
"restoring wave64 did not reuse its original program");
|
||||||
}
|
}
|
||||||
wave_ids[index] = pixel_shader.id;
|
wave_ids[index] = pixel.stage.module->id;
|
||||||
wave_keys[index] = std::move(key);
|
wave_keys[index] = std::move(key);
|
||||||
draw(pipeline(true, 2, 2));
|
draw(pipeline(true, 2, 2));
|
||||||
const auto wave_pixels = read_color();
|
const auto wave_pixels = read_color();
|
||||||
@@ -18832,8 +18871,8 @@ public:
|
|||||||
(wave == 32u ? 0x00400000u : 0u));
|
(wave == 32u ? 0x00400000u : 0u));
|
||||||
native_programs();
|
native_programs();
|
||||||
Require(name, "native NGG waterfall wave",
|
Require(name, "native NGG waterfall wave",
|
||||||
vertex.stage.program->stage == ShaderType::Vertex &&
|
vertex.stage.module->info.stage == ShaderType::Vertex &&
|
||||||
vertex.stage.program->wave_size == wave,
|
vertex.stage.module->info.wave_size == wave,
|
||||||
"NGG waterfall bypassed the native vertex path or lost its guest wave width");
|
"NGG waterfall bypassed the native vertex path or lost its guest wave width");
|
||||||
for (const u32 count : {3u, 6u, 33u}) {
|
for (const u32 count : {3u, 6u, 33u}) {
|
||||||
draw(pipeline(true, 2, 2), count);
|
draw(pipeline(true, 2, 2), count);
|
||||||
@@ -18907,10 +18946,10 @@ public:
|
|||||||
auto &selected = pipeline(true, 2, 2);
|
auto &selected = pipeline(true, 2, 2);
|
||||||
if (test.mode == ShaderAlphaBlendSource::SourceAlpha) {
|
if (test.mode == ShaderAlphaBlendSource::SourceAlpha) {
|
||||||
Require(name, "equal blend equation cache reuse",
|
Require(name, "equal blend equation cache reuse",
|
||||||
broadcast_program == 0 || (pixel_shader.id == broadcast_program &&
|
broadcast_program == 0 || (pixel.stage.module->id == broadcast_program &&
|
||||||
selected.pipeline == broadcast_pipeline),
|
selected.pipeline == broadcast_pipeline),
|
||||||
"equivalent separate alpha state created another shader or pipeline");
|
"equivalent separate alpha state created another shader or pipeline");
|
||||||
broadcast_program = pixel_shader.id;
|
broadcast_program = pixel.stage.module->id;
|
||||||
broadcast_pipeline = selected.pipeline;
|
broadcast_pipeline = selected.pipeline;
|
||||||
}
|
}
|
||||||
constexpr std::array<float, 4> destination{0.3f, 0.3f, 0.1f, 0.2f};
|
constexpr std::array<float, 4> destination{0.3f, 0.3f, 0.1f, 0.2f};
|
||||||
@@ -19333,6 +19372,13 @@ public:
|
|||||||
check("auto embedded fetch", fetch_vs, false, 4);
|
check("auto embedded fetch", fetch_vs, false, 4);
|
||||||
check("indexed native fetch", vertex_address, true, 2);
|
check("indexed native fetch", vertex_address, true, 2);
|
||||||
check("auto native fetch", vertex_address, false, 6);
|
check("auto native fetch", vertex_address, false, 6);
|
||||||
|
// Pipelines created from only their key and stage modules draw the same.
|
||||||
|
scheduler.Finish();
|
||||||
|
Require("PipelineFromKey", "vertex input pipelines",
|
||||||
|
PipelineCacheTestAccess::RecreateGraphicsPipelines(context.GetPipelineCache()) > 0,
|
||||||
|
"no cached graphics pipeline named only compiled modules");
|
||||||
|
check("recreated indexed embedded fetch", fetch_vs, true, 0);
|
||||||
|
check("recreated auto native fetch", vertex_address, false, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A fourth VS invocation reads beyond the descriptor instead of reconstructing the corner.
|
// A fourth VS invocation reads beyond the descriptor instead of reconstructing the corner.
|
||||||
@@ -19382,10 +19428,7 @@ public:
|
|||||||
registers.SetPsInputEna(2);
|
registers.SetPsInputEna(2);
|
||||||
registers.SetPsInputAddr(2);
|
registers.SetPsInputAddr(2);
|
||||||
registers.SetPsInputSettings(0, 0);
|
registers.SetPsInputSettings(0, 0);
|
||||||
for (const auto primitive : {Prospero::PrimitiveType::kRectList,
|
const auto check_rect = [&](Prospero::PrimitiveType primitive, const char *rect_name) {
|
||||||
Prospero::PrimitiveType::kRectListLegacy}) {
|
|
||||||
const char *rect_name = primitive == Prospero::PrimitiveType::kRectList
|
|
||||||
? "RectListThreeRecords" : "LegacyRectListThreeRecords";
|
|
||||||
user_config.SetPrimitiveType(primitive);
|
user_config.SetPrimitiveType(primitive);
|
||||||
registers.SetModeControl({});
|
registers.SetModeControl({});
|
||||||
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), sparse_color.image_id,
|
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), sparse_color.image_id,
|
||||||
@@ -19409,7 +19452,14 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
check_rect(Prospero::PrimitiveType::kRectList, "RectListThreeRecords");
|
||||||
|
check_rect(Prospero::PrimitiveType::kRectListLegacy, "LegacyRectListThreeRecords");
|
||||||
|
scheduler.Finish();
|
||||||
|
Require("PipelineFromKey", "rectangle-list pipelines",
|
||||||
|
PipelineCacheTestAccess::RecreateGraphicsPipelines(context.GetPipelineCache()) > 0,
|
||||||
|
"no cached graphics pipeline named only compiled modules");
|
||||||
|
check_rect(Prospero::PrimitiveType::kRectList, "PipelineFromKeyRectList");
|
||||||
// Captured format30 uses uncompressed mode9 at MRT2. Keep a blended
|
// Captured format30 uses uncompressed mode9 at MRT2. Keep a blended
|
||||||
// floating-point MRT live beside it, including sparse export routing.
|
// floating-point MRT live beside it, including sparse export routing.
|
||||||
constexpr uint64_t packed_address = depth_address + 0x28000;
|
constexpr uint64_t packed_address = depth_address + 0x28000;
|
||||||
@@ -19516,9 +19566,10 @@ public:
|
|||||||
"packed conversion or rounding contaminated another MRT or followed a physical slot");
|
"packed conversion or rounding contaminated another MRT or followed a physical slot");
|
||||||
if (test.slot == 2) {
|
if (test.slot == 2) {
|
||||||
auto &id = test.truncate ? truncate_program : half_up_program;
|
auto &id = test.truncate ? truncate_program : half_up_program;
|
||||||
Require(name, "packed rounding program reuse", id == 0 || id == pixel_shader.id,
|
Require(name, "packed rounding program reuse",
|
||||||
|
id == 0 || id == pixel.stage.module->id,
|
||||||
"restoring half-up rounding failed to reuse its program");
|
"restoring half-up rounding failed to reuse its program");
|
||||||
id = pixel_shader.id;
|
id = pixel.stage.module->id;
|
||||||
}
|
}
|
||||||
RenderColorInfo packed_target{}, float_target{};
|
RenderColorInfo packed_target{}, float_target{};
|
||||||
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
||||||
@@ -19576,9 +19627,6 @@ public:
|
|||||||
DestroyBuffer(&packed_output);
|
DestroyBuffer(&packed_output);
|
||||||
m_device.destroySampler(packed_sampler);
|
m_device.destroySampler(packed_sampler);
|
||||||
DestroyBuffer(&stencil_readback);
|
DestroyBuffer(&stencil_readback);
|
||||||
|
|
||||||
vertex_shader = owned_vertex_shader;
|
|
||||||
pixel_shader = owned_pixel_shader;
|
|
||||||
}
|
}
|
||||||
resources.UnmapMemory(depth_address, allocation_size);
|
resources.UnmapMemory(depth_address, allocation_size);
|
||||||
scheduler.Finish();
|
scheduler.Finish();
|
||||||
@@ -44530,7 +44578,7 @@ void CheckComputeLdsLimit(VulkanHarness &vulkan) {
|
|||||||
regs.cs_regs.num_thread_z = 1;
|
regs.cs_regs.num_thread_z = 1;
|
||||||
regs.cs_regs.wave_size = 32;
|
regs.cs_regs.wave_size = 32;
|
||||||
PipelineCache cache(graphics, nullptr);
|
PipelineCache cache(graphics, nullptr);
|
||||||
ShaderProgram previous;
|
uint64_t previous_id = 0;
|
||||||
uint16_t previous_units = 0;
|
uint16_t previous_units = 0;
|
||||||
for (const auto units : {static_cast<uint16_t>(limit_units - 1u), limit_units,
|
for (const auto units : {static_cast<uint16_t>(limit_units - 1u), limit_units,
|
||||||
uint16_t{112}, uint16_t{128}, uint16_t{128}}) {
|
uint16_t{112}, uint16_t{128}, uint16_t{128}}) {
|
||||||
@@ -44544,12 +44592,12 @@ void CheckComputeLdsLimit(VulkanHarness &vulkan) {
|
|||||||
Require(name, "pipeline creation",
|
Require(name, "pipeline creation",
|
||||||
cache.GetComputePipeline(input).pipeline != nullptr,
|
cache.GetComputePipeline(input).pipeline != nullptr,
|
||||||
"full-size LDS shader did not create a Vulkan compute pipeline");
|
"full-size LDS shader did not create a Vulkan compute pipeline");
|
||||||
if (previous.id != 0) {
|
if (previous_id != 0) {
|
||||||
Require(name, "guest-size cache identity",
|
Require(name, "guest-size cache identity",
|
||||||
(program.id == previous.id) == (units == previous_units),
|
(program->id == previous_id) == (units == previous_units),
|
||||||
"different LDS sizes shared a shader, or repeating a size recompiled it");
|
"different LDS sizes shared a shader, or repeating a size recompiled it");
|
||||||
}
|
}
|
||||||
previous = program;
|
previous_id = program->id;
|
||||||
previous_units = units;
|
previous_units = units;
|
||||||
}
|
}
|
||||||
std::printf("[gpu] %-32s ok\n", name);
|
std::printf("[gpu] %-32s ok\n", name);
|
||||||
@@ -44585,7 +44633,7 @@ void CheckStableProgramIds(VulkanHarness &vulkan) {
|
|||||||
DstSel(4, 5, 6, 7) | (static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u)}};
|
DstSel(4, 5, 6, 7) | (static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u)}};
|
||||||
std::copy_n(buffer.fields, 4, regs.cs_user_sgpr.value);
|
std::copy_n(buffer.fields, 4, regs.cs_user_sgpr.value);
|
||||||
ShaderComputeInputInfo input{};
|
ShaderComputeInputInfo input{};
|
||||||
return cache.GetComputeProgram(regs, input).id;
|
return cache.GetComputeProgram(regs, input)->id;
|
||||||
};
|
};
|
||||||
std::array<uint64_t, 3> forward{}, reverse{};
|
std::array<uint64_t, 3> forward{}, reverse{};
|
||||||
{
|
{
|
||||||
@@ -45283,10 +45331,10 @@ void CheckEmbeddedFetchVertexOffset() {
|
|||||||
u32 index_offset) {
|
u32 index_offset) {
|
||||||
ShaderVertexInputInfo vertex;
|
ShaderVertexInputInfo vertex;
|
||||||
vertex.fetch_embedded = true;
|
vertex.fetch_embedded = true;
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo program{};
|
ShaderModule module;
|
||||||
program.user_data_base = result.program.user_data_base;
|
module.info.user_data_base = result.program.user_data_base;
|
||||||
program.info.vertex_offset_sgpr = result.program.info.vertex_offset_sgpr;
|
module.info.info.vertex_offset_sgpr = result.program.info.vertex_offset_sgpr;
|
||||||
vertex.stage.program = &program;
|
vertex.stage.module = &module;
|
||||||
vertex.stage.resources = &result.resources;
|
vertex.stage.resources = &result.resources;
|
||||||
return ResolveDrawOffsets(index_offset, vertex).first;
|
return ResolveDrawOffsets(index_offset, vertex).first;
|
||||||
};
|
};
|
||||||
@@ -45294,11 +45342,11 @@ void CheckEmbeddedFetchVertexOffset() {
|
|||||||
const auto ResolveInstance = [](const CompiledShader &result) {
|
const auto ResolveInstance = [](const CompiledShader &result) {
|
||||||
ShaderVertexInputInfo vertex;
|
ShaderVertexInputInfo vertex;
|
||||||
vertex.fetch_embedded = true;
|
vertex.fetch_embedded = true;
|
||||||
ShaderRecompiler::IR::CompiledShaderInfo program{};
|
ShaderModule module;
|
||||||
program.user_data_base = result.program.user_data_base;
|
module.info.user_data_base = result.program.user_data_base;
|
||||||
program.info.instance_offset_sgpr =
|
module.info.info.instance_offset_sgpr =
|
||||||
result.program.info.instance_offset_sgpr;
|
result.program.info.instance_offset_sgpr;
|
||||||
vertex.stage.program = &program;
|
vertex.stage.module = &module;
|
||||||
vertex.stage.resources = &result.resources;
|
vertex.stage.resources = &result.resources;
|
||||||
return ResolveDrawOffsets(0, vertex).second;
|
return ResolveDrawOffsets(0, vertex).second;
|
||||||
};
|
};
|
||||||
@@ -47924,17 +47972,17 @@ void CheckDynamicRenderingState() {
|
|||||||
Require("DynamicRenderingState", "layout identity", first != changed,
|
Require("DynamicRenderingState", "layout identity", first != changed,
|
||||||
"attachment layout did not participate in rendering identity");
|
"attachment layout did not participate in rendering identity");
|
||||||
|
|
||||||
PipelineRenderingState rgba{};
|
GraphicsPipelineKey rgba{};
|
||||||
rgba.color_count = 1;
|
rgba.rendering.color_count = 1;
|
||||||
rgba.color_formats[0] = vk::Format::eR8G8B8A8Unorm;
|
rgba.rendering.color_formats[0] = vk::Format::eR8G8B8A8Unorm;
|
||||||
auto uint_color = rgba;
|
auto uint_color = rgba;
|
||||||
uint_color.color_formats[0] = vk::Format::eR8G8B8A8Uint;
|
uint_color.rendering.color_formats[0] = vk::Format::eR8G8B8A8Uint;
|
||||||
Require("DynamicRenderingState", "pipeline color format identity",
|
Require("DynamicRenderingState", "pipeline color format identity",
|
||||||
rgba != uint_color,
|
rgba != uint_color,
|
||||||
"distinct dynamic-rendering formats can alias one pipeline key");
|
"distinct dynamic-rendering formats can alias one pipeline key");
|
||||||
auto depth = rgba;
|
auto depth = rgba;
|
||||||
depth.depth_format = vk::Format::eD32SfloatS8Uint;
|
depth.rendering.depth_format = vk::Format::eD32SfloatS8Uint;
|
||||||
depth.stencil_format = vk::Format::eD32SfloatS8Uint;
|
depth.rendering.stencil_format = vk::Format::eD32SfloatS8Uint;
|
||||||
Require("DynamicRenderingState", "pipeline depth/stencil identity",
|
Require("DynamicRenderingState", "pipeline depth/stencil identity",
|
||||||
rgba != depth,
|
rgba != depth,
|
||||||
"depth/stencil formats did not participate in pipeline identity");
|
"depth/stencil formats did not participate in pipeline identity");
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "graphics/host_gpu/renderer/image/imageView.h"
|
#include "graphics/host_gpu/renderer/image/imageView.h"
|
||||||
#include "graphics/host_gpu/renderer/image/textureCommon.h"
|
#include "graphics/host_gpu/renderer/image/textureCommon.h"
|
||||||
#include "graphics/host_gpu/renderer/pipeline/blendMapping.h"
|
#include "graphics/host_gpu/renderer/pipeline/blendMapping.h"
|
||||||
|
#include "graphics/host_gpu/renderer/pipeline/pipelineCache.h"
|
||||||
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
||||||
#include "graphics/shader/recompiler/ShaderRecompiler.h"
|
#include "graphics/shader/recompiler/ShaderRecompiler.h"
|
||||||
#include "graphics/shader/recompiler/backend/spirv/SpirvEmitter.h"
|
#include "graphics/shader/recompiler/backend/spirv/SpirvEmitter.h"
|
||||||
@@ -163,10 +164,10 @@ void CompilePixelRuntime(const ShaderParams ¶ms,
|
|||||||
|
|
||||||
options.input_info.pixel = &input_info;
|
options.input_info.pixel = &input_info;
|
||||||
auto result = RecompileForTest(params.code, options);
|
auto result = RecompileForTest(params.code, options);
|
||||||
static std::deque<ShaderRecompiler::IR::CompiledShaderInfo> programs;
|
static std::deque<ShaderModule> modules;
|
||||||
static std::deque<ShaderRecompiler::IR::ResourceSnapshot> resources;
|
static std::deque<ShaderRecompiler::IR::ResourceSnapshot> resources;
|
||||||
programs.push_back(std::move(result.program).TakeCompiledInfo());
|
modules.push_back({.info = std::move(result.program).TakeCompiledInfo()});
|
||||||
input_info.stage.program = &programs.back();
|
input_info.stage.module = &modules.back();
|
||||||
resources.push_back(std::move(result.resources));
|
resources.push_back(std::move(result.resources));
|
||||||
input_info.stage.resources = &resources.back();
|
input_info.stage.resources = &resources.back();
|
||||||
}
|
}
|
||||||
@@ -1157,7 +1158,7 @@ void TestNativeShaderResourceDependencies() {
|
|||||||
set_buffer(0, 0x1000, 16, 3);
|
set_buffer(0, 0x1000, 16, 3);
|
||||||
set_buffer(1, 0x1800, 4, 7);
|
set_buffer(1, 0x1800, 4, 7);
|
||||||
set_buffer(2, 0x2000, 0, 64);
|
set_buffer(2, 0x2000, 0, 64);
|
||||||
const ShaderRecompiler::IR::CompiledShaderInfo compiled{
|
const ShaderModule compiled{.info = {
|
||||||
.stage = program.stage,
|
.stage = program.stage,
|
||||||
.shader_hash = program.shader_hash,
|
.shader_hash = program.shader_hash,
|
||||||
.wave_size = program.wave_size,
|
.wave_size = program.wave_size,
|
||||||
@@ -1166,8 +1167,8 @@ void TestNativeShaderResourceDependencies() {
|
|||||||
.scratch_dwords = program.scratch_dwords,
|
.scratch_dwords = program.scratch_dwords,
|
||||||
.info = program.info,
|
.info = program.info,
|
||||||
.bindings = program.bindings,
|
.bindings = program.bindings,
|
||||||
};
|
}};
|
||||||
ShaderStageRuntime runtime{.program = &compiled, .resources = &resources};
|
ShaderStageRuntime runtime{.module = &compiled, .resources = &resources};
|
||||||
Check(HasShaderBufferWrites(runtime),
|
Check(HasShaderBufferWrites(runtime),
|
||||||
"graphics/compute write predicate lost nonempty written buffers");
|
"graphics/compute write predicate lost nonempty written buffers");
|
||||||
set_buffer(0, 0, 16, 3);
|
set_buffer(0, 0, 16, 3);
|
||||||
@@ -15925,8 +15926,8 @@ void TestPixelProgramCacheBindingIdentity() {
|
|||||||
first_params.hash == XXH3_64bits(shader.data(), shader.size_bytes()) &&
|
first_params.hash == XXH3_64bits(shader.data(), shader.size_bytes()) &&
|
||||||
first_params.hash == second_params.hash &&
|
first_params.hash == second_params.hash &&
|
||||||
first_key == MakeStageStaticKey(second_info) &&
|
first_key == MakeStageStaticKey(second_info) &&
|
||||||
first_info.stage.program != nullptr &&
|
first_info.stage.module != nullptr &&
|
||||||
second_info.stage.program != nullptr,
|
second_info.stage.module != nullptr,
|
||||||
"pixel program matching did not preserve an identical source/static identity");
|
"pixel program matching did not preserve an identical source/static identity");
|
||||||
return std::pair {first_params.hash, first_key};
|
return std::pair {first_params.hash, first_key};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user