render: simplify command and resource ownership

This commit is contained in:
nmzik
2026-09-06 04:05:35 +04:00
parent 13ad9f510d
commit dda628ca81
18 changed files with 386 additions and 538 deletions
@@ -75,8 +75,8 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer&
mask = 0x0f;
}
r.target_slot = rt_slot;
r.export_mapping = {};
r = {};
r.target_slot = rt_slot;
if (rt.base.addr == 0 || mask == 0) {
if (graphics_debug_dump_enabled()) {
@@ -91,23 +91,6 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer&
}
}
// No color output
r.type = RenderColorType::NoColorOutput;
r.desc = {};
r.base_addr = 0;
r.image_id = {};
r.image_view = nullptr;
r.format = vk::Format::eUndefined;
r.extent = {};
r.base_mip_level = 0;
r.base_array_layer = 0;
r.buffer_size = 0;
r.samples = 1;
r.export_mapping = {};
r.color_clear_enable = false;
r.metadata_clear_supported = false;
r.metadata_fixed_clear_supported = false;
r.color_clear_value = {};
return;
}
const auto samples = render_sample_count(rt.attrib.num_fragments);
@@ -158,7 +141,6 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer&
rt.view.base_array_slice_index, rt.view.last_array_slice_index,
render_target_slice_offset);
}
r.base_array_layer = view.base_layer;
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);
@@ -179,9 +161,6 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer&
// Nonlinear clear values are still stored as normalized components.
// Fast color clears are metadata driven and must be handled explicitly when
// that metadata path is implemented; render-pass load must preserve contents.
r.color_clear_enable = false;
r.color_clear_value = {};
uint32_t width = 0;
uint32_t height = 0;
uint32_t pitch = 0;
@@ -246,9 +225,7 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer&
rt.attrib3.dimension, rt.attrib3.depth, view.base_layer, view.image_layers);
}
if (tile) {
if (volume) {
pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode);
} else if (texture_tile) {
if (volume || texture_tile) {
pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode);
} else {
pitch = TileGetRenderTargetPitch(width, bytes_per_element, rt.attrib.num_fragments);
@@ -397,17 +374,10 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer&
desc.view_info.usage = vk::ImageUsageFlagBits::eColorAttachment;
auto& texture_cache = m_context.GetTextureCache();
r.desc = std::move(desc);
r.guest_mip_level = rt.view.current_mip_level;
r.guest_array_layer = view.base_layer;
r.image_id = texture_cache.FindImage(r.desc, exact_format);
r.type = RenderColorType::RenderTexture;
r.base_addr = rt.base.addr;
r.image_view = nullptr;
r.format = r.desc.view_info.format;
r.extent = view_extent;
r.base_mip_level = rt.view.current_mip_level;
r.buffer_size = backing_size;
r.samples = samples;
r.export_mapping = target_format.export_mapping;
r.color_clear_enable = false;
ResolveDccClearInfo(r, target_format.format, has_dcc, rt.clear_word0.word0);
BindRenderTarget(r.image_id);
}
@@ -6,33 +6,27 @@
#include "graphics/host_gpu/renderer/renderTarget.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <algorithm>
#include <cstdint>
namespace Libs::Graphics {
enum class RenderColorType {
NoColorOutput,
RenderTexture,
};
struct RenderColorInfo {
RenderColorType type = RenderColorType::NoColorOutput;
// Discovery keeps guest image information but can remap the view into a larger cache image.
TextureCache::ImageDesc desc;
ImageId image_id;
vk::ImageView image_view = nullptr;
vk::Format format = vk::Format::eUndefined;
vk::Extent2D extent = {};
uint32_t base_mip_level = 0;
uint32_t base_array_layer = 0;
uint64_t base_addr = 0;
uint64_t buffer_size = 0;
uint32_t target_slot = 0;
uint32_t samples = 1;
uint32_t guest_mip_level = 0;
uint32_t guest_array_layer = 0;
Prospero::ColorComponentMapping export_mapping;
bool color_clear_enable = false;
bool metadata_clear_supported = false;
bool metadata_fixed_clear_supported = false;
vk::ClearColorValue color_clear_value {};
[[nodiscard]] vk::Extent2D Extent() const {
return {std::max(desc.info.extent.width >> guest_mip_level, 1u),
std::max(desc.info.extent.height >> guest_mip_level, 1u)};
}
};
} // namespace Libs::Graphics
@@ -148,14 +148,10 @@ void CommandScheduler::Begin(HW::Context& registers, HW::UserConfig& user_config
std::lock_guard lock(m_operation_mutex);
EXIT_IF(m_operation_state != OperationState::Open);
}
m_registers = &registers;
m_user_config = &user_config;
m_shaders = &shaders;
m_command.Bind(registers, user_config, shaders);
if (m_command.IsInvalid()) {
BeginNext();
} else {
BindCurrent();
}
}
@@ -346,11 +342,6 @@ CommandBuffer& CommandScheduler::Current() {
return m_command;
}
void CommandScheduler::BindCurrent() {
EXIT_IF(m_registers == nullptr || m_user_config == nullptr || m_shaders == nullptr);
m_command.Bind(*m_registers, *m_user_config, *m_shaders);
}
CommandBuffer& CommandScheduler::BeginCommand() {
EXIT_IF(!m_command.IsInvalid());
m_command.m_buffer = m_command_pool.Commit();
@@ -407,8 +398,7 @@ uint64_t CommandScheduler::Submit(SubmitInfo submit) {
}
void CommandScheduler::BeginNext() {
EXIT_IF(!m_command.IsInvalid());
BindCurrent();
CheckActive();
BeginCommand();
}
@@ -42,7 +42,7 @@ public:
void DeferPriorityOperation(Common::UniqueFunction<void>&& operation);
[[nodiscard]] static bool InDeferredOperation() noexcept;
[[nodiscard]] bool Active() const noexcept { return m_registers != nullptr; }
[[nodiscard]] bool Active() const noexcept { return m_command.m_registers != nullptr; }
void CheckActive() const;
CommandBuffer& Current();
[[nodiscard]] uint64_t CurrentTick() const noexcept { return m_master.CurrentTick(); }
@@ -80,7 +80,6 @@ private:
uint64_t tick = 0;
};
void BindCurrent();
void BeginNext();
void PopPendingOperations(bool refresh_gpu_tick);
void PriorityOperationsThread(std::stop_token stop);
@@ -99,9 +98,6 @@ private:
bool m_priority_active = false;
uint64_t m_priority_active_tick = 0;
OperationState m_operation_state = OperationState::Open;
HW::Context* m_registers = nullptr;
HW::UserConfig* m_user_config = nullptr;
HW::Shader* m_shaders = nullptr;
};
} // namespace Libs::Graphics
+3 -7
View File
@@ -402,7 +402,6 @@ static void ZCheck(const HW::DepthRenderTarget& z, const HW::DepthControl& dc,
EXIT_NOT_IMPLEMENTED(!z.z_info.HasValidTextureCompatibility());
EXIT_NOT_IMPLEMENTED(!z.stencil_info.HasValidTextureCompatibility());
if (z.z_info.format == Prospero::DepthFormat::kInvalid) {
EXIT_NOT_IMPLEMENTED(z.z_info.format != Prospero::DepthFormat::kInvalid);
EXIT_NOT_IMPLEMENTED(z.z_info.num_samples != 0);
EXIT_NOT_IMPLEMENTED(z.z_info.htile_acceleration != false);
EXIT_NOT_IMPLEMENTED(z.z_info.expclear_enabled != false);
@@ -424,14 +423,11 @@ static void ZCheck(const HW::DepthRenderTarget& z, const HW::DepthControl& dc,
EXIT_NOT_IMPLEMENTED(z.z_info.max_mip_level != 0);
}
if (z.stencil_info.format == Prospero::StencilFormat::kInvalid) {
EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false);
EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false);
} else {
if (z.stencil_info.format != Prospero::StencilFormat::kInvalid) {
EXIT_NOT_IMPLEMENTED(z.stencil_info.format != Prospero::StencilFormat::k8UInt);
EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false);
EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false);
}
EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false);
EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false);
if (z.z_info.format != Prospero::DepthFormat::kInvalid ||
z.stencil_info.format != Prospero::StencilFormat::kInvalid) {
@@ -203,8 +203,8 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer&
DepthFatal("unsupported depth/stencil format pair");
}
const auto ideal_format = DepthAttachmentFormat(*policy, has_stencil);
r.format = ResolveHostDepthAttachmentFormat(buffer, *policy, has_stencil, samples);
if (r.format == vk::Format::eUndefined) {
const auto format = ResolveHostDepthAttachmentFormat(buffer, *policy, has_stencil, samples);
if (format == vk::Format::eUndefined) {
DepthFatal("no host depth/stencil format supports required usage for %s",
VulkanToString(ideal_format).c_str());
}
@@ -234,16 +234,6 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer&
(has_htile && !GuestRange {z.htile_data_base_addr, htile_backing_size}.Valid())) {
DepthFatal("layered depth backing range is invalid");
}
r.htile = has_htile;
r.width = width;
r.height = height;
r.samples = samples;
r.depth_buffer_size = depth_backing_size;
r.depth_buffer_vaddr = z.z_read_base_addr;
r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0;
r.stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0;
r.htile_buffer_size = has_htile ? htile_backing_size : 0;
r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0;
r.depth_clear_enable = rc.depth_clear_enable;
r.depth_meta_clear_enable = false;
r.depth_load_clear_enable = r.depth_clear_enable;
@@ -294,18 +284,12 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer&
r.stencil_dynamic_back = r.stencil_dynamic_front;
}
}
r.vaddr_num = has_stencil ? 2 : 1;
r.vaddr[0] = r.depth_buffer_vaddr;
r.size[0] = r.depth_buffer_size;
if (has_stencil) {
r.vaddr[1] = r.stencil_buffer_vaddr;
r.size[1] = r.stencil_buffer_size;
}
TextureCache::ImageDesc desc {};
desc.type = TextureCache::BindingType::DepthTarget;
desc.info.data = {r.depth_buffer_vaddr, r.depth_buffer_size};
desc.info.stencil = {r.stencil_buffer_vaddr, r.stencil_buffer_size};
desc.info.pixel_format = r.format;
desc.info.data = {z.z_read_base_addr, depth_backing_size};
desc.info.stencil =
has_stencil ? GuestRange {z.stencil_read_base_addr, stencil_backing_size} : GuestRange {};
desc.info.pixel_format = format;
desc.info.guest_format = guest_format;
desc.info.type = Prospero::ImageType::kColor2D;
desc.info.extent = {width, height, 1};
@@ -314,15 +298,16 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer&
desc.info.bytes_per_block = bytes;
desc.info.samples = samples;
desc.info.tile_mode = Prospero::TileMode::kDepth;
desc.info.mip_layout[0] = {0, r.depth_buffer_size, pitch, height};
desc.info.metadata.range = {r.htile_buffer_vaddr, r.htile_buffer_size};
desc.info.mip_layout[0] = {0, depth_backing_size, pitch, height};
desc.info.metadata.range =
has_htile ? GuestRange {z.htile_data_base_addr, htile_backing_size} : GuestRange {};
desc.info.metadata.kind = has_htile ? ImageMetadataKind::Htile : ImageMetadataKind::None;
desc.info.metadata.stencil_compressed =
has_stencil && has_htile && !z.stencil_info.htile_stencil_disabled;
desc.view_info.format = r.format;
desc.view_info.format = format;
desc.view_info.type =
view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray;
desc.view_info.aspect = ImageViewOps::DepthAspectMask(r.format);
desc.view_info.aspect = ImageViewOps::DepthAspectMask(format);
desc.view_info.base_level = 0;
desc.view_info.level_count = 1;
desc.view_info.base_layer = view.base_layer;
@@ -331,11 +316,11 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer&
r.desc = std::move(desc);
auto& cache = m_context.GetTextureCache();
r.image_id = cache.FindImage(r.desc);
r.image_view = nullptr;
BindRenderTarget(r.image_id);
}
vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const {
const auto format = desc.view_info.format;
if (format == vk::Format::eUndefined) {
return {};
}
@@ -19,21 +19,8 @@ inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stenc
}
struct RenderDepthInfo {
// Discovery keeps guest image information but can remap the view into a larger cache image.
TextureCache::ImageDesc desc;
vk::Format format = vk::Format::eUndefined;
uint32_t width = 0;
uint32_t height = 0;
uint32_t samples = 1;
bool htile = false;
uint64_t depth_buffer_size = 0;
uint64_t depth_buffer_vaddr = 0;
uint64_t depth_tile_swizzle = 0;
uint64_t stencil_buffer_size = 0;
uint64_t stencil_buffer_vaddr = 0;
uint64_t stencil_tile_swizzle = 0;
uint64_t htile_buffer_size = 0;
uint64_t htile_buffer_vaddr = 0;
uint64_t htile_tile_swizzle = 0;
bool depth_clear_enable = false;
bool depth_load_clear_enable = false;
bool depth_meta_clear_enable = false;
@@ -52,10 +39,6 @@ struct RenderDepthInfo {
PipelineStencilDynamicState stencil_dynamic_front;
PipelineStencilDynamicState stencil_dynamic_back;
ImageId image_id;
vk::ImageView image_view = nullptr;
uint64_t vaddr[3] = {};
uint64_t size[3] = {};
int vaddr_num = 0;
[[nodiscard]] vk::ImageAspectFlags AttachmentWriteAspects() const;
};
@@ -65,7 +48,7 @@ inline bool depth_attachment_read_only(const RenderDepthInfo& depth) {
}
inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) {
const auto available = ImageViewOps::DepthAspectMask(depth.format);
const auto available = ImageViewOps::DepthAspectMask(depth.desc.view_info.format);
const auto writes = depth.AttachmentWriteAspects();
const bool has_depth = static_cast<bool>(available & vk::ImageAspectFlagBits::eDepth);
const bool has_stencil = static_cast<bool>(available & vk::ImageAspectFlagBits::eStencil);
@@ -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 {};
+63 -81
View File
@@ -109,12 +109,8 @@ static float ConvertPolygonOffsetConstantFactor(float guest_factor, const HW::Po
return std::ldexp(guest_factor, host_depth_bits + offset.neg_num_db_bits);
}
static const char* RenderColorTypeName(RenderColorType type) {
switch (type) {
case RenderColorType::NoColorOutput: return "NoColorOutput";
case RenderColorType::RenderTexture: return "RenderTexture";
default: return "Unknown";
}
static const char* RenderColorTypeName(const RenderColorInfo& color) {
return color.image_id ? "RenderTexture" : "NoColorOutput";
}
static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& color,
@@ -135,10 +131,12 @@ static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& col
"DrawFramebufferSkip[%u]: %s color=%s color_addr=0x%010" PRIx64 " color_size=0x%016" PRIx64
" color_image=%s depth_format=%s depth_image=%s depth_vaddr_num=%d target_mask=0x%08" PRIx32
" prim=%u index_count=%u flags=0x%08" PRIx32 "\n",
log_id, draw_name, RenderColorTypeName(color.type), color.base_addr, color.buffer_size,
color.image_id ? "yes" : "no", VulkanToString(depth.format).c_str(),
depth.image_id ? "yes" : "no", depth.vaddr_num, ctx.GetRenderTargetMask(),
static_cast<uint32_t>(ucfg.GetPrimType()), index_count, flags);
log_id, draw_name, RenderColorTypeName(color), color.desc.info.data.address,
color.desc.info.data.size, color.image_id ? "yes" : "no",
VulkanToString(depth.desc.view_info.format).c_str(), depth.image_id ? "yes" : "no",
static_cast<int>(!depth.desc.info.data.Empty()) +
static_cast<int>(depth.desc.info.HasStencil()),
ctx.GetRenderTargetMask(), static_cast<uint32_t>(ucfg.GetPrimType()), index_count, flags);
}
static void LogMrtState(const char* draw_name, const CommandBuffer& buffer,
@@ -191,7 +189,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
uint32_t flags) {
const auto& ctx = buffer.GetRegisters();
const auto& ucfg = buffer.GetUserConfig();
if (color.type == RenderColorType::NoColorOutput) {
if (!color.image_id) {
return;
}
@@ -211,8 +209,8 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
return image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled;
});
vk::Extent2D extent = color.image_id ? color.extent : vk::Extent2D {};
auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent);
const auto extent = color.Extent();
const auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent);
LOGF(
"DrawTargetState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64
@@ -221,13 +219,12 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
" blend=%s src=%u dst=%u comb=%u ps_tex=%d sampled=%d storage=%d ps_kill=%s target_mode0=%u"
" depth_test=%s depth_write=%s depth_func=%u depth_clear=%s viewport=(%.1f,%.1f %.1fx%.1f) "
"scissor=(%d,%d)-(%d,%d)\n",
log_id, buffer.GetContext().GetGpu().GetFrameNum(), draw_name,
RenderColorTypeName(color.type), color.base_addr, extent.width, extent.height,
log_id, buffer.GetContext().GetGpu().GetFrameNum(), draw_name, RenderColorTypeName(color),
color.desc.info.data.address, extent.width, extent.height,
static_cast<uint32_t>(ucfg.GetPrimType()), index_count, flags, ctx.GetRenderTargetMask(),
color.color_clear_enable ? "true" : "false", color.color_clear_value.float32[0],
color.color_clear_value.float32[1], color.color_clear_value.float32[2],
color.color_clear_value.float32[3], cc.mode, cc.op, bc.enable ? "true" : "false",
bc.color_srcblend, bc.color_destblend, bc.color_comb_fcn,
"false", color.color_clear_value.float32[0], color.color_clear_value.float32[1],
color.color_clear_value.float32[2], color.color_clear_value.float32[3], cc.mode, cc.op,
bc.enable ? "true" : "false", bc.color_srcblend, bc.color_destblend, bc.color_comb_fcn,
static_cast<int>(ps_resources.images.size()), static_cast<int>(sampled_images),
static_cast<int>(ps_resources.images.size() - sampled_images),
ps_input_info.ps_pixel_kill_enable ? "true" : "false", ps_input_info.target_output_mode[0],
@@ -251,9 +248,10 @@ static void LogDrawInputState(const CommandBuffer& buffer, const RenderColorInfo
LOGF("DrawInputState[%u]: frame=%d target=%s addr=0x%010" PRIx64
" index_type=%u index_count=%u index_addr=0x%016" PRIx64
" vs_resources=%d vs_buffers=%d\n",
log_id, buffer.GetContext().GetGpu().GetFrameNum(), RenderColorTypeName(color.type),
color.base_addr, index_type_and_size, index_count, reinterpret_cast<uint64_t>(index_addr),
vs_input_info.resources_num, vs_input_info.buffers_num);
log_id, buffer.GetContext().GetGpu().GetFrameNum(), RenderColorTypeName(color),
color.desc.info.data.address, index_type_and_size, index_count,
reinterpret_cast<uint64_t>(index_addr), vs_input_info.resources_num,
vs_input_info.buffers_num);
for (int bi = 0; bi < vs_input_info.buffers_num; bi++) {
const auto& b = vs_input_info.buffers[bi];
@@ -328,9 +326,9 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf
const auto& vp = ctx.GetScreenViewport();
vk::Extent2D framebuffer_extent {};
if (color_count > 0 && colors[0].image_id) {
framebuffer_extent = colors[0].extent;
framebuffer_extent = colors[0].Extent();
} else if (depth.image_id) {
framebuffer_extent = {depth.width, depth.height};
framebuffer_extent = {depth.desc.info.extent.width, depth.desc.info.extent.height};
} else {
const auto& limits = buffer.GetGraphics().GetPhysicalDeviceProperties().limits;
framebuffer_extent = {limits.maxFramebufferWidth, limits.maxFramebufferHeight};
@@ -392,8 +390,8 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf
// Vulkan has one bias for both faces. Prefer a visible front face when both are enabled.
const float guest_constant_factor =
use_front ? poly_offset.front_offset : poly_offset.back_offset;
const float constant_factor =
ConvertPolygonOffsetConstantFactor(guest_constant_factor, poly_offset, depth.format);
const float constant_factor = ConvertPolygonOffsetConstantFactor(
guest_constant_factor, poly_offset, depth.desc.view_info.format);
const float slope_factor =
(use_front ? poly_offset.front_scale : poly_offset.back_scale) / 16.0f;
vk_buffer.setDepthBias(constant_factor, poly_offset.clamp, slope_factor);
@@ -449,7 +447,6 @@ struct DrawRenderState {
RenderColorInfo color_info[RENDER_COLOR_ATTACHMENTS_MAX] = {};
uint32_t color_count = 0;
bool ps_active = true;
RenderState rendering;
ShaderVertexInputInfo vs_input_info;
ShaderPixelInputInfo ps_input_info;
PipelineCache::GraphicsPrograms programs;
@@ -549,23 +546,23 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
target.image_id = cache.FindImage(target.desc);
BindRenderTarget(target.image_id);
}
target.image_view = cache.FindRenderTarget(target.image_id, target.desc);
auto& image = cache.GetImage(target.image_id);
const auto image_view = cache.FindRenderTarget(target.image_id, target.desc);
auto& image = cache.GetImage(target.image_id);
SetVulkanObjectNameF(m_context.GetGraphics().device, image.backing.image,
"Kyty.MRT{}.Image[guest=0x{:016x} size=0x{:x} format={}]",
target.target_slot, image.info.data.address, image.info.data.size,
static_cast<uint32_t>(image.info.pixel_format));
SetVulkanObjectNameF(m_context.GetGraphics().device, target.image_view,
SetVulkanObjectNameF(m_context.GetGraphics().device, image_view,
"Kyty.MRT{}.View[guest=0x{:016x} mip={} layer={}+{}]",
target.target_slot, image.info.data.address,
target.desc.view_info.base_level, target.desc.view_info.base_layer,
target.desc.view_info.layer_count);
EXIT_IF(image.backing.samples != target.samples || target.image_view == nullptr);
EXIT_IF(image.backing.samples != target.desc.info.samples || image_view == nullptr);
if (attachment_samples == 0) {
attachment_samples = target.samples;
} else if (attachment_samples != target.samples) {
attachment_samples = target.desc.info.samples;
} else if (attachment_samples != target.desc.info.samples) {
EXIT("mixed color attachment sample counts are unsupported: %u and %u\n",
attachment_samples, target.samples);
attachment_samples, target.desc.info.samples);
}
const auto& view = target.desc.view_info;
const auto layout = image.binding.is_bound ? vk::ImageLayout::eGeneral
@@ -577,11 +574,12 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
ImageSubresourceRange {view.base_level, view.level_count, view.base_layer,
view.layer_count},
buffer.Handle());
state.width = std::min(state.width, target.extent.width);
state.height = std::min(state.height, target.extent.height);
const auto extent = target.Extent();
state.width = std::min(state.width, extent.width);
state.height = std::min(state.height, extent.height);
state.num_layers = std::min(state.num_layers, view.layer_count);
auto& attachment = state.color_attachments[i];
attachment.image_view = target.image_view;
attachment.image_view = image_view;
attachment.image_layout = layout;
attachment.clear_value = target.color_clear_value.uint32;
vk::ClearColorValue metadata_clear_value {};
@@ -590,23 +588,25 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
if (metadata_clear) {
attachment.clear_value = metadata_clear_value.uint32;
}
attachment.is_clear = target.color_clear_enable || metadata_clear;
attachment.is_clear = metadata_clear;
}
if (depth.image_id) {
const auto owner = cache.m_slot_images.try_get(depth.image_id);
if (owner == nullptr || !owner->registered || owner->binding.needs_rebind) {
EXIT("depth target changed after render-state discovery\n");
}
depth.image_view = cache.FindDepthTarget(depth.image_id, depth.desc);
if (depth.htile && depth.depth_clear_enable && !cache.ClearMeta(depth.htile_buffer_vaddr)) {
const auto image_view = cache.FindDepthTarget(depth.image_id, depth.desc);
const auto& metadata = depth.desc.info.metadata;
if (metadata.kind == ImageMetadataKind::Htile && depth.depth_clear_enable &&
!cache.ClearMeta(metadata.range.address)) {
EXIT("failed to acquire HTile metadata for a depth clear\n");
}
depth.depth_meta_clear_enable =
depth.htile &&
cache.IsMetaCleared(depth.htile_buffer_vaddr, depth.desc.view_info.base_layer);
metadata.kind == ImageMetadataKind::Htile &&
cache.IsMetaCleared(metadata.range.address, depth.desc.view_info.base_layer);
depth.depth_load_clear_enable = depth.depth_clear_enable || depth.depth_meta_clear_enable;
if (depth.depth_meta_clear_enable &&
!cache.TouchMeta(depth.htile_buffer_vaddr, depth.desc.view_info.base_layer, false)) {
!cache.TouchMeta(metadata.range.address, depth.desc.view_info.base_layer, false)) {
EXIT("failed to consume HTile clear state\n");
}
auto& image = cache.GetImage(depth.image_id);
@@ -614,16 +614,16 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
"Kyty.DepthTarget.Image[guest=0x{:016x} size=0x{:x} format={}]",
image.info.data.address, image.info.data.size,
static_cast<uint32_t>(image.info.pixel_format));
SetVulkanObjectNameF(m_context.GetGraphics().device, depth.image_view,
SetVulkanObjectNameF(m_context.GetGraphics().device, image_view,
"Kyty.DepthTarget.View[guest=0x{:016x} layer={}+{}]",
image.info.data.address, depth.desc.view_info.base_layer,
depth.desc.view_info.layer_count);
EXIT_IF(depth.image_view == nullptr || image.backing.samples != depth.samples);
EXIT_IF(image_view == nullptr || image.backing.samples != depth.desc.info.samples);
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);
}
const auto layout = depth_attachment_layout(depth);
// The attachment store writes even when guest depth/stencil tests do not.
@@ -636,12 +636,12 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
ImageSubresourceRange {view.base_level, view.level_count, view.base_layer,
view.layer_count},
buffer.Handle());
state.width = std::min(state.width, depth.width);
state.height = std::min(state.height, depth.height);
state.width = std::min(state.width, depth.desc.info.extent.width);
state.height = std::min(state.height, depth.desc.info.extent.height);
state.num_layers = std::min(state.num_layers, view.layer_count);
const auto aspects = ImageViewOps::DepthAspectMask(depth.format);
const auto aspects = ImageViewOps::DepthAspectMask(depth.desc.view_info.format);
auto& attachment = state.depth_stencil_attachment;
attachment.image_view = depth.image_view;
attachment.image_view = image_view;
attachment.image_layout = layout;
attachment.clear_value[0] = std::bit_cast<uint32_t>(depth.depth_clear_value);
attachment.clear_value[1] = depth.stencil_clear_value;
@@ -705,7 +705,6 @@ struct DrawEmitInfo {
};
struct DrawIndexBufferSource {
bool enabled = false;
uint64_t address = 0;
const void* host_data = nullptr;
uint64_t size = 0;
@@ -715,7 +714,6 @@ struct DrawIndexBufferSource {
struct PreparedIndexBuffer {
vk::Buffer buffer = nullptr;
uint64_t size = 0;
vk::DeviceSize offset = 0;
vk::IndexType type = vk::IndexType::eUint16;
};
@@ -849,8 +847,6 @@ static PreparedVertexBuffers AcquireVertexBuffers(CommandBuffer& b
static void SetDrawDebugPhase(CommandBuffer& buffer, uint64_t submit_id, const DrawCallInfo& draw,
uint32_t phase) {
EXIT_IF(draw.name == nullptr);
buffer.SetDebugInfo(static_cast<uint32_t>(draw.debug_op), submit_id, phase, draw.index_count, 0,
draw.instance_count, draw.first_instance);
}
@@ -935,7 +931,6 @@ bool RenderExecutor::PrepareDrawRenderState(uint64_t submit_id, CommandBuffer& b
const DrawCallInfo& draw,
uint32_t render_target_slice_offset,
bool log_setup_phases, DrawRenderState& state) {
EXIT_IF(draw.name == nullptr);
auto& ctx = buffer.GetRegisters();
if (ResolveColorTargets(submit_id, buffer, render_target_slice_offset)) {
@@ -960,9 +955,7 @@ bool RenderExecutor::PrepareDrawRenderState(uint64_t submit_id, CommandBuffer& b
ResolveRenderDepthTarget(submit_id, buffer, state.depth_info);
state.ps_active = DrawHasActivePixelShader(buffer);
const bool with_depth = (state.depth_info.format != vk::Format::eUndefined &&
static_cast<bool>(state.depth_info.image_id));
if (state.color_count == 0 && !with_depth && !state.ps_active) {
if (state.color_count == 0 && !state.depth_info.image_id && !state.ps_active) {
LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer,
draw.index_count, 0);
return false;
@@ -973,7 +966,6 @@ bool RenderExecutor::PrepareDrawRenderState(uint64_t submit_id, CommandBuffer& b
static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw, bool log_phases,
DrawRenderState& state) {
EXIT_IF(draw.name == nullptr);
auto& ctx = buffer.GetRegisters();
auto& sh_ctx = buffer.GetShaders();
@@ -1000,11 +992,9 @@ static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw, bool
static PreparedIndexBuffer PrepareIndexBuffer(CommandBuffer& buffer,
const DrawIndexBufferSource& source) {
PreparedIndexBuffer prepared;
if (!source.enabled) {
if (source.size == 0) {
return prepared;
}
EXIT_IF(source.size == 0);
prepared.size = source.size;
prepared.type = source.type;
if (source.host_data != nullptr) {
auto& stream = buffer.GetContext().GetBufferCache().GetUtilityBuffer(MemoryUsage::Stream);
@@ -1040,10 +1030,9 @@ static void CommitVertexBuffers(vk::CommandBuffer vk_buffer,
}
static void CommitIndexBuffer(vk::CommandBuffer vk_buffer, const PreparedIndexBuffer& prepared) {
if (prepared.size == 0) {
if (prepared.buffer == nullptr) {
return;
}
EXIT_IF(prepared.buffer == nullptr);
vk_buffer.bindIndexBuffer(prepared.buffer, prepared.offset, prepared.type);
}
@@ -1051,8 +1040,6 @@ static void LogDrawStateIfNeeded(const CommandBuffer& buffer, const DrawCallInfo
const DrawRenderState& state, bool always_log,
bool force_legacy_rect_log, uint32_t index_type_and_size,
const void* index_addr) {
EXIT_IF(draw.name == nullptr);
if (!graphics_debug_dump_enabled()) {
return;
}
@@ -1067,14 +1054,11 @@ static void LogDrawStateIfNeeded(const CommandBuffer& buffer, const DrawCallInfo
}
LogDrawInputState(buffer, state.color_info[0], state.vs_input_info, index_type_and_size,
draw.index_count, index_addr);
// LogDrawTextureState(draw.name, state.color_info[0], state.ps_input_info);
}
static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_buffer,
const ShaderVertexInputInfo& vs_input_info, const DrawCallInfo& draw,
const DrawEmitInfo& emit) {
EXIT_IF(draw.name == nullptr);
switch (ucfg.GetPrimType()) {
case Prospero::PrimitiveType::kPointList:
case Prospero::PrimitiveType::kLineList:
@@ -1121,7 +1105,6 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
const DrawIndexBufferSource& index_source,
bool primitive_restart_enable, bool log_pipeline_phase,
bool set_bind_debug, bool set_auto_debug) {
EXIT_IF(draw.name == nullptr);
auto& ucfg = buffer.GetUserConfig();
const bool mesh_active = state.vs_input_info.stage.program->stage == ShaderType::Mesh;
uint32_t mesh_groups = 0;
@@ -1163,7 +1146,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
vertex_bindings = AcquireVertexBuffers(buffer, state.vs_input_info);
index_binding = PrepareIndexBuffer(buffer, index_source);
}
state.rendering =
const auto rendering =
AcquireRenderTargets(buffer, state.color_info, state.color_count, state.depth_info);
if (log_pipeline_phase) {
@@ -1222,7 +1205,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x400u);
}
m_context.GetCommandScheduler().BeginRendering(state.rendering);
m_context.GetCommandScheduler().BeginRendering(rendering);
vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.pipeline);
if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x500u);
@@ -1345,7 +1328,6 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
}
DrawIndexBufferSource index_source {};
index_source.enabled = true;
index_source.address = reinterpret_cast<uint64_t>(args.index_addr);
index_source.host_data =
expanded_indices.empty() ? nullptr : static_cast<const void*>(expanded_indices.data());
@@ -1496,12 +1478,12 @@ bool RenderExecutor::ResolveColorTargets(uint64_t submit_id, CommandBuffer& buff
RenderColorInfo dst {};
ResolveRenderColorTarget(submit_id, buffer, src, render_target_slice_offset, 0, true, true);
ResolveRenderColorTarget(submit_id, buffer, dst, render_target_slice_offset, 1, true, true);
if (!src.image_id || !dst.image_id || src.type == RenderColorType::NoColorOutput ||
dst.type == RenderColorType::NoColorOutput) {
if (!src.image_id || !dst.image_id) {
return false;
}
if (src.base_addr == dst.base_addr && src.base_mip_level == dst.base_mip_level &&
src.base_array_layer == dst.base_array_layer) {
if (src.desc.info.data.address == dst.desc.info.data.address &&
src.guest_mip_level == dst.guest_mip_level &&
src.guest_array_layer == dst.guest_array_layer) {
return true;
}
@@ -1509,8 +1491,8 @@ bool RenderExecutor::ResolveColorTargets(uint64_t submit_id, CommandBuffer& buff
cache.MarkGpuWritten(dst.image_id);
auto& source = cache.GetImage(src.image_id);
auto& destination = cache.GetImage(dst.image_id);
destination.Resolve(source, {src.base_mip_level, 1, src.base_array_layer, 1},
{dst.base_mip_level, 1, dst.base_array_layer, 1});
destination.Resolve(source, {src.guest_mip_level, 1, src.guest_array_layer, 1},
{dst.guest_mip_level, 1, dst.guest_array_layer, 1});
return true;
}
+2 -2
View File
@@ -165,7 +165,7 @@ bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanIm
VmaAllocationInfo allocation_result {};
vk::Image::CType native_image = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(
const auto result = static_cast<vk::Result>(
vmaCreateImage(allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info),
&alloc_info, &native_image, &memory.allocation, &allocation_result));
image.image = native_image;
@@ -175,7 +175,7 @@ bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanIm
}
device.getImageMemoryRequirements(image.image, &memory.requirements);
memory.type = allocation_result.memoryType;
memory.type = allocation_result.memoryType;
VulkanTrackAllocation(memory);
return true;
}