mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
render: simplify command and resource ownership
This commit is contained in:
@@ -108,12 +108,6 @@ static vk::ShaderStageFlags NativeShaderStage(ShaderType stage) {
|
||||
}
|
||||
}
|
||||
|
||||
static void BindNullStorageBuffer(RenderContext& context, BufferView& dst) {
|
||||
dst.buffer = context.GetBufferCache().GetBuffer(NULL_BUFFER_ID).Handle();
|
||||
dst.offset = 0;
|
||||
dst.range = 16;
|
||||
}
|
||||
|
||||
static Prospero::ImageType TextureType(const ShaderTextureResource& descriptor) {
|
||||
const auto type = descriptor.Type();
|
||||
return type == Prospero::ImageType::kCube ? Prospero::ImageType::kColor2DArray : type;
|
||||
@@ -134,31 +128,20 @@ static bool IsMultisampledTexture(Prospero::ImageType type) {
|
||||
type == Prospero::ImageType::kColor2DMsaaArray;
|
||||
}
|
||||
|
||||
static BufferView NativeStorageBuffer(RenderContext& context,
|
||||
const ShaderBufferResource& descriptor,
|
||||
const ShaderRecompiler::IR::BufferResource& resource,
|
||||
ShaderType stage, uint32_t slot, uint32_t& buffer_offset,
|
||||
BufferId id) {
|
||||
BufferView result;
|
||||
static vk::DescriptorBufferInfo
|
||||
NativeStorageBuffer(RenderContext& context, const PreparedBindings::BufferSource& source,
|
||||
const ShaderRecompiler::IR::BufferResource& resource, ShaderType stage,
|
||||
uint32_t slot, uint32_t& buffer_offset) {
|
||||
buffer_offset = 0;
|
||||
|
||||
const auto address = descriptor.Base48();
|
||||
const auto stride = descriptor.Stride();
|
||||
const auto records = descriptor.NumRecords();
|
||||
if (stride != 0 && records > UINT64_MAX / stride) {
|
||||
EXIT("storage buffer descriptor footprint overflow\n");
|
||||
const auto& [address, size, id] = source;
|
||||
if (address == 0 || size == 0) {
|
||||
return {context.GetBufferCache().GetBuffer(NULL_BUFFER_ID).Handle(), 0, 16};
|
||||
}
|
||||
const auto requested_size = stride != 0 ? static_cast<uint64_t>(stride) * records : records;
|
||||
if (address == 0 || requested_size == 0) {
|
||||
BindNullStorageBuffer(context, result);
|
||||
return result;
|
||||
}
|
||||
const auto size = Libs::LibKernel::Memory::ClampRangeSize(address, requested_size);
|
||||
const auto& graphics = context.GetGraphics();
|
||||
const auto alignment = graphics.StorageMinAlignment();
|
||||
if (alignment == 0 ||
|
||||
size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange) {
|
||||
EXIT("storage buffer range or device alignment is unsupported\n");
|
||||
if (size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange) {
|
||||
EXIT("storage buffer range is unsupported\n");
|
||||
}
|
||||
auto [buffer, offset] = context.GetBufferCache().ObtainBuffer(address, size, resource.written,
|
||||
resource.formatted, id);
|
||||
@@ -169,9 +152,7 @@ static BufferView NativeStorageBuffer(RenderContext&
|
||||
EXIT("storage buffer offset adjustment is unsupported\n");
|
||||
}
|
||||
buffer_offset = static_cast<uint32_t>(adjustment);
|
||||
result.buffer = buffer->Handle();
|
||||
result.offset = aligned_offset;
|
||||
result.range = static_cast<vk::DeviceSize>(size + adjustment);
|
||||
const vk::DescriptorBufferInfo result {buffer->Handle(), aligned_offset, size + adjustment};
|
||||
if (resource.formatted && resource.written) {
|
||||
context.GetTextureCache().InvalidateMemoryFromGPU(address, size);
|
||||
}
|
||||
@@ -820,13 +801,14 @@ static vk::Sampler NativeSampler(RenderContext& context,
|
||||
return context.GetSamplerCache().GetSampler(descriptor);
|
||||
}
|
||||
|
||||
static BufferView NativeUpload(RenderContext& context, std::span<const uint32_t> data) {
|
||||
static vk::DescriptorBufferInfo NativeUpload(RenderContext& context,
|
||||
std::span<const uint32_t> data) {
|
||||
EXIT_IF(data.empty());
|
||||
auto& command_buffer = context.GetCommandScheduler().Current();
|
||||
EXIT_IF(command_buffer.IsInvalid());
|
||||
auto& buffer = context.GetBufferCache().GetUtilityBuffer(MemoryUsage::Stream);
|
||||
const auto offset = buffer.Copy(data.data(), data.size_bytes(), 256);
|
||||
return {.buffer = buffer.Handle(), .offset = offset, .range = data.size_bytes()};
|
||||
return {buffer.Handle(), offset, data.size_bytes()};
|
||||
}
|
||||
|
||||
void RenderExecutor::TrackImageBinding(ImageId id) {
|
||||
@@ -872,17 +854,15 @@ PreparedBindings RenderExecutor::PrepareBindings(const ShaderStageRuntime& runti
|
||||
PreparedBindings prepared;
|
||||
prepared.program = runtime.program;
|
||||
prepared.snapshot = &runtime.resources;
|
||||
auto& descriptors = prepared.resources;
|
||||
descriptors.buffers.reserve(program.info.buffers.size());
|
||||
descriptors.images.reserve(program.info.images.size());
|
||||
prepared.images.reserve(program.info.images.size());
|
||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||
auto binding = ResolveTexture(program.info.images[i], snapshot.images[i]);
|
||||
BindImage(binding.image_id, binding.desc.type == TextureCache::BindingType::Storage);
|
||||
descriptors.images.push_back(binding);
|
||||
prepared.images.push_back(std::move(binding));
|
||||
}
|
||||
descriptors.samplers.reserve(program.info.samplers.size());
|
||||
prepared.samplers.reserve(program.info.samplers.size());
|
||||
for (uint32_t i = 0; i < program.info.samplers.size(); i++) {
|
||||
descriptors.samplers.push_back(NativeSampler(m_context, program, i, snapshot.samplers[i]));
|
||||
prepared.samplers.push_back(NativeSampler(m_context, program, i, snapshot.samplers[i]));
|
||||
}
|
||||
prepared.shader_data.reserve(program.bindings.ShaderDataDwords());
|
||||
for (const auto reg: program.bindings.user_data_registers) {
|
||||
@@ -891,7 +871,7 @@ PreparedBindings RenderExecutor::PrepareBindings(const ShaderStageRuntime& runti
|
||||
prepared.shader_data.resize(program.bindings.ShaderDataDwords());
|
||||
if (ShaderRecompiler::IR::FindBinding(
|
||||
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) {
|
||||
descriptors.gds.buffer = m_context.GetBufferCache().GetGdsBuffer()->Handle();
|
||||
prepared.gds.buffer = m_context.GetBufferCache().GetGdsBuffer()->Handle();
|
||||
}
|
||||
return prepared;
|
||||
}
|
||||
@@ -910,16 +890,15 @@ void RenderExecutor::FindBuffers(PreparedBindings& prepared) {
|
||||
const auto address = descriptor.Base48();
|
||||
const auto stride = descriptor.Stride();
|
||||
const auto records = descriptor.NumRecords();
|
||||
EXIT_IF(stride != 0 && records > UINT64_MAX / stride);
|
||||
// The descriptor has a 14-bit stride and 32-bit record count, so the product fits u64.
|
||||
const auto requested_size = stride != 0 ? static_cast<uint64_t>(stride) * records : records;
|
||||
if (address == 0 || requested_size == 0) {
|
||||
prepared.buffer_sources.emplace_back(descriptor, BufferId {});
|
||||
prepared.buffer_sources.push_back({});
|
||||
continue;
|
||||
}
|
||||
const auto size = Libs::LibKernel::Memory::ClampRangeSize(address, requested_size);
|
||||
prepared.buffer_sources.emplace_back(descriptor, cache.FindBuffer(address, size));
|
||||
prepared.buffer_sources.push_back({address, size, cache.FindBuffer(address, size)});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RenderExecutor::RebindBuffers(PreparedBindings& prepared) {
|
||||
@@ -927,12 +906,11 @@ void RenderExecutor::RebindBuffers(PreparedBindings& prepared) {
|
||||
EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr);
|
||||
const auto& program = *prepared.program;
|
||||
const auto& snapshot = *prepared.snapshot;
|
||||
auto& resources = prepared.resources;
|
||||
const auto& layout = program.bindings;
|
||||
EXIT_IF(prepared.buffer_sources.size() != program.info.buffers.size());
|
||||
|
||||
resources.buffers.clear();
|
||||
resources.buffers.reserve(program.info.buffers.size());
|
||||
prepared.buffers.clear();
|
||||
prepared.buffers.reserve(program.info.buffers.size());
|
||||
EXIT_IF(prepared.shader_data.size() != layout.ShaderDataDwords());
|
||||
std::fill(prepared.shader_data.begin() + layout.memory_offset_dword,
|
||||
prepared.shader_data.end(), 0);
|
||||
@@ -942,20 +920,19 @@ void RenderExecutor::RebindBuffers(PreparedBindings& prepared) {
|
||||
prepared.shader_data[dword] |= offset << shift;
|
||||
};
|
||||
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
||||
const auto& [descriptor, buffer_id] = prepared.buffer_sources[i];
|
||||
uint32_t buffer_offset = 0;
|
||||
resources.buffers.push_back(NativeStorageBuffer(m_context, descriptor,
|
||||
program.info.buffers[i], program.stage, i,
|
||||
buffer_offset, buffer_id));
|
||||
prepared.buffers.push_back(NativeStorageBuffer(m_context, prepared.buffer_sources[i],
|
||||
program.info.buffers[i], program.stage, i,
|
||||
buffer_offset));
|
||||
pack_memory_offset(i, buffer_offset);
|
||||
}
|
||||
if (ShaderRecompiler::IR::FindBinding(
|
||||
layout, ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) != nullptr) {
|
||||
resources.flattened_srt = NativeUpload(m_context, snapshot.flattened_srt);
|
||||
prepared.flattened_srt = NativeUpload(m_context, snapshot.flattened_srt);
|
||||
}
|
||||
if (ShaderRecompiler::IR::FindBinding(
|
||||
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::ShaderData) != nullptr) {
|
||||
resources.shader_data = NativeUpload(m_context, prepared.shader_data);
|
||||
prepared.shader_data_buffer = NativeUpload(m_context, prepared.shader_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -964,7 +941,7 @@ void RenderExecutor::RebindImages(PreparedBindings& prepared) {
|
||||
EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr);
|
||||
const auto& program = *prepared.program;
|
||||
const auto& snapshot = *prepared.snapshot;
|
||||
auto& images = prepared.resources.images;
|
||||
auto& images = prepared.images;
|
||||
EXIT_IF(images.size() != program.info.images.size());
|
||||
auto& texture_cache = m_context.GetTextureCache();
|
||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||
@@ -1075,7 +1052,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
||||
|
||||
for (auto* prepared: prepared_bindings) {
|
||||
const auto& program = *prepared->program;
|
||||
auto& descriptors = prepared->resources;
|
||||
auto& descriptors = *prepared;
|
||||
const auto shader_stage = NativeShaderStage(program.stage);
|
||||
const auto shader_stages = ShaderPipelineStages(shader_stage);
|
||||
if (descriptors.gds.buffer != nullptr) {
|
||||
@@ -1165,7 +1142,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
||||
for (const auto resource: binding.resources) {
|
||||
const auto& view = descriptors.buffers.at(resource);
|
||||
EXIT_IF(view.buffer == nullptr);
|
||||
m_descriptor_buffers.emplace_back(view.buffer, view.offset, view.range);
|
||||
m_descriptor_buffers.push_back(view);
|
||||
}
|
||||
break;
|
||||
case BindingKind::BdaPagetable:
|
||||
@@ -1181,14 +1158,14 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
||||
case BindingKind::FlattenedSrt:
|
||||
case BindingKind::ShaderData:
|
||||
case BindingKind::Gds: {
|
||||
const BufferView* view = &descriptors.gds;
|
||||
const vk::DescriptorBufferInfo* view = &descriptors.gds;
|
||||
if (binding.kind == BindingKind::FlattenedSrt) {
|
||||
view = &descriptors.flattened_srt;
|
||||
} else if (binding.kind == BindingKind::ShaderData) {
|
||||
view = &descriptors.shader_data;
|
||||
view = &descriptors.shader_data_buffer;
|
||||
}
|
||||
EXIT_IF(view->buffer == nullptr);
|
||||
m_descriptor_buffers.emplace_back(view->buffer, view->offset, view->range);
|
||||
m_descriptor_buffers.push_back(*view);
|
||||
break;
|
||||
}
|
||||
case BindingKind::Samplers:
|
||||
|
||||
@@ -20,12 +20,6 @@ namespace ShaderRecompiler::IR {
|
||||
struct ResourceSnapshot;
|
||||
}
|
||||
|
||||
struct BufferView {
|
||||
vk::Buffer buffer = nullptr;
|
||||
vk::DeviceSize offset = 0;
|
||||
vk::DeviceSize range = VK_WHOLE_SIZE;
|
||||
};
|
||||
|
||||
struct TextureBinding {
|
||||
ImageId image_id;
|
||||
vk::ImageView image_view = nullptr;
|
||||
@@ -34,21 +28,25 @@ struct TextureBinding {
|
||||
std::vector<vk::ImageView> mip_views;
|
||||
};
|
||||
|
||||
struct NativeDescriptors {
|
||||
std::vector<BufferView> buffers;
|
||||
std::vector<TextureBinding> images;
|
||||
std::vector<vk::Sampler> samplers;
|
||||
BufferView gds;
|
||||
BufferView flattened_srt;
|
||||
BufferView shader_data;
|
||||
};
|
||||
|
||||
struct PreparedBindings {
|
||||
struct BufferSource {
|
||||
uint64_t address = 0;
|
||||
uint64_t size = 0;
|
||||
BufferId id;
|
||||
};
|
||||
|
||||
const ShaderRecompiler::IR::CompiledShaderInfo* program = nullptr;
|
||||
const ShaderRecompiler::IR::ResourceSnapshot* snapshot = nullptr;
|
||||
NativeDescriptors resources;
|
||||
std::vector<std::pair<ShaderBufferResource, BufferId>> buffer_sources;
|
||||
std::vector<uint32_t> shader_data;
|
||||
// Keep the resolved guest range through cache preparation; only the host buffer ID may
|
||||
// become stale and need resolving again when bindings are rebound.
|
||||
std::vector<BufferSource> buffer_sources;
|
||||
std::vector<vk::DescriptorBufferInfo> buffers;
|
||||
std::vector<TextureBinding> images;
|
||||
std::vector<vk::Sampler> samplers;
|
||||
vk::DescriptorBufferInfo gds {nullptr, 0, VK_WHOLE_SIZE};
|
||||
vk::DescriptorBufferInfo flattened_srt;
|
||||
vk::DescriptorBufferInfo shader_data_buffer;
|
||||
std::vector<uint32_t> shader_data;
|
||||
};
|
||||
|
||||
[[nodiscard]] vk::DescriptorType
|
||||
|
||||
@@ -343,7 +343,7 @@ struct PipelineCache::ProgramCache {
|
||||
input_info.stage = {.program = &permutation.program, .resources = std::move(resources)};
|
||||
permutation.program.bindings.AdvancePushData(push_data_cursor);
|
||||
|
||||
std::printf("Num compiled %u shaders\n", ++num_compiled);
|
||||
std::printf("Num compiled %" PRIu64 " shaders\n", next_shader_id);
|
||||
return permutation.handle;
|
||||
}
|
||||
|
||||
@@ -362,7 +362,6 @@ struct PipelineCache::ProgramCache {
|
||||
std::unordered_map<ProgramKey, SourceEntry, ProgramKeyHash> programs;
|
||||
ProgramKey lookup_key;
|
||||
vk::Device device;
|
||||
uint32_t num_compiled = 0;
|
||||
uint64_t next_shader_id = 0;
|
||||
};
|
||||
|
||||
@@ -602,7 +601,7 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other)
|
||||
return std::memcmp(this, &other, sizeof(*this)) == 0;
|
||||
}
|
||||
|
||||
PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
|
||||
PipelineCache::Pipeline& PipelineCache::CreateGraphicsPipeline(
|
||||
std::span<const RenderColorInfo> colors, const RenderDepthInfo& depth,
|
||||
const ShaderVertexInputInfo& vs_input_info, CommandBuffer& command,
|
||||
const ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology,
|
||||
@@ -619,47 +618,42 @@ PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
|
||||
Common::LockGuard lock(m_mutex);
|
||||
auto& ctx = command.GetRegisters();
|
||||
|
||||
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
for (uint32_t i = 0; i < color_count; i++) {
|
||||
color_mask[i] =
|
||||
(colors[i].image_id ? colors[i].export_mapping.ApplyMask(render_target_mask_slot(
|
||||
ctx.GetRenderTargetMask(), colors[i].target_slot))
|
||||
: 0);
|
||||
}
|
||||
const HW::ModeControl& mc = ctx.GetModeControl();
|
||||
|
||||
const auto vs_id = vertex_program.id;
|
||||
const auto ps_id = ps_active ? pixel_program.id : 0;
|
||||
|
||||
PipelineStaticParameters static_params {};
|
||||
|
||||
static_params.color_count = color_count;
|
||||
PipelineRenderingState rendering {};
|
||||
PipelineRenderingState rendering {};
|
||||
rendering.color_count = color_count;
|
||||
uint32_t attachment_samples = 0;
|
||||
for (uint32_t i = 0; i < color_count; i++) {
|
||||
EXIT_IF(!colors[i].image_id || colors[i].format == vk::Format::eUndefined);
|
||||
rendering.color_formats[i] = colors[i].format;
|
||||
EXIT_IF(!colors[i].image_id || colors[i].desc.view_info.format == vk::Format::eUndefined);
|
||||
static_params.color_mask[i] = colors[i].export_mapping.ApplyMask(
|
||||
render_target_mask_slot(ctx.GetRenderTargetMask(), colors[i].target_slot));
|
||||
rendering.color_formats[i] = colors[i].desc.view_info.format;
|
||||
if (attachment_samples == 0) {
|
||||
attachment_samples = colors[i].samples;
|
||||
} else if (attachment_samples != colors[i].samples) {
|
||||
attachment_samples = colors[i].desc.info.samples;
|
||||
} else if (attachment_samples != colors[i].desc.info.samples) {
|
||||
EXIT("mixed color attachment sample counts are unsupported: %u and %u\n",
|
||||
attachment_samples, colors[i].samples);
|
||||
attachment_samples, colors[i].desc.info.samples);
|
||||
}
|
||||
}
|
||||
const bool with_depth =
|
||||
depth.format != vk::Format::eUndefined && static_cast<bool>(depth.image_id);
|
||||
depth.desc.view_info.format != vk::Format::eUndefined && static_cast<bool>(depth.image_id);
|
||||
if (with_depth) {
|
||||
const auto aspects = ImageViewOps::DepthAspectMask(depth.format);
|
||||
rendering.depth_format =
|
||||
aspects & vk::ImageAspectFlagBits::eDepth ? depth.format : vk::Format::eUndefined;
|
||||
rendering.stencil_format =
|
||||
aspects & vk::ImageAspectFlagBits::eStencil ? depth.format : vk::Format::eUndefined;
|
||||
const auto aspects = ImageViewOps::DepthAspectMask(depth.desc.view_info.format);
|
||||
rendering.depth_format = aspects & vk::ImageAspectFlagBits::eDepth
|
||||
? depth.desc.view_info.format
|
||||
: vk::Format::eUndefined;
|
||||
rendering.stencil_format = aspects & vk::ImageAspectFlagBits::eStencil
|
||||
? depth.desc.view_info.format
|
||||
: vk::Format::eUndefined;
|
||||
if (attachment_samples == 0) {
|
||||
attachment_samples = depth.samples;
|
||||
} else if (attachment_samples != depth.samples) {
|
||||
attachment_samples = depth.desc.info.samples;
|
||||
} else if (attachment_samples != depth.desc.info.samples) {
|
||||
EXIT("mixed color/depth sample counts are unsupported: %u and %u\n", attachment_samples,
|
||||
depth.samples);
|
||||
depth.desc.info.samples);
|
||||
}
|
||||
}
|
||||
if (color_count == 0 && !with_depth) {
|
||||
@@ -689,16 +683,12 @@ PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
|
||||
if (static_params.sample_shading_enable && !m_graphics.sample_rate_shading_enabled) {
|
||||
EXIT("Pipeline: sample-rate shading is required but unsupported by the host\n");
|
||||
}
|
||||
static_params.with_depth = with_depth;
|
||||
static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable;
|
||||
static_params.depth_min_bounds = depth.depth_min_bounds;
|
||||
static_params.depth_max_bounds = depth.depth_max_bounds;
|
||||
static_params.stencil_test_enable = depth.stencil_test_enable;
|
||||
static_params.stencil_front = depth.stencil_static_front;
|
||||
static_params.stencil_back = depth.stencil_static_back;
|
||||
for (uint32_t i = 0; i < RENDER_COLOR_ATTACHMENTS_MAX; i++) {
|
||||
static_params.color_mask[i] = color_mask[i];
|
||||
}
|
||||
const bool rect_list = topology == vk::PrimitiveTopology::ePatchList;
|
||||
static_params.cull_back = !rect_list && mc.cull_back;
|
||||
static_params.cull_front = !rect_list && mc.cull_front;
|
||||
@@ -763,13 +753,11 @@ PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
|
||||
static_cast<void*>(pixel_program.module));
|
||||
}
|
||||
|
||||
auto cached = std::make_unique<GraphicsPipeline>();
|
||||
cached->ps_shader_id = ps_id;
|
||||
cached->vs_shader_id = vs_id;
|
||||
auto cached = std::make_unique<Pipeline>();
|
||||
LogPipelineTrace("CreatePipelineInternal begin", vs_id, ps_id);
|
||||
CreatePipelineInternal(m_graphics, *cached, rendering, key.vertex_input, vs_input_info,
|
||||
vertex_program.module, ps_input_info, pixel_program.module,
|
||||
static_params, m_driver_cache);
|
||||
vertex_program, ps_input_info, pixel_program, static_params,
|
||||
m_driver_cache);
|
||||
LogPipelineTrace("CreatePipelineInternal done", vs_id, ps_id);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cached->pipeline == nullptr);
|
||||
@@ -781,19 +769,17 @@ PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline(
|
||||
return *iter->second;
|
||||
}
|
||||
|
||||
PipelineCache::ComputePipeline&
|
||||
PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info,
|
||||
const ShaderProgram& compute_program) {
|
||||
PipelineCache::Pipeline&
|
||||
PipelineCache::CreateComputePipeline(const ShaderComputeInputInfo& input_info,
|
||||
const ShaderProgram& compute_program) {
|
||||
KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100);
|
||||
|
||||
EXIT_IF(!compute_program);
|
||||
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
ComputePipelineKey key {};
|
||||
key.cs_shader_id = compute_program.id;
|
||||
|
||||
if (auto iter = m_compute_pipelines.find(key); iter != m_compute_pipelines.end()) {
|
||||
if (auto iter = m_compute_pipelines.find(compute_program.id);
|
||||
iter != m_compute_pipelines.end()) {
|
||||
return *iter->second;
|
||||
}
|
||||
|
||||
@@ -801,14 +787,13 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info,
|
||||
ShaderDbgDumpInputInfo(input_info);
|
||||
}
|
||||
|
||||
auto cached = std::make_unique<ComputePipeline>();
|
||||
cached->cs_shader_id = compute_program.id;
|
||||
auto cached = std::make_unique<Pipeline>();
|
||||
CreatePipelineInternal(m_graphics, *cached, input_info, compute_program.module, m_driver_cache);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cached->pipeline == nullptr);
|
||||
EXIT_NOT_IMPLEMENTED(cached->pipeline_layout == nullptr);
|
||||
|
||||
auto [iter, inserted] = m_compute_pipelines.emplace(std::move(key), std::move(cached));
|
||||
auto [iter, inserted] = m_compute_pipelines.emplace(compute_program.id, std::move(cached));
|
||||
EXIT_IF(!inserted);
|
||||
|
||||
return *iter->second;
|
||||
|
||||
@@ -39,14 +39,12 @@ struct PipelineStaticParameters {
|
||||
bool primitive_restart_enable = false;
|
||||
uint32_t samples = 1;
|
||||
bool sample_shading_enable = false;
|
||||
bool with_depth = false;
|
||||
bool depth_bounds_test_enable = false;
|
||||
float depth_min_bounds = 0.0f;
|
||||
float depth_max_bounds = 0.0f;
|
||||
bool stencil_test_enable = false;
|
||||
PipelineStencilStaticState stencil_front;
|
||||
PipelineStencilStaticState stencil_back;
|
||||
uint32_t color_count = 1;
|
||||
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
bool cull_front = false;
|
||||
bool cull_back = false;
|
||||
@@ -69,7 +67,7 @@ struct PipelineStaticParameters {
|
||||
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) == 166);
|
||||
static_assert(sizeof(PipelineStaticParameters) == 161);
|
||||
|
||||
struct PipelineRenderingState {
|
||||
std::array<vk::Format, RENDER_COLOR_ATTACHMENTS_MAX> color_formats {};
|
||||
@@ -121,15 +119,6 @@ public:
|
||||
bool uses_push_descriptors = false;
|
||||
};
|
||||
|
||||
struct GraphicsPipeline: Pipeline {
|
||||
uint64_t vs_shader_id = 0;
|
||||
uint64_t ps_shader_id = 0;
|
||||
};
|
||||
|
||||
struct ComputePipeline: Pipeline {
|
||||
uint64_t cs_shader_id = 0;
|
||||
};
|
||||
|
||||
struct GraphicsPrograms {
|
||||
ShaderProgram vertex;
|
||||
ShaderProgram pixel;
|
||||
@@ -146,14 +135,14 @@ public:
|
||||
const HW::ShaderRegisters& sh,
|
||||
ShaderComputeInputInfo& input_info);
|
||||
|
||||
GraphicsPipeline&
|
||||
Pipeline&
|
||||
CreateGraphicsPipeline(std::span<const RenderColorInfo> colors, const RenderDepthInfo& depth,
|
||||
const ShaderVertexInputInfo& vs_input_info, CommandBuffer& command,
|
||||
const ShaderPixelInputInfo* ps_input_info,
|
||||
vk::PrimitiveTopology topology, bool primitive_restart_enable,
|
||||
const ShaderProgram& vertex_program, const ShaderProgram& pixel_program);
|
||||
ComputePipeline& CreateComputePipeline(ShaderComputeInputInfo& input_info,
|
||||
const ShaderProgram& compute_program);
|
||||
Pipeline& CreateComputePipeline(const ShaderComputeInputInfo& input_info,
|
||||
const ShaderProgram& compute_program);
|
||||
|
||||
private:
|
||||
struct ProgramCache;
|
||||
@@ -172,14 +161,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
struct ComputePipelineKey {
|
||||
uint64_t cs_shader_id = 0;
|
||||
|
||||
bool operator==(const ComputePipelineKey& other) const {
|
||||
return cs_shader_id == other.cs_shader_id;
|
||||
}
|
||||
};
|
||||
|
||||
struct PipelineKeyHash {
|
||||
static void Mix(std::size_t& hash, std::size_t value) {
|
||||
hash ^= value + static_cast<std::size_t>(0x9e3779b97f4a7c15ull) + (hash << 6u) +
|
||||
@@ -224,23 +205,13 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
struct ComputePipelineKeyHash {
|
||||
std::size_t operator()(const ComputePipelineKey& key) const {
|
||||
std::size_t hash = 0;
|
||||
PipelineKeyHash::Mix(hash, key.cs_shader_id);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
GraphicContext& m_graphics;
|
||||
std::unique_ptr<ProgramCache> m_program_cache;
|
||||
vk::PipelineCache m_driver_cache = nullptr;
|
||||
std::filesystem::path m_driver_cache_path;
|
||||
std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>,
|
||||
GraphicsPipelineKeyHash>
|
||||
m_graphics_pipelines;
|
||||
std::unordered_map<ComputePipelineKey, std::unique_ptr<ComputePipeline>, ComputePipelineKeyHash>
|
||||
m_compute_pipelines;
|
||||
std::unordered_map<GraphicsPipelineKey, std::unique_ptr<Pipeline>, GraphicsPipelineKeyHash>
|
||||
m_graphics_pipelines;
|
||||
std::unordered_map<uint64_t, std::unique_ptr<Pipeline>> m_compute_pipelines;
|
||||
Common::Mutex m_mutex;
|
||||
|
||||
void InitializeDriverCache();
|
||||
@@ -248,12 +219,12 @@ private:
|
||||
|
||||
void LogPipelineTrace(const char* phase, uint64_t vertex_program_id, uint64_t pixel_program_id);
|
||||
void CreatePipelineInternal(
|
||||
GraphicContext& graphics, PipelineCache::GraphicsPipeline& pipeline,
|
||||
GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
||||
const PipelineRenderingState& rendering, const PipelineVertexInputState& vertex_input,
|
||||
const ShaderVertexInputInfo& vs_input_info, vk::ShaderModule vertex_module,
|
||||
const ShaderPixelInputInfo* ps_input_info, vk::ShaderModule pixel_module,
|
||||
const ShaderVertexInputInfo& vs_input_info, const ShaderProgram& vertex_program,
|
||||
const ShaderPixelInputInfo* ps_input_info, const ShaderProgram& pixel_program,
|
||||
const PipelineStaticParameters& static_params, vk::PipelineCache driver_cache);
|
||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipeline& pipeline,
|
||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
||||
const ShaderComputeInputInfo& input_info,
|
||||
vk::ShaderModule compute_module, vk::PipelineCache driver_cache);
|
||||
|
||||
|
||||
@@ -67,11 +67,12 @@ vk::BufferMemoryBarrier MakeGdsDependency(vk::Buffer buffer) {
|
||||
return barrier;
|
||||
}
|
||||
|
||||
std::vector<ShaderBufferWriteRange>
|
||||
CollectShaderBufferWrites(const ShaderRecompiler::IR::CompiledShaderInfo& program,
|
||||
const ShaderRecompiler::IR::ResourceSnapshot& resources) {
|
||||
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) {
|
||||
EXIT_IF(!runtime);
|
||||
const auto& program = *runtime.program;
|
||||
const auto& resources = runtime.resources;
|
||||
EXIT_IF(resources.buffers.size() != program.info.buffers.size());
|
||||
std::vector<ShaderBufferWriteRange> writes;
|
||||
bool has_writes = false;
|
||||
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
||||
if (!program.info.buffers[i].written) {
|
||||
continue;
|
||||
@@ -80,23 +81,11 @@ CollectShaderBufferWrites(const ShaderRecompiler::IR::CompiledShaderInfo& progra
|
||||
EXIT_IF(value.dword_count < 4);
|
||||
ShaderBufferResource descriptor;
|
||||
std::memcpy(descriptor.fields, value.dwords.data(), sizeof(descriptor.fields));
|
||||
const auto address = descriptor.Base48();
|
||||
const auto records = static_cast<uint64_t>(descriptor.NumRecords());
|
||||
const auto stride = static_cast<uint64_t>(descriptor.Stride());
|
||||
if (stride != 0 && records > UINT64_MAX / stride) {
|
||||
EXIT("shader resource barrier buffer footprint overflow\n");
|
||||
}
|
||||
const auto size = stride == 0 ? records : stride * records;
|
||||
if (address != 0 && size != 0) {
|
||||
writes.push_back({address, size});
|
||||
}
|
||||
// A zero stride means byte addressing. For either addressing mode a nonzero record
|
||||
// count is exactly the condition for a nonempty descriptor range.
|
||||
has_writes |= descriptor.Base48() != 0 && descriptor.NumRecords() != 0;
|
||||
}
|
||||
return writes;
|
||||
}
|
||||
|
||||
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) {
|
||||
EXIT_IF(!runtime);
|
||||
return !CollectShaderBufferWrites(*runtime.program, runtime.resources).empty();
|
||||
return has_writes;
|
||||
}
|
||||
|
||||
void ShaderAccessBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages) {
|
||||
|
||||
@@ -4,27 +4,15 @@
|
||||
#include "graphics/host_gpu/graphicContext.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
struct ShaderStageRuntime;
|
||||
|
||||
struct ShaderBufferWriteRange {
|
||||
uint64_t address = 0;
|
||||
uint64_t size = 0;
|
||||
|
||||
bool operator==(const ShaderBufferWriteRange& other) const = default;
|
||||
};
|
||||
|
||||
vk::PipelineStageFlags ShaderPipelineStages(vk::ShaderStageFlags stages);
|
||||
VulkanMemoryBarrier MakeShaderAccessDependency();
|
||||
VulkanMemoryBarrier MakeShaderWriteHazardDependency();
|
||||
VulkanMemoryBarrier MakeShaderWriteDependency();
|
||||
vk::BufferMemoryBarrier MakeGdsDependency(vk::Buffer buffer);
|
||||
std::vector<ShaderBufferWriteRange>
|
||||
CollectShaderBufferWrites(const ShaderRecompiler::IR::CompiledShaderInfo& program,
|
||||
const ShaderRecompiler::IR::ResourceSnapshot& resources);
|
||||
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime);
|
||||
void ShaderAccessBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages);
|
||||
void ShaderWriteHazardBarrier(vk::CommandBuffer vk_buffer,
|
||||
|
||||
@@ -419,13 +419,15 @@ static void CreateDescriptorLayout(GraphicContext& graphics, PipelineCache::Pipe
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
void CreatePipelineInternal(
|
||||
GraphicContext& graphics, PipelineCache::GraphicsPipeline& pipeline,
|
||||
GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
||||
const PipelineRenderingState& rendering, const PipelineVertexInputState& vertex_input,
|
||||
const ShaderVertexInputInfo& vs_input_info, vk::ShaderModule vertex_module,
|
||||
const ShaderPixelInputInfo* ps_input_info, vk::ShaderModule pixel_module,
|
||||
const ShaderVertexInputInfo& vs_input_info, const ShaderProgram& vertex_program,
|
||||
const ShaderPixelInputInfo* ps_input_info, const ShaderProgram& pixel_program,
|
||||
const PipelineStaticParameters& static_params, vk::PipelineCache driver_cache) {
|
||||
const bool ps_active = ps_input_info != nullptr;
|
||||
EXIT_IF(vertex_module == nullptr || (ps_active && pixel_module == nullptr));
|
||||
EXIT_IF(!vertex_program || (ps_active && !pixel_program));
|
||||
const bool with_depth = rendering.depth_format != vk::Format::eUndefined ||
|
||||
rendering.stencil_format != vk::Format::eUndefined;
|
||||
EXIT_IF(!vs_input_info.stage);
|
||||
const bool mesh = vs_input_info.stage.program->stage == ShaderType::Mesh;
|
||||
EXIT_NOT_IMPLEMENTED(mesh && !graphics.mesh_shader_enabled);
|
||||
@@ -468,12 +470,12 @@ void CreatePipelineInternal(
|
||||
|
||||
vk::PipelineShaderStageCreateInfo vert_shader_stage_info {};
|
||||
vert_shader_stage_info.stage = vertex_stage;
|
||||
vert_shader_stage_info.module = vertex_module;
|
||||
vert_shader_stage_info.module = vertex_program.module;
|
||||
vert_shader_stage_info.pName = "main";
|
||||
|
||||
vk::PipelineShaderStageCreateInfo frag_shader_stage_info {};
|
||||
frag_shader_stage_info.stage = vk::ShaderStageFlagBits::eFragment;
|
||||
frag_shader_stage_info.module = pixel_module;
|
||||
frag_shader_stage_info.module = pixel_program.module;
|
||||
frag_shader_stage_info.pName = "main";
|
||||
|
||||
vk::PipelineShaderStageCreateInfo tess_control_shader_stage_info {};
|
||||
@@ -605,7 +607,7 @@ void CreatePipelineInternal(
|
||||
multisampling.minSampleShading = 1.0f;
|
||||
|
||||
vk::PipelineColorBlendAttachmentState color_blend_attachment[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
for (uint32_t i = 0; i < static_params.color_count; i++) {
|
||||
for (uint32_t i = 0; i < rendering.color_count; i++) {
|
||||
EXIT_NOT_IMPLEMENTED((static_params.color_mask[i] & ~0x0fu) != 0);
|
||||
color_blend_attachment[i].colorWriteMask =
|
||||
vk::ColorComponentFlags {static_params.color_mask[i]};
|
||||
@@ -629,12 +631,12 @@ void CreatePipelineInternal(
|
||||
}
|
||||
|
||||
vk::Bool32 color_write_enable[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
for (uint32_t i = 0; i < static_params.color_count; i++) {
|
||||
for (uint32_t i = 0; i < rendering.color_count; i++) {
|
||||
color_write_enable[i] = VK_TRUE;
|
||||
}
|
||||
|
||||
vk::PipelineColorWriteCreateInfoEXT color_write {};
|
||||
color_write.attachmentCount = static_params.color_count;
|
||||
color_write.attachmentCount = rendering.color_count;
|
||||
color_write.pColorWriteEnables = color_write_enable;
|
||||
|
||||
vk::PipelineColorBlendStateCreateInfo color_blending {};
|
||||
@@ -644,7 +646,7 @@ void CreatePipelineInternal(
|
||||
color_blending.pNext = &color_write;
|
||||
#endif
|
||||
color_blending.logicOp = vk::LogicOp::eCopy;
|
||||
color_blending.attachmentCount = static_params.color_count;
|
||||
color_blending.attachmentCount = rendering.color_count;
|
||||
color_blending.pAttachments = color_blend_attachment;
|
||||
|
||||
std::vector<vk::DescriptorSetLayoutBinding> descriptor_bindings;
|
||||
@@ -670,7 +672,7 @@ void CreatePipelineInternal(
|
||||
if (graphics_debug_dump_enabled()) {
|
||||
LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=%" PRIu64 " PS=%" PRIu64
|
||||
" set_layouts=1 push_constants=%" PRIu32 "\n",
|
||||
pipeline.vs_shader_id, pipeline.ps_shader_id, 1u);
|
||||
vertex_program.id, ps_active ? pixel_program.id : 0, 1u);
|
||||
}
|
||||
result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr,
|
||||
&pipeline.pipeline_layout);
|
||||
@@ -722,7 +724,7 @@ void CreatePipelineInternal(
|
||||
auto dynamic_states_count =
|
||||
static_cast<uint32_t>(sizeof(dynamic_states) / sizeof(dynamic_states[0]));
|
||||
#if !defined(__APPLE__)
|
||||
if (static_params.color_count == 0) {
|
||||
if (rendering.color_count == 0) {
|
||||
dynamic_states_count--;
|
||||
}
|
||||
#endif
|
||||
@@ -748,8 +750,7 @@ void CreatePipelineInternal(
|
||||
pipeline_info.pViewportState = &viewport_state;
|
||||
pipeline_info.pRasterizationState = &rasterizer;
|
||||
pipeline_info.pMultisampleState = &multisampling;
|
||||
pipeline_info.pDepthStencilState =
|
||||
(static_params.with_depth ? &depth_stencil_info : nullptr);
|
||||
pipeline_info.pDepthStencilState = (with_depth ? &depth_stencil_info : nullptr);
|
||||
pipeline_info.pColorBlendState = &color_blending;
|
||||
pipeline_info.pDynamicState = &dynamic_state;
|
||||
pipeline_info.layout = pipeline.pipeline_layout;
|
||||
@@ -761,10 +762,10 @@ void CreatePipelineInternal(
|
||||
LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=%" PRIu64 " PS=%" PRIu64
|
||||
" topology=%" PRIu32 " color_mask=0x%08" PRIx32
|
||||
" depth=%s blend=%s dyn_states=%" PRIu32 "\n",
|
||||
pipeline.vs_shader_id, pipeline.ps_shader_id,
|
||||
vertex_program.id, ps_active ? pixel_program.id : 0,
|
||||
static_cast<uint32_t>(static_params.topology), static_params.color_mask[0],
|
||||
(static_params.with_depth ? "true" : "false"),
|
||||
(static_params.blend_enable[0] ? "true" : "false"), dynamic_states_count);
|
||||
(with_depth ? "true" : "false"), (static_params.blend_enable[0] ? "true" : "false"),
|
||||
dynamic_states_count);
|
||||
}
|
||||
result = graphics.device.createGraphicsPipelines(driver_cache, 1, &pipeline_info, nullptr,
|
||||
&pipeline.pipeline);
|
||||
@@ -785,9 +786,9 @@ void CreatePipelineInternal(
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipeline& pipeline,
|
||||
void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline,
|
||||
const ShaderComputeInputInfo& input_info,
|
||||
vk::ShaderModule compute_module, vk::PipelineCache driver_cache) {
|
||||
vk::ShaderModule compute_module, vk::PipelineCache driver_cache) {
|
||||
EXIT_IF(compute_module == nullptr);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo comp_shader_stage_info {};
|
||||
|
||||
Reference in New Issue
Block a user