Initial instancing and asynchronous compute queues (#207)

* gnm_driver: added `sceGnmRegisterOwner` and `sceGnmRegisterResource`

* video_out: `sceVideoOutGetDeviceCapabilityInfo` for sdk runtime

* gnm_driver: correct vqid index range

* amdgpu: indirect buffer, release mem and some additional irq modes

* amdgpu: added ASC commands processor

* shader_recompiler: added support for fetch instance id

* amdgpu: classic bitfields for T# representation (debugging experience)

* renderer_vulkan: skip zero sized VBs from binding

* texture_cache: image upload logic moved into `Image` object

* gnm_driver: `sceGnmDingDong` implementation

* texture_cache: `Image` usage flags moved; correct VO buffer pitch
This commit is contained in:
psucien 2024-06-22 18:50:20 +02:00 committed by GitHub
parent a9cbd8287c
commit cb6b21de1f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 361 additions and 100 deletions

View file

@ -116,11 +116,13 @@ static vk::ImageType ConvertImageType(AmdGpu::ImageType type) noexcept {
ImageInfo::ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noexcept {
const auto& attrib = group.attrib;
is_tiled = attrib.tiling_mode == TilingMode::Tile;
tiling_mode =
is_tiled ? AmdGpu::TilingMode::Display_MacroTiled : AmdGpu::TilingMode::Display_Linear;
pixel_format = ConvertPixelFormat(attrib.pixel_format);
type = vk::ImageType::e2D;
size.width = attrib.width;
size.height = attrib.height;
pitch = attrib.tiling_mode == TilingMode::Linear ? size.width : (size.width + 127) >> 7;
pitch = attrib.tiling_mode == TilingMode::Linear ? size.width : (size.width + 127) & (~127);
const bool is_32bpp = attrib.pixel_format != VideoOutFormat::A16R16G16B16Float;
ASSERT(is_32bpp);
if (!is_tiled) {
@ -128,11 +130,11 @@ ImageInfo::ImageInfo(const Libraries::VideoOut::BufferAttributeGroup& group) noe
return;
}
if (Config::isNeoMode()) {
guest_size_bytes = pitch * 128 * ((size.height + 127) & (~127)) * 4;
guest_size_bytes = pitch * ((size.height + 127) & (~127)) * 4;
} else {
guest_size_bytes = pitch * 128 * ((size.height + 63) & (~63)) * 4;
guest_size_bytes = pitch * ((size.height + 63) & (~63)) * 4;
}
is_vo_surface = true;
usage.vo_buffer = true;
}
ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
@ -140,12 +142,14 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
is_tiled = buffer.IsTiled();
tiling_mode = buffer.GetTilingMode();
pixel_format = LiverpoolToVK::SurfaceFormat(buffer.info.format, buffer.NumFormat());
num_samples = 1 << buffer.attrib.num_fragments_log2;
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();
usage.render_target = true;
}
ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer,
@ -153,18 +157,20 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer,
is_tiled = false;
pixel_format = LiverpoolToVK::DepthFormat(buffer.z_info.format, buffer.stencil_info.format);
type = vk::ImageType::e2D;
num_samples = 1 << buffer.z_info.num_samples; // spec doesn't say it is a log2
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();
usage.depth_target = true;
}
ImageInfo::ImageInfo(const AmdGpu::Image& image) noexcept {
is_tiled = image.IsTiled();
tiling_mode = image.GetTilingMode();
pixel_format = LiverpoolToVK::SurfaceFormat(image.GetDataFmt(), image.GetNumberFmt());
type = ConvertImageType(image.type);
type = ConvertImageType(image.GetType());
size.width = image.width + 1;
size.height = image.height + 1;
size.depth = 1;
@ -222,7 +228,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
}
}
info.usage = ImageUsageFlags(info);
usage = ImageUsageFlags(info);
if (info.pixel_format == vk::Format::eD32Sfloat) {
aspect_mask = vk::ImageAspectFlagBits::eDepth;
@ -243,7 +249,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
.mipLevels = static_cast<u32>(info.resources.levels),
.arrayLayers = static_cast<u32>(info.resources.layers),
.tiling = vk::ImageTiling::eOptimal,
.usage = info.usage,
.usage = usage,
.initialLayout = vk::ImageLayout::eUndefined,
};
@ -296,6 +302,31 @@ void Image::Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits> ds
pl_stage = dst_pl_stage;
}
void Image::Upload(vk::Buffer buffer, u64 offset) {
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite);
// Copy to the image.
const vk::BufferImageCopy image_copy = {
.bufferOffset = offset,
.bufferRowLength = info.pitch,
.bufferImageHeight = info.size.height,
.imageSubresource{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.imageOffset = {0, 0, 0},
.imageExtent = {info.size.width, info.size.height, 1},
};
const auto cmdbuf = scheduler->CommandBuffer();
cmdbuf.copyBufferToImage(buffer, image, vk::ImageLayout::eTransferDstOptimal, image_copy);
Transit(vk::ImageLayout::eGeneral,
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead);
}
Image::~Image() = default;
} // namespace VideoCore

View file

@ -42,18 +42,28 @@ struct ImageInfo {
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept;
explicit ImageInfo(const AmdGpu::Image& image) noexcept;
bool IsTiled() const {
return tiling_mode != AmdGpu::TilingMode::Display_Linear;
}
bool IsBlockCoded() const;
bool IsPacked() const;
bool IsDepthStencil() const;
struct {
u32 texture : 1;
u32 storage : 1;
u32 render_target : 1;
u32 depth_target : 1;
u32 vo_buffer : 1;
} usage; // Usage data tracked during image lifetime
bool is_tiled = false;
bool is_storage = false;
bool is_vo_surface = false;
vk::Format pixel_format = vk::Format::eUndefined;
vk::ImageType type = vk::ImageType::e1D;
vk::ImageUsageFlags usage;
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};
@ -117,6 +127,7 @@ struct Image {
}
void Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits> dst_mask);
void Upload(vk::Buffer buffer, u64 offset);
const Vulkan::Instance* instance;
Vulkan::Scheduler* scheduler;
@ -131,6 +142,7 @@ struct Image {
std::optional<ImageView> view_for_detiler;
// Resource state tracking
vk::ImageUsageFlags usage;
vk::Flags<vk::PipelineStageFlagBits> pl_stage = vk::PipelineStageFlagBits::eAllCommands;
vk::Flags<vk::AccessFlagBits> access_mask = vk::AccessFlagBits::eNone;
vk::ImageLayout layout = vk::ImageLayout::eUndefined;

View file

@ -48,7 +48,7 @@ vk::ComponentSwizzle ConvertComponentSwizzle(u32 dst_sel) {
ImageViewInfo::ImageViewInfo(const AmdGpu::Image& image, bool is_storage) noexcept
: is_storage{is_storage} {
type = ConvertImageViewType(image.type);
type = ConvertImageViewType(image.GetType());
format = Vulkan::LiverpoolToVK::SurfaceFormat(image.GetDataFmt(), image.GetNumberFmt());
range.base.level = 0;
range.base.layer = 0;

View file

@ -151,7 +151,7 @@ ImageView& TextureCache::RegisterImageView(Image& image, const ImageViewInfo& vi
// temporary remove its storage bit.
std::optional<vk::ImageUsageFlags> usage_override;
if (!image.info.is_storage) {
usage_override = image.info.usage & ~vk::ImageUsageFlagBits::eStorage;
usage_override = image.usage & ~vk::ImageUsageFlagBits::eStorage;
}
const ImageViewId view_id = slot_image_views.insert(instance, view_info, image, usage_override);
@ -183,7 +183,7 @@ ImageView& TextureCache::RenderTarget(const AmdGpu::Liverpool::ColorBuffer& buff
vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eColorAttachmentRead);
ImageViewInfo view_info{buffer, image.info.is_vo_surface};
ImageViewInfo view_info{buffer, !!image.info.usage.vo_buffer};
return RegisterImageView(image, view_info);
}
@ -210,26 +210,8 @@ void TextureCache::RefreshImage(Image& image) {
if (!tile_manager.TryDetile(image)) {
// Upload data to the staging buffer.
const auto offset = staging.Copy(image.cpu_addr, image.info.guest_size_bytes, 4);
image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite);
// Copy to the image.
const vk::BufferImageCopy image_copy = {
.bufferOffset = offset,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.imageOffset = {0, 0, 0},
.imageExtent = {image.info.size.width, image.info.size.height, 1},
};
const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.copyBufferToImage(staging.Handle(), image.image,
vk::ImageLayout::eTransferDstOptimal, image_copy);
image.Upload(staging.Handle(), offset);
}
image.Transit(vk::ImageLayout::eGeneral,

View file

@ -15,7 +15,6 @@
#include <boost/container/static_vector.hpp>
#include <magic_enum.hpp>
#include <vulkan/vulkan_to_string.hpp>
namespace VideoCore {