Port UMA part 2

This commit is contained in:
CamilleLaVey
2026-10-01 01:09:01 -04:00
parent 0a88e761eb
commit 9cc9a1fc35
7 changed files with 120 additions and 16 deletions
@@ -283,11 +283,13 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
[[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator,
const ImageInfo& info, std::span<const VkFormat> view_formats,
std::optional<VkFormat> format_override = {}) {
std::optional<VkFormat> format_override = {},
VkImageUsageFlags host_usage = 0) {
if (info.type == ImageType::Buffer) {
return vk::Image{};
}
VkImageCreateInfo image_ci = MakeImageCreateInfo(device, info, format_override);
image_ci.usage |= host_usage;
const VkImageFormatListCreateInfo image_format_list = {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO,
.pNext = nullptr,
@@ -1042,6 +1044,17 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
pitch_unswizzle_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
compute_pass_descriptor_queue);
}
for (size_t index = 0; index < VideoCore::Surface::MaxPixelFormat; index++) {
const auto format = static_cast<PixelFormat>(index);
if (!device.IsHostImageCopySupported() || DefaultBlockWidth(format) == 1) {
continue;
}
const VkFormat vk_format =
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format).format;
host_copy_formats[index] =
(device.GetPhysical().GetFormatProperties3(vk_format).optimalTilingFeatures &
VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT) != 0;
}
if (!device.IsKhrImageFormatListSupported()) {
return;
}
@@ -1968,10 +1981,7 @@ void TextureCacheRuntime::TickFrame() {
Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_,
VAddr cpu_addr_)
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler},
runtime{&runtime_},
original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info,
runtime->ViewFormats(info.format))),
aspect_mask(ImageAspectMask(info.format)) {
runtime{&runtime_}, aspect_mask(ImageAspectMask(info.format)) {
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
switch (Settings::values.accelerate_astc.GetValue()) {
case Settings::AstcDecodeMode::Gpu:
@@ -1997,6 +2007,13 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
WillUseAcceleratedUnswizzle(runtime->device, info)) {
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
}
VkImageUsageFlags host_usage{};
if (False(flags & VideoCommon::ImageFlagBits::Converted) &&
runtime->host_copy_formats[static_cast<size_t>(info.format)]) {
host_usage = VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
}
original_image = MakeImage(runtime->device, runtime->memory_allocator, info,
runtime->ViewFormats(info.format), {}, host_usage);
if (runtime->device.HasDebuggingToolAttached()) {
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
}
@@ -2130,6 +2147,33 @@ void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImag
UploadMemory(map.buffer, map.offset, copies);
}
void Image::UploadHostMemory(std::span<const u8> memory,
std::span<const BufferImageCopy> copies) {
const auto vk_copies = TransformBufferImageCopies(copies, 0, aspect_mask);
boost::container::small_vector<VkMemoryToImageCopyEXT, 16> regions;
for (const VkBufferImageCopy2& copy : vk_copies) {
regions.push_back(VkMemoryToImageCopyEXT{
.sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT,
.pNext = nullptr,
.pHostPointer = memory.data() + copy.bufferOffset,
.memoryRowLength = copy.bufferRowLength,
.memoryImageHeight = copy.bufferImageHeight,
.imageSubresource = copy.imageSubresource,
.imageOffset = copy.imageOffset,
.imageExtent = copy.imageExtent,
});
}
runtime->device.GetLogical().CopyMemoryToImageEXT(VkCopyMemoryToImageInfoEXT{
.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT,
.pNext = nullptr,
.flags = 0,
.dstImage = *original_image,
.dstImageLayout = VK_IMAGE_LAYOUT_GENERAL,
.regionCount = static_cast<u32>(regions.size()),
.pRegions = regions.data(),
});
}
void Image::DownloadMemory(VkBuffer buffer, size_t offset,
std::span<const VideoCommon::BufferImageCopy> copies) {
std::array buffer_handles{
@@ -3177,9 +3221,27 @@ void TextureCacheRuntime::AccelerateImageUpload(
}
void TextureCacheRuntime::TransitionImageLayout(Image& image) {
if (!image.ExchangeInitialization()) {
RecordInitialLayout(scheduler, image.Handle(), image.AspectMask());
if (image.ExchangeInitialization()) {
return;
}
if (!image.CanUploadHostMemory()) {
RecordInitialLayout(scheduler, image.Handle(), image.AspectMask());
return;
}
device.GetLogical().TransitionImageLayoutEXT(VkHostImageLayoutTransitionInfoEXT{
.sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
.pNext = nullptr,
.image = image.Handle(),
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.subresourceRange{
.aspectMask = image.AspectMask(),
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
});
}
} // namespace Vulkan
@@ -6,6 +6,7 @@
#pragma once
#include <bitset>
#include <span>
#include "video_core/texture_cache/texture_cache_base.h"
@@ -154,6 +155,7 @@ public:
std::optional<PitchUnswizzlePass> pitch_unswizzle_pass;
const Settings::ResolutionScalingInfo& resolution;
std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;
std::bitset<VideoCore::Surface::MaxPixelFormat> host_copy_formats;
static constexpr size_t indexing_slots = 8 * sizeof(size_t);
std::array<vk::Buffer, indexing_slots> buffers{};
@@ -294,6 +296,13 @@ public:
void UploadMemory(const StagingBufferRef& map,
std::span<const VideoCommon::BufferImageCopy> copies);
void UploadHostMemory(std::span<const u8> memory,
std::span<const VideoCommon::BufferImageCopy> copies);
[[nodiscard]] bool CanUploadHostMemory() const noexcept {
return (original_image.UsageFlags() & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) != 0;
}
void DownloadMemory(VkBuffer buffer, size_t offset,
std::span<const VideoCommon::BufferImageCopy> copies);
@@ -1033,6 +1033,18 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
QueueAsyncDecode(image, image_id);
return;
}
if constexpr (requires { image.UploadHostMemory(unswizzle_data_buffer, {}); }) {
if (True(image.flags & ImageFlagBits::ReorderableUpload) && image.CanUploadHostMemory()) {
Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead>
swizzle_data(*gpu_memory, image.gpu_addr, image.guest_size_bytes,
&swizzle_data_buffer);
unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes);
const auto copies = FixSmallVectorADL(UnswizzleImage(
*gpu_memory, image.gpu_addr, image.info, swizzle_data, unswizzle_data_buffer));
image.UploadHostMemory(unswizzle_data_buffer, copies);
return;
}
}
auto staging = runtime.UploadStagingBuffer(MapSizeBytes(image));
UploadImageContents(image, staging);
+13 -9
View File
@@ -433,6 +433,13 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
const vk::InstanceDispatch& dld_)
: instance{instance_}, dld{dld_}, physical{physical_},
format_properties(GetFormatProperties(physical)) {
const VkPhysicalDeviceMemoryProperties memory_properties =
physical.GetMemoryProperties().memoryProperties;
is_uma = std::all_of(memory_properties.memoryTypes,
memory_properties.memoryTypes + memory_properties.memoryTypeCount,
[](const VkMemoryType& type) {
return (type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0;
});
// Get suitability and device properties.
const bool is_suitable = GetSuitability(surface != VkSurfaceKHR{});
@@ -487,15 +494,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
properties.subgroup_size_control.maxSubgroupSize > GuestWarpSize;
is_integrated = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
const VkPhysicalDeviceMemoryProperties memory_properties =
physical.GetMemoryProperties().memoryProperties;
is_uma = std::all_of(memory_properties.memoryTypes,
memory_properties.memoryTypes + memory_properties.memoryTypeCount,
[](const VkMemoryType& type) {
return (type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ==
0 ||
(type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
});
supports_d24_depth =
IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
@@ -1425,6 +1423,12 @@ void Device::RemoveUnsuitableExtensions() {
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance5, features.maintenance5,
VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
if (!is_uma || instance_version < VK_API_VERSION_1_3 ||
!features.host_image_copy.hostImageCopy) {
RemoveExtensionFeature(extensions.host_image_copy, features.host_image_copy,
VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME);
}
extensions.synchronization2 = features.synchronization2.synchronization2;
extensions.dynamic_rendering = features.dynamic_rendering.dynamicRendering;
@@ -68,6 +68,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \
FEATURE(EXT, 4444Formats, 4444_FORMATS, format_a4b4g4r4) \
FEATURE(EXT, HostImageCopy, HOST_IMAGE_COPY, host_image_copy) \
FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \
FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \
FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART, \
@@ -988,6 +989,10 @@ FN_MAX_LIMIT_LIST
return is_uma;
}
bool IsHostImageCopySupported() const {
return extensions.host_image_copy;
}
bool HasNullDescriptor() const {
return features.robustness2.nullDescriptor;
}
@@ -206,6 +206,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkGetPipelineExecutablePropertiesKHR);
X(vkGetPipelineExecutableStatisticsKHR);
X(vkGetSemaphoreCounterValue);
X(vkCopyMemoryToImageEXT);
X(vkTransitionImageLayoutEXT);
X(vkQueueBindSparse);
X(vkQueueSubmit2);
X(vkResetFences);
@@ -355,6 +355,8 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR{};
PFN_vkGetQueryPoolResults vkGetQueryPoolResults{};
PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue{};
PFN_vkCopyMemoryToImageEXT vkCopyMemoryToImageEXT{};
PFN_vkTransitionImageLayoutEXT vkTransitionImageLayoutEXT{};
PFN_vkQueueBindSparse vkQueueBindSparse{};
PFN_vkQueueSubmit2 vkQueueSubmit2{};
PFN_vkResetFences vkResetFences{};
@@ -1092,6 +1094,14 @@ public:
dld->vkResetQueryPool(handle, query_pool, first, count);
}
void CopyMemoryToImageEXT(const VkCopyMemoryToImageInfoEXT& info) const {
Check(dld->vkCopyMemoryToImageEXT(handle, &info));
}
void TransitionImageLayoutEXT(const VkHostImageLayoutTransitionInfoEXT& info) const {
Check(dld->vkTransitionImageLayoutEXT(handle, 1, &info));
}
VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size,
void* data, VkDeviceSize stride,
VkQueryResultFlags flags) const noexcept {