diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index b561b712..a190a870 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -10,10 +10,8 @@ #include "video_core/amdgpu/pixel_format.h" #include -#include #include -#include -#include +#include #include #include #include @@ -333,6 +331,14 @@ struct Liverpool { u32 Height() const { 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 { @@ -717,6 +723,14 @@ struct Liverpool { CbColor7Base = 0xA381, }; + struct PolygonOffset { + float depth_bias; + float front_scale; + float front_offset; + float back_scale; + float back_offset; + }; + union Regs { struct { INSERT_PADDING_WORDS(0x2C08); @@ -726,8 +740,8 @@ struct Liverpool { INSERT_PADDING_WORDS(0x2E00 - 0x2C4C - 16); ComputeProgram cs_program; INSERT_PADDING_WORDS(0xA008 - 0x2E00 - 80); - u32 depth_bounds_min; - u32 depth_bounds_max; + float depth_bounds_min; + float depth_bounds_max; u32 stencil_clear; u32 depth_clear; Scissor screen_scissor; @@ -776,7 +790,9 @@ struct Liverpool { IndexBufferType index_buffer_type; INSERT_PADDING_WORDS(0xA2A1 - 0xA29E - 2); 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]; INSERT_PADDING_WORDS(0xC242 - 0xA390); 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(index_buffer_type) == 0xA29F); 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].pitch) == 0xA319); static_assert(GFX6_3D_REG_INDEX(color_buffers[0].slice) == 0xA31A); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index c92bf7fe..fe464f0f 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -64,8 +64,10 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul .pVertexAttributeDescriptions = attributes.data(), }; - ASSERT_MSG(key.prim_type != Liverpool::PrimitiveType::RectList || IsEmbeddedVs(), - "Rectangle List primitive type is only supported for embedded VS"); + if (key.prim_type == Liverpool::PrimitiveType::RectList && !IsEmbeddedVs()) { + LOG_WARNING(Render_Vulkan, + "Rectangle List primitive type is only supported for embedded VS"); + } const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { .topology = LiverpoolToVK::PrimitiveType(key.prim_type), @@ -76,11 +78,14 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul .depthClampEnable = false, .rasterizerDiscardEnable = false, .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 ? vk::FrontFace::eClockwise : 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, }; @@ -103,7 +108,12 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul .extent = {1, 1}, }; + const vk::PipelineViewportDepthClipControlCreateInfoEXT clip_control = { + .negativeOneToOne = key.clip_space == Liverpool::ClipSpace::MinusWToW, + }; + const vk::PipelineViewportStateCreateInfo viewport_info = { + .pNext = &clip_control, .viewportCount = 1, .pViewports = &viewport, .scissorCount = 1, @@ -150,6 +160,8 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul .writeMask = key.stencil_ref_back.stencil_write_mask, .reference = key.stencil_ref_back.stencil_test_val, }, + .minDepthBounds = key.depth_bounds_min, + .maxDepthBounds = key.depth_bounds_max, }; u32 shader_count = 1; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index e93ea6f4..ff512406 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -32,6 +32,12 @@ struct GraphicsPipelineKey { vk::Format depth_format; 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::StencilRefMask stencil_ref_front; Liverpool::StencilRefMask stencil_ref_back; @@ -39,7 +45,7 @@ struct GraphicsPipelineKey { Liverpool::PolygonMode polygon_mode; Liverpool::CullMode cull_mode; Liverpool::FrontFace front_face; - u32 pad{}; + Liverpool::ClipSpace clip_space; std::array blend_controls; std::array write_masks; @@ -47,7 +53,6 @@ struct GraphicsPipelineKey { return std::memcmp(this, &key, sizeof(key)) == 0; } }; -static_assert(std::has_unique_object_representations_v); class GraphicsPipeline { public: diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 355d2603..6d19452d 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -155,6 +155,8 @@ bool Instance::CreateDevice() { custom_border_color = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); add_extension(VK_KHR_PUSH_DESCRIPTOR_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 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); @@ -227,6 +229,9 @@ bool Instance::CreateDevice() { vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{ .extendedDynamicState3ColorWriteMask = true, }, + vk::PhysicalDeviceDepthClipControlFeaturesEXT{ + .depthClipControl = true, + }, }; if (!color_write_en) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 11cd5419..441d0b78 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -88,12 +88,26 @@ void PipelineCache::RefreshGraphicsKey() { auto& key = graphics_key; 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_ref_front = regs.stencil_ref_front; key.stencil_ref_back = regs.stencil_ref_back; key.prim_type = regs.primitive_type; key.polygon_mode = regs.polygon_control.PolyMode(); key.cull_mode = regs.polygon_control.CullingMode(); + key.clip_space = regs.clipper_control.clip_space; key.front_face = regs.polygon_control.front_face; 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 // 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 + key.color_formats.fill(vk::Format::eUndefined); + key.blend_controls.fill({}); + key.write_masks.fill({}); int remapped_cb{}; for (auto cb = 0u; cb < Liverpool::NumColorBuffers; ++cb) { auto const& col_buf = regs.color_buffers[cb]; @@ -112,6 +129,8 @@ void PipelineCache::RefreshGraphicsKey() { key.color_formats[remapped_cb] = LiverpoolToVK::SurfaceFormat(col_buf.info.format, col_buf.NumFormat()); 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)}; ++remapped_cb; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index d49e7138..c1340d08 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -41,6 +41,8 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) { boost::container::static_vector color_attachments{}; + vk::RenderingAttachmentInfo depth_attachment{}; + u32 num_depth_attachments{}; for (auto col_buf_id = 0u; col_buf_id < Liverpool::NumColorBuffers; ++col_buf_id) { const auto& col_buf = regs.color_buffers[col_buf_id]; if (!col_buf) { @@ -57,6 +59,17 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) { .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 const auto& scissor = regs.screen_scissor; @@ -69,6 +82,7 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) { .layerCount = 1, .colorAttachmentCount = static_cast(color_attachments.size()), .pColorAttachments = color_attachments.data(), + .pDepthAttachment = num_depth_attachments ? &depth_attachment : nullptr, }; UpdateDynamicState(*pipeline); @@ -78,7 +92,9 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) { if (is_indexed) { cmdbuf.drawIndexed(num_indices, regs.num_instances.NumInstances(), 0, 0, 0); } 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.endRendering(); @@ -156,13 +172,15 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) { void Rasterizer::UpdateViewportScissorState() { 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 vk::Viewport viewport{ .x = regs.viewports[0].xoffset - regs.viewports[0].xscale, .y = regs.viewports[0].yoffset - regs.viewports[0].yscale, .width = regs.viewports[0].xscale * 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, }; const vk::Rect2D scissor{ diff --git a/src/video_core/texture_cache/image.cpp b/src/video_core/texture_cache/image.cpp index 9bf3ec0a..fc11e6cb 100644 --- a/src/video_core/texture_cache/image.cpp +++ b/src/video_core/texture_cache/image.cpp @@ -33,11 +33,23 @@ static vk::Format ConvertPixelFormat(const VideoOutFormat format) { 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) { vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled; - if (false /*&& IsDepthStencilFormat(format)*/) { + if (IsDepthStencilFormat(format)) { usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; } else { if (format != vk::Format::eBc3SrgbBlock) { @@ -54,9 +66,9 @@ static vk::ImageType ConvertImageType(AmdGpu::ImageType type) noexcept { case AmdGpu::ImageType::Color2D: case AmdGpu::ImageType::Color1DArray: case AmdGpu::ImageType::Cube: + case AmdGpu::ImageType::Color2DArray: return vk::ImageType::e2D; case AmdGpu::ImageType::Color3D: - case AmdGpu::ImageType::Color2DArray: return vk::ImageType::e3D; default: UNREACHABLE(); @@ -98,6 +110,18 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer, 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 { is_tiled = image.IsTiled(); tiling_mode = image.GetTilingMode(); @@ -165,6 +189,13 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, 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 = { .flags = flags, .imageType = info.type, @@ -187,7 +218,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, if (info.is_tiled) { ImageViewInfo view_info; 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); @@ -198,23 +229,25 @@ void Image::Transit(vk::ImageLayout dst_layout, vk::Flags ds return; } - const vk::ImageMemoryBarrier barrier = {.srcAccessMask = access_mask, - .dstAccessMask = dst_mask, - .oldLayout = layout, - .newLayout = dst_layout, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = image, - .subresourceRange{ - .aspectMask = aspect_mask, - .baseMipLevel = 0, - .levelCount = VK_REMAINING_MIP_LEVELS, - .baseArrayLayer = 0, - .layerCount = VK_REMAINING_ARRAY_LAYERS, - }}; + const vk::ImageMemoryBarrier barrier = { + .srcAccessMask = access_mask, + .dstAccessMask = dst_mask, + .oldLayout = layout, + .newLayout = dst_layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange{ + .aspectMask = aspect_mask, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }, + }; // Adjust pipieline stage - vk::PipelineStageFlags dst_pl_stage = + const vk::PipelineStageFlags dst_pl_stage = (dst_mask == vk::AccessFlagBits::eTransferRead || dst_mask == vk::AccessFlagBits::eTransferWrite) ? vk::PipelineStageFlagBits::eTransfer diff --git a/src/video_core/texture_cache/image.h b/src/video_core/texture_cache/image.h index c357f8a2..64bcfbd3 100644 --- a/src/video_core/texture_cache/image.h +++ b/src/video_core/texture_cache/image.h @@ -38,6 +38,8 @@ struct ImageInfo { explicit ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noexcept; explicit ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer, 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; bool is_tiled = false; diff --git a/src/video_core/texture_cache/image_view.cpp b/src/video_core/texture_cache/image_view.cpp index 919415e8..52fb28a4 100644 --- a/src/video_core/texture_cache/image_view.cpp +++ b/src/video_core/texture_cache/image_view.cpp @@ -3,6 +3,7 @@ #include "video_core/renderer_vulkan/liverpool_to_vk.h" #include "video_core/renderer_vulkan/vk_instance.h" +#include "video_core/texture_cache/image.h" #include "video_core/texture_cache/image_view.h" namespace VideoCore { @@ -58,7 +59,7 @@ ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image) noexcept { 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 usage_override /*= {}*/) : info{info_} { vk::ImageViewUsageCreateInfo usage_ci{}; @@ -66,14 +67,20 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info 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 = { .pNext = usage_override.has_value() ? &usage_ci : nullptr, - .image = image, + .image = image.image, .viewType = info.type, - .format = info.format, + .format = format, .components = info.mapping, .subresourceRange{ - .aspectMask = vk::ImageAspectFlagBits::eColor, + .aspectMask = image.aspect_mask, .baseMipLevel = 0U, .levelCount = 1, .baseArrayLayer = 0, diff --git a/src/video_core/texture_cache/image_view.h b/src/video_core/texture_cache/image_view.h index ae1f9ba0..2e15e1a1 100644 --- a/src/video_core/texture_cache/image_view.h +++ b/src/video_core/texture_cache/image_view.h @@ -28,8 +28,10 @@ struct ImageViewInfo { auto operator<=>(const ImageViewInfo&) const = default; }; +struct Image; + 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 usage_override = {}); ~ImageView(); diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 5c371112..fd6767b7 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -93,7 +93,7 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& ASSERT(null_id.index == 0); 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() { @@ -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}; boost::container::small_vector image_ids; 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]; - if (True(image.flags & ImageFlagBits::CpuModified)) { + if (True(image.flags & ImageFlagBits::CpuModified) && + (!image_ids.empty() || refresh_on_create)) { RefreshImage(image); TrackImage(image, image_id); } @@ -153,8 +154,7 @@ ImageView& TextureCache::RegisterImageView(Image& image, const ImageViewInfo& vi usage_override = image.info.usage & ~vk::ImageUsageFlagBits::eStorage; } - const ImageViewId view_id = - slot_image_views.insert(instance, view_info, image.image, usage_override); + const ImageViewId view_id = slot_image_views.insert(instance, view_info, image, usage_override); image.image_view_infos.emplace_back(view_info); image.image_view_ids.emplace_back(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 ImageInfo info{buffer, hint}; auto& image = FindImage(info, buffer.Address()); + image.flags &= ~ImageFlagBits::CpuModified; image.Transit(vk::ImageLayout::eColorAttachmentOptimal, vk::AccessFlagBits::eColorAttachmentWrite | @@ -187,6 +188,17 @@ ImageView& TextureCache::RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buff 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) { // Mark image as validated. image.flags &= ~ImageFlagBits::CpuModified; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index a4dbff73..20ae5bd5 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -37,7 +37,8 @@ public: void OnCpuWrite(VAddr 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. [[nodiscard]] ImageView& FindImageView(const AmdGpu::Image& image); @@ -45,6 +46,8 @@ public: /// Retrieves the render target with specified properties [[nodiscard]] ImageView& RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buffer, const AmdGpu::Liverpool::CbDbExtent& hint); + [[nodiscard]] ImageView& DepthTarget(const AmdGpu::Liverpool::DepthBuffer& buffer, + const AmdGpu::Liverpool::CbDbExtent& hint); /// Reuploads image contents. void RefreshImage(Image& image);