renderer_vulkan: Add depth buffer support

This commit is contained in:
raphaelthegreat 2024-06-07 15:45:03 +03:00
parent 12f1743d5f
commit 17cb4e0132
12 changed files with 178 additions and 43 deletions

View File

@ -10,10 +10,8 @@
#include "video_core/amdgpu/pixel_format.h" #include "video_core/amdgpu/pixel_format.h"
#include <array> #include <array>
#include <condition_variable>
#include <coroutine> #include <coroutine>
#include <functional> #include <mutex>
#include <future>
#include <span> #include <span>
#include <thread> #include <thread>
#include <queue> #include <queue>
@ -333,6 +331,14 @@ struct Liverpool {
u32 Height() const { u32 Height() const {
return (depth_size.height_tile_max + 1) << 3; return (depth_size.height_tile_max + 1) << 3;
} }
u64 Address() const {
return u64(z_read_base) << 8;
}
[[nodiscard]] size_t GetSizeAligned() const {
return depth_slice.tile_max * 8;
}
}; };
enum class ClipSpace : u32 { enum class ClipSpace : u32 {
@ -717,6 +723,14 @@ struct Liverpool {
CbColor7Base = 0xA381, CbColor7Base = 0xA381,
}; };
struct PolygonOffset {
float depth_bias;
float front_scale;
float front_offset;
float back_scale;
float back_offset;
};
union Regs { union Regs {
struct { struct {
INSERT_PADDING_WORDS(0x2C08); INSERT_PADDING_WORDS(0x2C08);
@ -726,8 +740,8 @@ struct Liverpool {
INSERT_PADDING_WORDS(0x2E00 - 0x2C4C - 16); INSERT_PADDING_WORDS(0x2E00 - 0x2C4C - 16);
ComputeProgram cs_program; ComputeProgram cs_program;
INSERT_PADDING_WORDS(0xA008 - 0x2E00 - 80); INSERT_PADDING_WORDS(0xA008 - 0x2E00 - 80);
u32 depth_bounds_min; float depth_bounds_min;
u32 depth_bounds_max; float depth_bounds_max;
u32 stencil_clear; u32 stencil_clear;
u32 depth_clear; u32 depth_clear;
Scissor screen_scissor; Scissor screen_scissor;
@ -776,7 +790,9 @@ struct Liverpool {
IndexBufferType index_buffer_type; IndexBufferType index_buffer_type;
INSERT_PADDING_WORDS(0xA2A1 - 0xA29E - 2); INSERT_PADDING_WORDS(0xA2A1 - 0xA29E - 2);
u32 enable_primitive_id; u32 enable_primitive_id;
INSERT_PADDING_WORDS(0xA318 - 0xA2A1 - 1); INSERT_PADDING_WORDS(0xA2DF - 0xA2A1 - 1);
PolygonOffset poly_offset;
INSERT_PADDING_WORDS(0xA318 - 0xA2DF - 5);
ColorBuffer color_buffers[NumColorBuffers]; ColorBuffer color_buffers[NumColorBuffers];
INSERT_PADDING_WORDS(0xC242 - 0xA390); INSERT_PADDING_WORDS(0xC242 - 0xA390);
PrimitiveType primitive_type; PrimitiveType primitive_type;
@ -930,6 +946,7 @@ static_assert(GFX6_3D_REG_INDEX(viewport_control) == 0xA206);
static_assert(GFX6_3D_REG_INDEX(vs_output_control) == 0xA207); static_assert(GFX6_3D_REG_INDEX(vs_output_control) == 0xA207);
static_assert(GFX6_3D_REG_INDEX(index_buffer_type) == 0xA29F); static_assert(GFX6_3D_REG_INDEX(index_buffer_type) == 0xA29F);
static_assert(GFX6_3D_REG_INDEX(enable_primitive_id) == 0xA2A1); static_assert(GFX6_3D_REG_INDEX(enable_primitive_id) == 0xA2A1);
static_assert(GFX6_3D_REG_INDEX(poly_offset) == 0xA2DF);
static_assert(GFX6_3D_REG_INDEX(color_buffers[0].base_address) == 0xA318); static_assert(GFX6_3D_REG_INDEX(color_buffers[0].base_address) == 0xA318);
static_assert(GFX6_3D_REG_INDEX(color_buffers[0].pitch) == 0xA319); static_assert(GFX6_3D_REG_INDEX(color_buffers[0].pitch) == 0xA319);
static_assert(GFX6_3D_REG_INDEX(color_buffers[0].slice) == 0xA31A); static_assert(GFX6_3D_REG_INDEX(color_buffers[0].slice) == 0xA31A);

View File

@ -64,8 +64,10 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.pVertexAttributeDescriptions = attributes.data(), .pVertexAttributeDescriptions = attributes.data(),
}; };
ASSERT_MSG(key.prim_type != Liverpool::PrimitiveType::RectList || IsEmbeddedVs(), if (key.prim_type == Liverpool::PrimitiveType::RectList && !IsEmbeddedVs()) {
"Rectangle List primitive type is only supported for embedded VS"); LOG_WARNING(Render_Vulkan,
"Rectangle List primitive type is only supported for embedded VS");
}
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
.topology = LiverpoolToVK::PrimitiveType(key.prim_type), .topology = LiverpoolToVK::PrimitiveType(key.prim_type),
@ -76,11 +78,14 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.depthClampEnable = false, .depthClampEnable = false,
.rasterizerDiscardEnable = false, .rasterizerDiscardEnable = false,
.polygonMode = LiverpoolToVK::PolygonMode(key.polygon_mode), .polygonMode = LiverpoolToVK::PolygonMode(key.polygon_mode),
.cullMode = vk::CullModeFlagBits::eNone, /*LiverpoolToVK::CullMode(key.cull_mode),*/ .cullMode = LiverpoolToVK::CullMode(key.cull_mode),
.frontFace = key.front_face == Liverpool::FrontFace::Clockwise .frontFace = key.front_face == Liverpool::FrontFace::Clockwise
? vk::FrontFace::eClockwise ? vk::FrontFace::eClockwise
: vk::FrontFace::eCounterClockwise, : vk::FrontFace::eCounterClockwise,
.depthBiasEnable = false, .depthBiasEnable = bool(key.depth_bias_enable),
.depthBiasConstantFactor = key.depth_bias_const_factor,
.depthBiasClamp = key.depth_bias_clamp,
.depthBiasSlopeFactor = key.depth_bias_slope_factor,
.lineWidth = 1.0f, .lineWidth = 1.0f,
}; };
@ -103,7 +108,12 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.extent = {1, 1}, .extent = {1, 1},
}; };
const vk::PipelineViewportDepthClipControlCreateInfoEXT clip_control = {
.negativeOneToOne = key.clip_space == Liverpool::ClipSpace::MinusWToW,
};
const vk::PipelineViewportStateCreateInfo viewport_info = { const vk::PipelineViewportStateCreateInfo viewport_info = {
.pNext = &clip_control,
.viewportCount = 1, .viewportCount = 1,
.pViewports = &viewport, .pViewports = &viewport,
.scissorCount = 1, .scissorCount = 1,
@ -150,6 +160,8 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.writeMask = key.stencil_ref_back.stencil_write_mask, .writeMask = key.stencil_ref_back.stencil_write_mask,
.reference = key.stencil_ref_back.stencil_test_val, .reference = key.stencil_ref_back.stencil_test_val,
}, },
.minDepthBounds = key.depth_bounds_min,
.maxDepthBounds = key.depth_bounds_max,
}; };
u32 shader_count = 1; u32 shader_count = 1;

View File

@ -32,6 +32,12 @@ struct GraphicsPipelineKey {
vk::Format depth_format; vk::Format depth_format;
Liverpool::DepthControl depth; Liverpool::DepthControl depth;
float depth_bounds_min;
float depth_bounds_max;
float depth_bias_const_factor;
float depth_bias_slope_factor;
float depth_bias_clamp;
u32 depth_bias_enable;
Liverpool::StencilControl stencil; Liverpool::StencilControl stencil;
Liverpool::StencilRefMask stencil_ref_front; Liverpool::StencilRefMask stencil_ref_front;
Liverpool::StencilRefMask stencil_ref_back; Liverpool::StencilRefMask stencil_ref_back;
@ -39,7 +45,7 @@ struct GraphicsPipelineKey {
Liverpool::PolygonMode polygon_mode; Liverpool::PolygonMode polygon_mode;
Liverpool::CullMode cull_mode; Liverpool::CullMode cull_mode;
Liverpool::FrontFace front_face; Liverpool::FrontFace front_face;
u32 pad{}; Liverpool::ClipSpace clip_space;
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls; std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks; std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks;
@ -47,7 +53,6 @@ struct GraphicsPipelineKey {
return std::memcmp(this, &key, sizeof(key)) == 0; return std::memcmp(this, &key, sizeof(key)) == 0;
} }
}; };
static_assert(std::has_unique_object_representations_v<GraphicsPipelineKey>);
class GraphicsPipeline { class GraphicsPipeline {
public: public:

View File

@ -155,6 +155,8 @@ bool Instance::CreateDevice() {
custom_border_color = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); custom_border_color = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
add_extension(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
add_extension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
// The next two extensions are required to be available together in order to support write masks // The next two extensions are required to be available together in order to support write masks
color_write_en = add_extension(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME); color_write_en = add_extension(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
color_write_en &= add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); color_write_en &= add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
@ -227,6 +229,9 @@ bool Instance::CreateDevice() {
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{ vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{
.extendedDynamicState3ColorWriteMask = true, .extendedDynamicState3ColorWriteMask = true,
}, },
vk::PhysicalDeviceDepthClipControlFeaturesEXT{
.depthClipControl = true,
},
}; };
if (!color_write_en) { if (!color_write_en) {

View File

@ -88,12 +88,26 @@ void PipelineCache::RefreshGraphicsKey() {
auto& key = graphics_key; auto& key = graphics_key;
key.depth = regs.depth_control; key.depth = regs.depth_control;
key.depth_bounds_min = regs.depth_bounds_min;
key.depth_bounds_max = regs.depth_bounds_max;
key.depth_bias_enable = regs.polygon_control.enable_polygon_offset_back ||
regs.polygon_control.enable_polygon_offset_front ||
regs.polygon_control.enable_polygon_offset_para;
if (regs.polygon_control.enable_polygon_offset_front) {
key.depth_bias_const_factor = regs.poly_offset.front_offset;
key.depth_bias_slope_factor = regs.poly_offset.front_scale;
} else {
key.depth_bias_const_factor = regs.poly_offset.back_offset;
key.depth_bias_slope_factor = regs.poly_offset.back_scale;
}
key.depth_bias_clamp = regs.poly_offset.depth_bias;
key.stencil = regs.stencil_control; key.stencil = regs.stencil_control;
key.stencil_ref_front = regs.stencil_ref_front; key.stencil_ref_front = regs.stencil_ref_front;
key.stencil_ref_back = regs.stencil_ref_back; key.stencil_ref_back = regs.stencil_ref_back;
key.prim_type = regs.primitive_type; key.prim_type = regs.primitive_type;
key.polygon_mode = regs.polygon_control.PolyMode(); key.polygon_mode = regs.polygon_control.PolyMode();
key.cull_mode = regs.polygon_control.CullingMode(); key.cull_mode = regs.polygon_control.CullingMode();
key.clip_space = regs.clipper_control.clip_space;
key.front_face = regs.polygon_control.front_face; key.front_face = regs.polygon_control.front_face;
const auto& db = regs.depth_buffer; const auto& db = regs.depth_buffer;
@ -103,6 +117,9 @@ void PipelineCache::RefreshGraphicsKey() {
// `RenderingInfo` is assumed to be initialized with a contiguous array of valid color // `RenderingInfo` is assumed to be initialized with a contiguous array of valid color
// attachments. This might be not a case as HW color buffers can be bound in an arbitrary order. // attachments. This might be not a case as HW color buffers can be bound in an arbitrary order.
// We need to do some arrays compaction at this stage // We need to do some arrays compaction at this stage
key.color_formats.fill(vk::Format::eUndefined);
key.blend_controls.fill({});
key.write_masks.fill({});
int remapped_cb{}; int remapped_cb{};
for (auto cb = 0u; cb < Liverpool::NumColorBuffers; ++cb) { for (auto cb = 0u; cb < Liverpool::NumColorBuffers; ++cb) {
auto const& col_buf = regs.color_buffers[cb]; auto const& col_buf = regs.color_buffers[cb];
@ -112,6 +129,8 @@ void PipelineCache::RefreshGraphicsKey() {
key.color_formats[remapped_cb] = key.color_formats[remapped_cb] =
LiverpoolToVK::SurfaceFormat(col_buf.info.format, col_buf.NumFormat()); LiverpoolToVK::SurfaceFormat(col_buf.info.format, col_buf.NumFormat());
key.blend_controls[remapped_cb] = regs.blend_control[cb]; key.blend_controls[remapped_cb] = regs.blend_control[cb];
key.blend_controls[remapped_cb].enable.Assign(key.blend_controls[remapped_cb].enable &&
!col_buf.info.blend_bypass);
key.write_masks[remapped_cb] = vk::ColorComponentFlags{regs.color_target_mask.GetMask(cb)}; key.write_masks[remapped_cb] = vk::ColorComponentFlags{regs.color_target_mask.GetMask(cb)};
++remapped_cb; ++remapped_cb;

View File

@ -41,6 +41,8 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
boost::container::static_vector<vk::RenderingAttachmentInfo, Liverpool::NumColorBuffers> boost::container::static_vector<vk::RenderingAttachmentInfo, Liverpool::NumColorBuffers>
color_attachments{}; color_attachments{};
vk::RenderingAttachmentInfo depth_attachment{};
u32 num_depth_attachments{};
for (auto col_buf_id = 0u; col_buf_id < Liverpool::NumColorBuffers; ++col_buf_id) { for (auto col_buf_id = 0u; col_buf_id < Liverpool::NumColorBuffers; ++col_buf_id) {
const auto& col_buf = regs.color_buffers[col_buf_id]; const auto& col_buf = regs.color_buffers[col_buf_id];
if (!col_buf) { if (!col_buf) {
@ -57,6 +59,17 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
.storeOp = vk::AttachmentStoreOp::eStore, .storeOp = vk::AttachmentStoreOp::eStore,
}); });
} }
if (regs.depth_control.depth_enable && regs.depth_buffer.Address() != 0) {
const auto& image_view =
texture_cache.DepthTarget(regs.depth_buffer, liverpool->last_db_extent);
depth_attachment = {
.imageView = *image_view.image_view,
.imageLayout = vk::ImageLayout::eGeneral,
.loadOp = vk::AttachmentLoadOp::eLoad,
.storeOp = vk::AttachmentStoreOp::eStore,
};
num_depth_attachments++;
}
// TODO: Don't restart renderpass every draw // TODO: Don't restart renderpass every draw
const auto& scissor = regs.screen_scissor; const auto& scissor = regs.screen_scissor;
@ -69,6 +82,7 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
.layerCount = 1, .layerCount = 1,
.colorAttachmentCount = static_cast<u32>(color_attachments.size()), .colorAttachmentCount = static_cast<u32>(color_attachments.size()),
.pColorAttachments = color_attachments.data(), .pColorAttachments = color_attachments.data(),
.pDepthAttachment = num_depth_attachments ? &depth_attachment : nullptr,
}; };
UpdateDynamicState(*pipeline); UpdateDynamicState(*pipeline);
@ -78,7 +92,9 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
if (is_indexed) { if (is_indexed) {
cmdbuf.drawIndexed(num_indices, regs.num_instances.NumInstances(), 0, 0, 0); cmdbuf.drawIndexed(num_indices, regs.num_instances.NumInstances(), 0, 0, 0);
} else { } else {
const u32 num_vertices = pipeline->IsEmbeddedVs() ? 4 : regs.num_indices; const u32 num_vertices = regs.primitive_type == AmdGpu::Liverpool::PrimitiveType::RectList
? 4
: regs.num_indices;
cmdbuf.draw(num_vertices, regs.num_instances.NumInstances(), 0, 0); cmdbuf.draw(num_vertices, regs.num_instances.NumInstances(), 0, 0);
} }
cmdbuf.endRendering(); cmdbuf.endRendering();
@ -156,13 +172,15 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) {
void Rasterizer::UpdateViewportScissorState() { void Rasterizer::UpdateViewportScissorState() {
auto& regs = liverpool->regs; auto& regs = liverpool->regs;
const float reduce_z =
regs.clipper_control.clip_space == AmdGpu::Liverpool::ClipSpace::MinusWToW ? 1.0f : 0.0f;
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
const vk::Viewport viewport{ const vk::Viewport viewport{
.x = regs.viewports[0].xoffset - regs.viewports[0].xscale, .x = regs.viewports[0].xoffset - regs.viewports[0].xscale,
.y = regs.viewports[0].yoffset - regs.viewports[0].yscale, .y = regs.viewports[0].yoffset - regs.viewports[0].yscale,
.width = regs.viewports[0].xscale * 2.0f, .width = regs.viewports[0].xscale * 2.0f,
.height = regs.viewports[0].yscale * 2.0f, .height = regs.viewports[0].yscale * 2.0f,
.minDepth = regs.viewports[0].zoffset - regs.viewports[0].zscale, .minDepth = regs.viewports[0].zoffset - regs.viewports[0].zscale * reduce_z,
.maxDepth = regs.viewports[0].zscale + regs.viewports[0].zoffset, .maxDepth = regs.viewports[0].zscale + regs.viewports[0].zoffset,
}; };
const vk::Rect2D scissor{ const vk::Rect2D scissor{

View File

@ -33,11 +33,23 @@ static vk::Format ConvertPixelFormat(const VideoOutFormat format) {
return {}; return {};
} }
static bool IsDepthStencilFormat(vk::Format format) {
switch (format) {
case vk::Format::eD16Unorm:
case vk::Format::eD16UnormS8Uint:
case vk::Format::eD32Sfloat:
case vk::Format::eD32SfloatS8Uint:
return true;
default:
return false;
}
}
static vk::ImageUsageFlags ImageUsageFlags(const vk::Format format) { static vk::ImageUsageFlags ImageUsageFlags(const vk::Format format) {
vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eTransferSrc |
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eSampled; vk::ImageUsageFlagBits::eSampled;
if (false /*&& IsDepthStencilFormat(format)*/) { if (IsDepthStencilFormat(format)) {
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
} else { } else {
if (format != vk::Format::eBc3SrgbBlock) { if (format != vk::Format::eBc3SrgbBlock) {
@ -54,9 +66,9 @@ static vk::ImageType ConvertImageType(AmdGpu::ImageType type) noexcept {
case AmdGpu::ImageType::Color2D: case AmdGpu::ImageType::Color2D:
case AmdGpu::ImageType::Color1DArray: case AmdGpu::ImageType::Color1DArray:
case AmdGpu::ImageType::Cube: case AmdGpu::ImageType::Cube:
case AmdGpu::ImageType::Color2DArray:
return vk::ImageType::e2D; return vk::ImageType::e2D;
case AmdGpu::ImageType::Color3D: case AmdGpu::ImageType::Color3D:
case AmdGpu::ImageType::Color2DArray:
return vk::ImageType::e3D; return vk::ImageType::e3D;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -98,6 +110,18 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
guest_size_bytes = buffer.GetSizeAligned(); guest_size_bytes = buffer.GetSizeAligned();
} }
ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint) noexcept {
is_tiled = false;
pixel_format = LiverpoolToVK::DepthFormat(buffer.z_info.format, buffer.stencil_info.format);
type = vk::ImageType::e2D;
size.width = hint.Valid() ? hint.width : buffer.Pitch();
size.height = hint.Valid() ? hint.height : buffer.Height();
size.depth = 1;
pitch = size.width;
guest_size_bytes = buffer.GetSizeAligned();
}
ImageInfo::ImageInfo(const AmdGpu::Image& image) noexcept { ImageInfo::ImageInfo(const AmdGpu::Image& image) noexcept {
is_tiled = image.IsTiled(); is_tiled = image.IsTiled();
tiling_mode = image.GetTilingMode(); tiling_mode = image.GetTilingMode();
@ -165,6 +189,13 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
info.usage |= vk::ImageUsageFlagBits::eStorage; info.usage |= vk::ImageUsageFlagBits::eStorage;
} }
if (info.pixel_format == vk::Format::eD32Sfloat) {
aspect_mask = vk::ImageAspectFlagBits::eDepth;
}
if (info.pixel_format == vk::Format::eD32SfloatS8Uint) {
aspect_mask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
}
const vk::ImageCreateInfo image_ci = { const vk::ImageCreateInfo image_ci = {
.flags = flags, .flags = flags,
.imageType = info.type, .imageType = info.type,
@ -187,7 +218,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
if (info.is_tiled) { if (info.is_tiled) {
ImageViewInfo view_info; ImageViewInfo view_info;
view_info.format = DemoteImageFormatForDetiling(info.pixel_format); view_info.format = DemoteImageFormatForDetiling(info.pixel_format);
view_for_detiler.emplace(*instance, view_info, image); view_for_detiler.emplace(*instance, view_info, *this);
} }
Transit(vk::ImageLayout::eGeneral, vk::AccessFlagBits::eNone); Transit(vk::ImageLayout::eGeneral, vk::AccessFlagBits::eNone);
@ -198,23 +229,25 @@ void Image::Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits> ds
return; return;
} }
const vk::ImageMemoryBarrier barrier = {.srcAccessMask = access_mask, const vk::ImageMemoryBarrier barrier = {
.dstAccessMask = dst_mask, .srcAccessMask = access_mask,
.oldLayout = layout, .dstAccessMask = dst_mask,
.newLayout = dst_layout, .oldLayout = layout,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .newLayout = dst_layout,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.subresourceRange{ .image = image,
.aspectMask = aspect_mask, .subresourceRange{
.baseMipLevel = 0, .aspectMask = aspect_mask,
.levelCount = VK_REMAINING_MIP_LEVELS, .baseMipLevel = 0,
.baseArrayLayer = 0, .levelCount = VK_REMAINING_MIP_LEVELS,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .baseArrayLayer = 0,
}}; .layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
// Adjust pipieline stage // Adjust pipieline stage
vk::PipelineStageFlags dst_pl_stage = const vk::PipelineStageFlags dst_pl_stage =
(dst_mask == vk::AccessFlagBits::eTransferRead || (dst_mask == vk::AccessFlagBits::eTransferRead ||
dst_mask == vk::AccessFlagBits::eTransferWrite) dst_mask == vk::AccessFlagBits::eTransferWrite)
? vk::PipelineStageFlagBits::eTransfer ? vk::PipelineStageFlagBits::eTransfer

View File

@ -38,6 +38,8 @@ struct ImageInfo {
explicit ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noexcept; explicit ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noexcept;
explicit ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer, explicit ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept; const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept;
explicit ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept;
explicit ImageInfo(const AmdGpu::Image& image) noexcept; explicit ImageInfo(const AmdGpu::Image& image) noexcept;
bool is_tiled = false; bool is_tiled = false;

View File

@ -3,6 +3,7 @@
#include "video_core/renderer_vulkan/liverpool_to_vk.h" #include "video_core/renderer_vulkan/liverpool_to_vk.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/texture_cache/image.h"
#include "video_core/texture_cache/image_view.h" #include "video_core/texture_cache/image_view.h"
namespace VideoCore { namespace VideoCore {
@ -58,7 +59,7 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image) noexcept {
mapping.a = ConvertComponentSwizzle(image.dst_sel_w); mapping.a = ConvertComponentSwizzle(image.dst_sel_w);
} }
ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info_, vk::Image image, ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info_, Image& image,
std::optional<vk::ImageUsageFlags> usage_override /*= {}*/) std::optional<vk::ImageUsageFlags> usage_override /*= {}*/)
: info{info_} { : info{info_} {
vk::ImageViewUsageCreateInfo usage_ci{}; vk::ImageViewUsageCreateInfo usage_ci{};
@ -66,14 +67,20 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
usage_ci.usage = usage_override.value(); usage_ci.usage = usage_override.value();
} }
// When sampling D32 texture from shader, the T# specifies R32 Float format so adjust it.
vk::Format format = info.format;
if (image.aspect_mask & vk::ImageAspectFlagBits::eDepth && format == vk::Format::eR32Sfloat) {
format = vk::Format::eD32Sfloat;
}
const vk::ImageViewCreateInfo image_view_ci = { const vk::ImageViewCreateInfo image_view_ci = {
.pNext = usage_override.has_value() ? &usage_ci : nullptr, .pNext = usage_override.has_value() ? &usage_ci : nullptr,
.image = image, .image = image.image,
.viewType = info.type, .viewType = info.type,
.format = info.format, .format = format,
.components = info.mapping, .components = info.mapping,
.subresourceRange{ .subresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = image.aspect_mask,
.baseMipLevel = 0U, .baseMipLevel = 0U,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,

View File

@ -28,8 +28,10 @@ struct ImageViewInfo {
auto operator<=>(const ImageViewInfo&) const = default; auto operator<=>(const ImageViewInfo&) const = default;
}; };
struct Image;
struct ImageView { struct ImageView {
explicit ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info, vk::Image image, explicit ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info, Image& image,
std::optional<vk::ImageUsageFlags> usage_override = {}); std::optional<vk::ImageUsageFlags> usage_override = {});
~ImageView(); ~ImageView();

View File

@ -93,7 +93,7 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler&
ASSERT(null_id.index == 0); ASSERT(null_id.index == 0);
ImageViewInfo view_info; ImageViewInfo view_info;
void(slot_image_views.insert(instance, view_info, slot_images[null_id].image)); void(slot_image_views.insert(instance, view_info, slot_images[null_id]));
} }
TextureCache::~TextureCache() { TextureCache::~TextureCache() {
@ -112,7 +112,7 @@ void TextureCache::OnCpuWrite(VAddr address) {
}); });
} }
Image& TextureCache::FindImage(const ImageInfo& info, VAddr cpu_address) { Image& TextureCache::FindImage(const ImageInfo& info, VAddr cpu_address, bool refresh_on_create) {
std::unique_lock lock{m_page_table}; std::unique_lock lock{m_page_table};
boost::container::small_vector<ImageId, 2> image_ids; boost::container::small_vector<ImageId, 2> image_ids;
ForEachImageInRegion(cpu_address, info.guest_size_bytes, [&](ImageId image_id, Image& image) { ForEachImageInRegion(cpu_address, info.guest_size_bytes, [&](ImageId image_id, Image& image) {
@ -132,7 +132,8 @@ Image& TextureCache::FindImage(const ImageInfo& info, VAddr cpu_address) {
} }
Image& image = slot_images[image_id]; Image& image = slot_images[image_id];
if (True(image.flags & ImageFlagBits::CpuModified)) { if (True(image.flags & ImageFlagBits::CpuModified) &&
(!image_ids.empty() || refresh_on_create)) {
RefreshImage(image); RefreshImage(image);
TrackImage(image, image_id); TrackImage(image, image_id);
} }
@ -153,8 +154,7 @@ ImageView& TextureCache::RegisterImageView(Image& image, const ImageViewInfo& vi
usage_override = image.info.usage & ~vk::ImageUsageFlagBits::eStorage; usage_override = image.info.usage & ~vk::ImageUsageFlagBits::eStorage;
} }
const ImageViewId view_id = const ImageViewId view_id = slot_image_views.insert(instance, view_info, image, usage_override);
slot_image_views.insert(instance, view_info, image.image, usage_override);
image.image_view_infos.emplace_back(view_info); image.image_view_infos.emplace_back(view_info);
image.image_view_ids.emplace_back(view_id); image.image_view_ids.emplace_back(view_id);
return slot_image_views[view_id]; return slot_image_views[view_id];
@ -177,6 +177,7 @@ ImageView& TextureCache::RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buff
const AmdGpu::Liverpool::CbDbExtent& hint) { const AmdGpu::Liverpool::CbDbExtent& hint) {
const ImageInfo info{buffer, hint}; const ImageInfo info{buffer, hint};
auto& image = FindImage(info, buffer.Address()); auto& image = FindImage(info, buffer.Address());
image.flags &= ~ImageFlagBits::CpuModified;
image.Transit(vk::ImageLayout::eColorAttachmentOptimal, image.Transit(vk::ImageLayout::eColorAttachmentOptimal,
vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentWrite |
@ -187,6 +188,17 @@ ImageView& TextureCache::RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buff
return RegisterImageView(image, view_info); return RegisterImageView(image, view_info);
} }
ImageView& TextureCache::DepthTarget(const AmdGpu::Liverpool::DepthBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint) {
const ImageInfo info{buffer, hint};
auto& image = FindImage(info, buffer.Address(), false);
image.flags &= ~ImageFlagBits::CpuModified;
ImageViewInfo view_info;
view_info.format = info.pixel_format;
return RegisterImageView(image, view_info);
}
void TextureCache::RefreshImage(Image& image) { void TextureCache::RefreshImage(Image& image) {
// Mark image as validated. // Mark image as validated.
image.flags &= ~ImageFlagBits::CpuModified; image.flags &= ~ImageFlagBits::CpuModified;

View File

@ -37,7 +37,8 @@ public:
void OnCpuWrite(VAddr address); void OnCpuWrite(VAddr address);
/// Retrieves the image handle of the image with the provided attributes and address. /// Retrieves the image handle of the image with the provided attributes and address.
[[nodiscard]] Image& FindImage(const ImageInfo& info, VAddr cpu_address); [[nodiscard]] Image& FindImage(const ImageInfo& info, VAddr cpu_address,
bool refresh_on_create = true);
/// Retrieves an image view with the properties of the specified image descriptor. /// Retrieves an image view with the properties of the specified image descriptor.
[[nodiscard]] ImageView& FindImageView(const AmdGpu::Image& image); [[nodiscard]] ImageView& FindImageView(const AmdGpu::Image& image);
@ -45,6 +46,8 @@ public:
/// Retrieves the render target with specified properties /// Retrieves the render target with specified properties
[[nodiscard]] ImageView& RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buffer, [[nodiscard]] ImageView& RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint); const AmdGpu::Liverpool::CbDbExtent& hint);
[[nodiscard]] ImageView& DepthTarget(const AmdGpu::Liverpool::DepthBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint);
/// Reuploads image contents. /// Reuploads image contents.
void RefreshImage(Image& image); void RefreshImage(Image& image);