mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-02 16:53:17 +00:00
video_core: Add image support
This commit is contained in:
parent
729e166cd3
commit
d59b102b6f
48 changed files with 1264 additions and 259 deletions
|
@ -44,6 +44,22 @@ using Libraries::VideoOut::TilingMode;
|
|||
return usage;
|
||||
}
|
||||
|
||||
[[nodiscard]] vk::ImageType ConvertImageType(AmdGpu::ImageType type) noexcept {
|
||||
switch (type) {
|
||||
case AmdGpu::ImageType::Color1D:
|
||||
return vk::ImageType::e1D;
|
||||
case AmdGpu::ImageType::Color2D:
|
||||
case AmdGpu::ImageType::Color1DArray:
|
||||
case AmdGpu::ImageType::Cube:
|
||||
return vk::ImageType::e2D;
|
||||
case AmdGpu::ImageType::Color3D:
|
||||
case AmdGpu::ImageType::Color2DArray:
|
||||
return vk::ImageType::e3D;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
ImageInfo::ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noexcept {
|
||||
const auto& attrib = group.attrib;
|
||||
is_tiled = attrib.tiling_mode == TilingMode::Tile;
|
||||
|
@ -72,10 +88,23 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer) noexcept {
|
|||
type = vk::ImageType::e2D;
|
||||
size.width = buffer.Pitch();
|
||||
size.height = buffer.Height();
|
||||
size.depth = 1;
|
||||
pitch = size.width;
|
||||
guest_size_bytes = buffer.slice.tile_max * (buffer.view.slice_max + 1);
|
||||
}
|
||||
|
||||
ImageInfo::ImageInfo(const AmdGpu::Image& image) noexcept {
|
||||
is_tiled = false;
|
||||
pixel_format = LiverpoolToVK::SurfaceFormat(image.GetDataFmt(), image.GetNumberFmt());
|
||||
type = ConvertImageType(image.type);
|
||||
size.width = image.width + 1;
|
||||
size.height = image.height + 1;
|
||||
size.depth = 1;
|
||||
// TODO: Derive this properly from tiling params
|
||||
pitch = size.width;
|
||||
guest_size_bytes = size.width * size.height * 4;
|
||||
}
|
||||
|
||||
UniqueImage::UniqueImage(vk::Device device_, VmaAllocator allocator_)
|
||||
: device{device_}, allocator{allocator_} {}
|
||||
|
||||
|
@ -109,7 +138,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
|
|||
: instance{&instance_}, scheduler{&scheduler_}, info{info_},
|
||||
image{instance->GetDevice(), instance->GetAllocator()}, cpu_addr{cpu_addr},
|
||||
cpu_addr_end{cpu_addr + info.guest_size_bytes} {
|
||||
vk::ImageCreateFlags flags{};
|
||||
vk::ImageCreateFlags flags{vk::ImageCreateFlagBits::eMutableFormat};
|
||||
if (info.type == vk::ImageType::e2D && info.resources.layers >= 6 &&
|
||||
info.size.width == info.size.height) {
|
||||
flags |= vk::ImageCreateFlagBits::eCubeCompatible;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "common/types.h"
|
||||
#include "core/libraries/videoout/buffer.h"
|
||||
#include "video_core/amdgpu/liverpool.h"
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
#include "video_core/renderer_vulkan/vk_common.h"
|
||||
#include "video_core/texture_cache/image_view.h"
|
||||
#include "video_core/texture_cache/types.h"
|
||||
|
@ -34,6 +35,7 @@ struct ImageInfo {
|
|||
ImageInfo() = default;
|
||||
explicit ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noexcept;
|
||||
explicit ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer) noexcept;
|
||||
explicit ImageInfo(const AmdGpu::Image& image) noexcept;
|
||||
|
||||
bool is_tiled = false;
|
||||
vk::Format pixel_format = vk::Format::eUndefined;
|
||||
|
|
|
@ -1,11 +1,62 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#include "video_core/texture_cache/image_view.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
vk::ImageViewType ConvertImageViewType(AmdGpu::ImageType type) {
|
||||
switch (type) {
|
||||
case AmdGpu::ImageType::Color1D:
|
||||
return vk::ImageViewType::e1D;
|
||||
case AmdGpu::ImageType::Color1DArray:
|
||||
return vk::ImageViewType::e1DArray;
|
||||
case AmdGpu::ImageType::Color2D:
|
||||
case AmdGpu::ImageType::Cube:
|
||||
return vk::ImageViewType::e2D;
|
||||
case AmdGpu::ImageType::Color2DArray:
|
||||
return vk::ImageViewType::e2DArray;
|
||||
case AmdGpu::ImageType::Color3D:
|
||||
return vk::ImageViewType::e3D;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
vk::ComponentSwizzle ConvertComponentSwizzle(u32 dst_sel) {
|
||||
switch (dst_sel) {
|
||||
case 0:
|
||||
return vk::ComponentSwizzle::eZero;
|
||||
case 1:
|
||||
return vk::ComponentSwizzle::eOne;
|
||||
case 4:
|
||||
return vk::ComponentSwizzle::eR;
|
||||
case 5:
|
||||
return vk::ComponentSwizzle::eG;
|
||||
case 6:
|
||||
return vk::ComponentSwizzle::eB;
|
||||
case 7:
|
||||
return vk::ComponentSwizzle::eA;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image) noexcept {
|
||||
type = ConvertImageViewType(image.type);
|
||||
format = Vulkan::LiverpoolToVK::SurfaceFormat(image.GetDataFmt(), image.GetNumberFmt());
|
||||
range.base.level = image.base_level;
|
||||
range.base.layer = 0;
|
||||
range.extent.levels = 1;
|
||||
range.extent.layers = 1;
|
||||
mapping.r = ConvertComponentSwizzle(image.dst_sel_x);
|
||||
mapping.g = ConvertComponentSwizzle(image.dst_sel_y);
|
||||
mapping.b = ConvertComponentSwizzle(image.dst_sel_z);
|
||||
mapping.a = ConvertComponentSwizzle(image.dst_sel_w);
|
||||
}
|
||||
|
||||
ImageView::ImageView(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,
|
||||
const ImageViewInfo& info_, vk::Image image)
|
||||
: info{info_} {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
#include "video_core/renderer_vulkan/vk_common.h"
|
||||
#include "video_core/texture_cache/types.h"
|
||||
|
||||
|
@ -14,6 +15,9 @@ class Scheduler;
|
|||
namespace VideoCore {
|
||||
|
||||
struct ImageViewInfo {
|
||||
explicit ImageViewInfo() = default;
|
||||
explicit ImageViewInfo(const AmdGpu::Image& image) noexcept;
|
||||
|
||||
vk::ImageViewType type = vk::ImageViewType::e2D;
|
||||
vk::Format format = vk::Format::eR8G8B8A8Unorm;
|
||||
SubresourceRange range;
|
||||
|
|
32
src/video_core/texture_cache/sampler.cpp
Normal file
32
src/video_core/texture_cache/sampler.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#include "video_core/texture_cache/sampler.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler) {
|
||||
using namespace Vulkan;
|
||||
const vk::SamplerCreateInfo sampler_ci = {
|
||||
.magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter),
|
||||
.minFilter = LiverpoolToVK::Filter(sampler.xy_min_filter),
|
||||
.mipmapMode = LiverpoolToVK::MipFilter(sampler.mip_filter),
|
||||
.addressModeU = LiverpoolToVK::ClampMode(sampler.clamp_x),
|
||||
.addressModeV = LiverpoolToVK::ClampMode(sampler.clamp_y),
|
||||
.addressModeW = LiverpoolToVK::ClampMode(sampler.clamp_z),
|
||||
.mipLodBias = sampler.LodBias(),
|
||||
.compareEnable = sampler.depth_compare_func != AmdGpu::DepthCompare::Never,
|
||||
.compareOp = LiverpoolToVK::DepthCompare(sampler.depth_compare_func),
|
||||
.minLod = sampler.MinLod(),
|
||||
.maxLod = sampler.MaxLod(),
|
||||
.borderColor = LiverpoolToVK::BorderColor(sampler.border_color_type),
|
||||
.unnormalizedCoordinates = bool(sampler.force_unnormalized),
|
||||
};
|
||||
handle = instance.GetDevice().createSamplerUnique(sampler_ci);
|
||||
}
|
||||
|
||||
Sampler::~Sampler() = default;
|
||||
|
||||
} // namespace VideoCore
|
34
src/video_core/texture_cache/sampler.h
Normal file
34
src/video_core/texture_cache/sampler.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
#include "video_core/renderer_vulkan/vk_common.h"
|
||||
|
||||
namespace Vulkan {
|
||||
class Instance;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
class Sampler {
|
||||
public:
|
||||
explicit Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler);
|
||||
~Sampler();
|
||||
|
||||
Sampler(const Sampler&) = delete;
|
||||
Sampler& operator=(const Sampler&) = delete;
|
||||
|
||||
Sampler(Sampler&&) = default;
|
||||
Sampler& operator=(Sampler&&) = default;
|
||||
|
||||
vk::Sampler Handle() const noexcept {
|
||||
return *handle;
|
||||
}
|
||||
|
||||
private:
|
||||
vk::UniqueSampler handle;
|
||||
};
|
||||
|
||||
} // namespace VideoCore
|
|
@ -1,10 +1,9 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <limits>
|
||||
#include <xxhash.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "core/libraries/videoout/buffer.h"
|
||||
#include "core/virtual_memory.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/texture_cache/texture_cache.h"
|
||||
|
@ -137,6 +136,21 @@ Image& TextureCache::FindImage(const ImageInfo& info, VAddr cpu_address) {
|
|||
return image;
|
||||
}
|
||||
|
||||
ImageView& TextureCache::FindImageView(const AmdGpu::Image& desc) {
|
||||
Image& image = FindImage(ImageInfo{desc}, desc.Address());
|
||||
|
||||
const ImageViewInfo view_info{desc};
|
||||
if (const ImageViewId view_id = image.FindView(view_info); view_id) {
|
||||
return slot_image_views[view_id];
|
||||
}
|
||||
|
||||
const ImageViewId view_id =
|
||||
slot_image_views.insert(instance, scheduler, view_info, image.image);
|
||||
image.image_view_infos.emplace_back(view_info);
|
||||
image.image_view_ids.emplace_back(view_id);
|
||||
return slot_image_views[view_id];
|
||||
}
|
||||
|
||||
ImageView& TextureCache::RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||
const ImageInfo info{buffer};
|
||||
auto& image = FindImage(info, buffer.Address());
|
||||
|
@ -159,7 +173,7 @@ void TextureCache::RefreshImage(Image& image) {
|
|||
image.flags &= ~ImageFlagBits::CpuModified;
|
||||
|
||||
// Upload data to the staging buffer.
|
||||
const auto [data, offset, _] = staging.Map(image.info.guest_size_bytes, 0);
|
||||
const auto [data, offset, _] = staging.Map(image.info.guest_size_bytes, 4);
|
||||
const u8* image_data = reinterpret_cast<const u8*>(image.cpu_addr);
|
||||
if (image.info.is_tiled) {
|
||||
ConvertTileToLinear(data, image_data, image.info.size.width, image.info.size.height,
|
||||
|
@ -202,6 +216,12 @@ void TextureCache::RefreshImage(Image& image) {
|
|||
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead);
|
||||
}
|
||||
|
||||
vk::Sampler TextureCache::GetSampler(const AmdGpu::Sampler& sampler) {
|
||||
const u64 hash = XXH3_64bits(&sampler, sizeof(sampler));
|
||||
const auto [it, new_sampler] = samplers.try_emplace(hash, instance, sampler);
|
||||
return it->second.Handle();
|
||||
}
|
||||
|
||||
void TextureCache::RegisterImage(ImageId image_id) {
|
||||
Image& image = slot_images[image_id];
|
||||
ASSERT_MSG(False(image.flags & ImageFlagBits::Registered),
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
#include <boost/icl/interval_map.hpp>
|
||||
#include <tsl/robin_map.h>
|
||||
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
|
||||
#include "video_core/texture_cache/image.h"
|
||||
#include "video_core/texture_cache/image_view.h"
|
||||
#include "video_core/texture_cache/sampler.h"
|
||||
#include "video_core/texture_cache/slot_vector.h"
|
||||
|
||||
namespace Core::Libraries::VideoOut {
|
||||
|
@ -36,12 +38,18 @@ public:
|
|||
/// Retrieves the image handle of the image with the provided attributes and address.
|
||||
Image& FindImage(const ImageInfo& info, VAddr cpu_address);
|
||||
|
||||
/// Retrieves an image view with the properties of the specified image descriptor.
|
||||
ImageView& FindImageView(const AmdGpu::Image& image);
|
||||
|
||||
/// Retrieves the render target with specified properties
|
||||
ImageView& RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buffer);
|
||||
|
||||
/// Reuploads image contents.
|
||||
void RefreshImage(Image& image);
|
||||
|
||||
/// Retrieves the sampler that matches the provided S# descriptor.
|
||||
vk::Sampler GetSampler(const AmdGpu::Sampler& sampler);
|
||||
|
||||
private:
|
||||
/// Iterate over all page indices in a range
|
||||
template <typename Func>
|
||||
|
@ -121,6 +129,7 @@ private:
|
|||
Vulkan::StreamBuffer staging;
|
||||
SlotVector<Image> slot_images;
|
||||
SlotVector<ImageView> slot_image_views;
|
||||
tsl::robin_map<u64, Sampler> samplers;
|
||||
tsl::robin_pg_map<u64, std::vector<ImageId>> page_table;
|
||||
boost::icl::interval_map<VAddr, s32> cached_pages;
|
||||
#ifdef _WIN64
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "video_core/texture_cache/tile_manager.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue