diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 6d498c759..098f14d9b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -182,8 +182,9 @@ bool RendererVulkan::ShowSplash(Frame* frame /*= nullptr*/) { info.size = VideoCore::Extent3D{splash->GetImageInfo().width, splash->GetImageInfo().height, 1}; info.pitch = splash->GetImageInfo().width; + info.guest_address = VAddr(splash->GetImageData().data()); info.guest_size_bytes = splash->GetImageData().size(); - splash_img.emplace(instance, scheduler, info, VAddr(splash->GetImageData().data())); + splash_img.emplace(instance, scheduler, info); texture_cache.RefreshImage(*splash_img); } frame = PrepareFrameInternal(*splash_img); diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index bf5d220b3..701d3d14b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -40,7 +40,7 @@ public: Frame* PrepareFrame(const Libraries::VideoOut::BufferAttributeGroup& attribute, VAddr cpu_address) { - const auto info = VideoCore::ImageInfo{attribute}; + const auto info = VideoCore::ImageInfo{attribute, cpu_address}; const auto image_id = texture_cache.FindImage(info, cpu_address); auto& image = texture_cache.GetImage(image_id); return PrepareFrameInternal(image); @@ -54,7 +54,7 @@ public: VideoCore::Image& RegisterVideoOutSurface( const Libraries::VideoOut::BufferAttributeGroup& attribute, VAddr cpu_address) { vo_buffers_addr.emplace_back(cpu_address); - const auto info = VideoCore::ImageInfo{attribute}; + const auto info = VideoCore::ImageInfo{attribute, cpu_address}; const auto image_id = texture_cache.FindImage(info, cpu_address); return texture_cache.GetImage(image_id); } diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index f70e49a72..954adf448 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -128,7 +128,7 @@ bool ComputePipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& s for (const auto& image_desc : info.images) { const auto tsharp = info.ReadUd(image_desc.sgpr_base, image_desc.dword_offset); - const auto& image_view = texture_cache.FindImageView(tsharp, image_desc.is_storage); + const auto& image_view = texture_cache.FindTexture(tsharp, image_desc.is_storage); const auto& image = texture_cache.GetImage(image_view.image_id); image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view, image.layout); set_writes.push_back({ diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index a3ba2f77b..f119bc770 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -366,7 +366,7 @@ void GraphicsPipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& for (const auto& image_desc : stage.images) { const auto& tsharp = tsharps.emplace_back( stage.ReadUd(image_desc.sgpr_base, image_desc.dword_offset)); - const auto& image_view = texture_cache.FindImageView(tsharp, image_desc.is_storage); + const auto& image_view = texture_cache.FindTexture(tsharp, image_desc.is_storage); const auto& image = texture_cache.GetImage(image_view.image_id); image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view, image.layout); set_writes.push_back({ diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f98e890f2..fe52d0741 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -113,7 +113,7 @@ void Rasterizer::BeginRendering() { } const auto& hint = liverpool->last_cb_extent[col_buf_id]; - const auto& image_view = texture_cache.RenderTarget(col_buf, hint); + const auto& image_view = texture_cache.FindRenderTarget(col_buf, hint); const auto& image = texture_cache.GetImage(image_view.image_id); state.width = std::min(state.width, image.info.size.width); state.height = std::min(state.height, image.info.size.height); @@ -136,8 +136,9 @@ void Rasterizer::BeginRendering() { const bool is_clear = regs.depth_render_control.depth_clear_enable || texture_cache.IsMetaCleared(htile_address); const auto& hint = liverpool->last_db_extent; - const auto& image_view = texture_cache.DepthTarget(regs.depth_buffer, htile_address, hint, - regs.depth_control.depth_write_enable); + const auto& image_view = texture_cache.FindDepthTarget( + regs.depth_buffer, regs.depth_view.NumSlices(), htile_address, hint, + regs.depth_control.depth_write_enable); const auto& image = texture_cache.GetImage(image_view.image_id); state.width = std::min(state.width, image.info.size.width); state.height = std::min(state.height, image.info.size.height); diff --git a/src/video_core/texture_cache/image.cpp b/src/video_core/texture_cache/image.cpp index f4ba2088c..2b4447740 100644 --- a/src/video_core/texture_cache/image.cpp +++ b/src/video_core/texture_cache/image.cpp @@ -112,9 +112,9 @@ void UniqueImage::Create(const vk::ImageCreateInfo& image_ci) { } Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, - const ImageInfo& info_, VAddr cpu_addr) + const ImageInfo& info_) : instance{&instance_}, scheduler{&scheduler_}, info{info_}, - image{instance->GetDevice(), instance->GetAllocator()}, cpu_addr{cpu_addr}, + image{instance->GetDevice(), instance->GetAllocator()}, cpu_addr{info.guest_address}, cpu_addr_end{cpu_addr + info.guest_size_bytes} { ASSERT(info.pixel_format != vk::Format::eUndefined); vk::ImageCreateFlags flags{vk::ImageCreateFlagBits::eMutableFormat | diff --git a/src/video_core/texture_cache/image.h b/src/video_core/texture_cache/image.h index fceeddf99..97ceaa098 100644 --- a/src/video_core/texture_cache/image.h +++ b/src/video_core/texture_cache/image.h @@ -69,8 +69,7 @@ private: constexpr Common::SlotId NULL_IMAGE_ID{0}; struct Image { - explicit Image(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, - const ImageInfo& info, VAddr cpu_addr); + Image(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, const ImageInfo& info); ~Image(); Image(const Image&) = delete; diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index 12df14c01..2839ec225 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp @@ -44,7 +44,8 @@ static vk::ImageType ConvertImageType(AmdGpu::ImageType type) noexcept { } } -ImageInfo::ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noexcept { +ImageInfo::ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group, + VAddr cpu_address) noexcept { const auto& attrib = group.attrib; is_tiled = attrib.tiling_mode == TilingMode::Tile; tiling_mode = @@ -56,14 +57,16 @@ ImageInfo::ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noe pitch = attrib.tiling_mode == TilingMode::Linear ? size.width : (size.width + 127) & (~127); const bool is_32bpp = attrib.pixel_format != VideoOutFormat::A16R16G16B16Float; ASSERT(is_32bpp); + + guest_address = cpu_address; if (!is_tiled) { guest_size_bytes = pitch * size.height * 4; - return; - } - if (Config::isNeoMode()) { - guest_size_bytes = pitch * ((size.height + 127) & (~127)) * 4; } else { - guest_size_bytes = pitch * ((size.height + 63) & (~63)) * 4; + if (Config::isNeoMode()) { + guest_size_bytes = pitch * ((size.height + 127) & (~127)) * 4; + } else { + guest_size_bytes = pitch * ((size.height + 63) & (~63)) * 4; + } } usage.vo_buffer = true; } @@ -79,14 +82,17 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer, size.height = hint.Valid() ? hint.height : buffer.Height(); size.depth = 1; pitch = size.width; - guest_size_bytes = buffer.GetColorSliceSize(); + resources.layers = buffer.NumSlices(); meta_info.cmask_addr = buffer.info.fast_clear ? buffer.CmaskAddress() : 0; meta_info.fmask_addr = buffer.info.compression ? buffer.FmaskAddress() : 0; usage.render_target = true; + + guest_address = buffer.Address(); + guest_size_bytes = buffer.GetColorSliceSize() * buffer.NumSlices(); } -ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, VAddr htile_address, - const AmdGpu::Liverpool::CbDbExtent& hint) noexcept { +ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, + VAddr htile_address, 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; @@ -95,9 +101,12 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, VAddr htile_a size.height = hint.Valid() ? hint.height : buffer.Height(); size.depth = 1; pitch = size.width; - guest_size_bytes = buffer.GetDepthSliceSize(); + resources.layers = num_slices; meta_info.htile_addr = buffer.z_info.tile_surface_en ? htile_address : 0; usage.depth_target = true; + + guest_address = buffer.Address(); + guest_size_bytes = buffer.GetDepthSliceSize() * num_slices; } ImageInfo::ImageInfo(const AmdGpu::Image& image) noexcept { @@ -111,8 +120,11 @@ ImageInfo::ImageInfo(const AmdGpu::Image& image) noexcept { pitch = image.Pitch(); resources.levels = image.NumLevels(); resources.layers = image.NumLayers(); - guest_size_bytes = image.GetSize(); + is_cube = image.GetType() == AmdGpu::ImageType::Cube; usage.texture = true; + + guest_address = image.Address(); + guest_size_bytes = image.GetSize(); } } // namespace VideoCore diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h index a473896c1..60961b440 100644 --- a/src/video_core/texture_cache/image_info.h +++ b/src/video_core/texture_cache/image_info.h @@ -13,12 +13,12 @@ namespace VideoCore { struct ImageInfo { ImageInfo() = default; - 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, VAddr htile_address, - const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept; - explicit ImageInfo(const AmdGpu::Image& image) noexcept; + ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group, VAddr cpu_address) noexcept; + ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer, + const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept; + ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, VAddr htile_address, + const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept; + ImageInfo(const AmdGpu::Image& image) noexcept; bool IsTiled() const { return tiling_mode != AmdGpu::TilingMode::Display_Linear; @@ -42,15 +42,18 @@ struct ImageInfo { u32 vo_buffer : 1; } usage{}; // Usage data tracked during image lifetime + bool is_cube = false; bool is_tiled = false; + bool is_read_only = false; vk::Format pixel_format = vk::Format::eUndefined; vk::ImageType type = vk::ImageType::e1D; SubresourceExtent resources; Extent3D size{1, 1, 1}; u32 num_samples = 1; u32 pitch = 0; - u32 guest_size_bytes = 0; AmdGpu::TilingMode tiling_mode{AmdGpu::TilingMode::Display_Linear}; + VAddr guest_address{0}; + u32 guest_size_bytes{0}; }; } // namespace VideoCore diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 8cd6f8930..70ddb8d5f 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -89,7 +89,7 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& ImageInfo info; info.pixel_format = vk::Format::eR8G8B8A8Unorm; info.type = vk::ImageType::e2D; - const ImageId null_id = slot_images.insert(instance, scheduler, info, 0); + const ImageId null_id = slot_images.insert(instance, scheduler, info); ASSERT(null_id.index == 0); ImageViewInfo view_info; @@ -112,26 +112,27 @@ void TextureCache::OnCpuWrite(VAddr address) { }); } -ImageId TextureCache::FindImage(const ImageInfo& info, VAddr cpu_address, bool refresh_on_create) { +ImageId TextureCache::FindImage(const ImageInfo& info, 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) { - // Address and width must match. - if (image.cpu_addr != cpu_address || image.info.size.width != info.size.width) { - return; - } - if (info.IsDepthStencil() != image.info.IsDepthStencil() && - info.pixel_format != vk::Format::eR32Sfloat) { - return; - } - image_ids.push_back(image_id); - }); + ForEachImageInRegion( + info.guest_address, info.guest_size_bytes, [&](ImageId image_id, Image& image) { + // Address and width must match. + if (image.cpu_addr != info.guest_address || image.info.size.width != info.size.width) { + return; + } + if (info.IsDepthStencil() != image.info.IsDepthStencil() && + info.pixel_format != vk::Format::eR32Sfloat) { + return; + } + image_ids.push_back(image_id); + }); ASSERT_MSG(image_ids.size() <= 1, "Overlapping images not allowed!"); ImageId image_id{}; if (image_ids.empty()) { - image_id = slot_images.insert(instance, scheduler, info, cpu_address); + image_id = slot_images.insert(instance, scheduler, info); RegisterImage(image_id); } else { image_id = image_ids[0]; @@ -169,9 +170,9 @@ ImageView& TextureCache::RegisterImageView(ImageId image_id, const ImageViewInfo return slot_image_views[view_id]; } -ImageView& TextureCache::FindImageView(const AmdGpu::Image& desc, bool is_storage) { +ImageView& TextureCache::FindTexture(const AmdGpu::Image& desc, bool is_storage) { const ImageInfo info{desc}; - const ImageId image_id = FindImage(info, desc.Address()); + const ImageId image_id = FindImage(info); Image& image = slot_images[image_id]; auto& usage = image.info.usage; @@ -190,10 +191,10 @@ ImageView& TextureCache::FindImageView(const AmdGpu::Image& desc, bool is_storag return RegisterImageView(image_id, view_info); } -ImageView& TextureCache::RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buffer, - const AmdGpu::Liverpool::CbDbExtent& hint) { +ImageView& TextureCache::FindRenderTarget(const AmdGpu::Liverpool::ColorBuffer& buffer, + const AmdGpu::Liverpool::CbDbExtent& hint) { const ImageInfo info{buffer, hint}; - const ImageId image_id = FindImage(info, buffer.Address()); + const ImageId image_id = FindImage(info); Image& image = slot_images[image_id]; image.flags &= ~ImageFlagBits::CpuModified; @@ -207,11 +208,12 @@ ImageView& TextureCache::RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buff return RegisterImageView(image_id, view_info); } -ImageView& TextureCache::DepthTarget(const AmdGpu::Liverpool::DepthBuffer& buffer, - VAddr htile_address, const AmdGpu::Liverpool::CbDbExtent& hint, - bool write_enabled) { - const ImageInfo info{buffer, htile_address, hint}; - const ImageId image_id = FindImage(info, buffer.Address(), false); +ImageView& TextureCache::FindDepthTarget(const AmdGpu::Liverpool::DepthBuffer& buffer, + u32 num_slices, VAddr htile_address, + const AmdGpu::Liverpool::CbDbExtent& hint, + bool write_enabled) { + const ImageInfo info{buffer, num_slices, htile_address, hint}; + const ImageId image_id = FindImage(info, false); Image& image = slot_images[image_id]; 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 421651ff3..8a6189835 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -47,20 +47,21 @@ public: /// Invalidates any image in the logical page range. void OnCpuWrite(VAddr address); - /// Retrieves the image handle of the image with the provided attributes and address. - [[nodiscard]] ImageId FindImage(const ImageInfo& info, VAddr cpu_address, - bool refresh_on_create = true); + /// Retrieves the image handle of the image with the provided attributes. + [[nodiscard]] ImageId FindImage(const ImageInfo& info, bool refresh_on_create = true); /// Retrieves an image view with the properties of the specified image descriptor. - [[nodiscard]] ImageView& FindImageView(const AmdGpu::Image& image, bool is_storage); + [[nodiscard]] ImageView& FindTexture(const AmdGpu::Image& image, bool is_storage); /// 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, - VAddr htile_address, - const AmdGpu::Liverpool::CbDbExtent& hint, - bool write_enabled); + [[nodiscard]] ImageView& FindRenderTarget(const AmdGpu::Liverpool::ColorBuffer& buffer, + const AmdGpu::Liverpool::CbDbExtent& hint); + + /// Retrieves the depth target with specified properties + [[nodiscard]] ImageView& FindDepthTarget(const AmdGpu::Liverpool::DepthBuffer& buffer, + u32 num_slices, VAddr htile_address, + const AmdGpu::Liverpool::CbDbExtent& hint, + bool write_enabled); /// Reuploads image contents. void RefreshImage(Image& image);