mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-27 09:23:01 +00:00
Adjustments on upload for textures
This commit is contained in:
@@ -373,6 +373,7 @@ struct TextureCacheParams {
|
||||
static constexpr bool HAS_DEVICE_MEMORY_INFO = true;
|
||||
static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = true;
|
||||
static constexpr bool HAS_MSAA_DOWNLOADS = false;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = false;
|
||||
|
||||
using Runtime = OpenGL::TextureCacheRuntime;
|
||||
using Image = OpenGL::Image;
|
||||
|
||||
@@ -424,11 +424,8 @@ void BufferCacheRuntime::TryEnableUnifiedMemory(void* base, size_t size,
|
||||
std::span<AHardwareBuffer* const> hardware_buffers,
|
||||
size_t hardware_buffer_window,
|
||||
size_t hardware_buffer_base) {
|
||||
unified_memory = std::make_unique<HostMemoryImport>(
|
||||
device, base, size, hardware_buffers, hardware_buffer_window, hardware_buffer_base);
|
||||
if (!unified_memory->IsValid()) {
|
||||
unified_memory.reset();
|
||||
}
|
||||
unified_memory = memory_allocator.CreateHostMemoryImport(
|
||||
base, size, hardware_buffers, hardware_buffer_window, hardware_buffer_base);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::CopyToUnifiedMemory(
|
||||
|
||||
@@ -264,7 +264,7 @@ private:
|
||||
std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer;
|
||||
|
||||
vk::Buffer null_buffer;
|
||||
std::unique_ptr<HostMemoryImport> unified_memory;
|
||||
HostMemoryImport* unified_memory{};
|
||||
boost::container::small_vector<PendingUnifiedCopy, 8> pending_unified_copies;
|
||||
|
||||
std::unique_ptr<Uint8Pass> uint8_pass;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
@@ -955,10 +956,10 @@ bool BlockLinearUnswizzle2DPass::IsSupported(const Device& device,
|
||||
if (info.type != VideoCommon::ImageType::e2D) {
|
||||
return false;
|
||||
}
|
||||
if (info.resources.levels != 1 || info.resources.layers != 1) {
|
||||
if (info.num_samples > 1) {
|
||||
return false;
|
||||
}
|
||||
if (info.num_samples > 1) {
|
||||
if (device.GetStorageBufferAlignment() > Tegra::Texture::GOB_SIZE) {
|
||||
return false;
|
||||
}
|
||||
if (VideoCore::Surface::IsPixelFormatASTC(info.format) && !device.IsOptimalAstcSupported()) {
|
||||
@@ -974,83 +975,37 @@ bool BlockLinearUnswizzle2DPass::IsSupported(const Device& device,
|
||||
void BlockLinearUnswizzle2DPass::Unswizzle(
|
||||
Image& image, const StagingBufferRef& swizzled,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
if (swizzles.empty()) {
|
||||
UnswizzleFrom(image, swizzled.buffer, swizzled.offset, swizzles);
|
||||
}
|
||||
|
||||
void BlockLinearUnswizzle2DPass::UnswizzleFrom(
|
||||
Image& image, VkBuffer source_buffer, VkDeviceSize source_offset,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
const VkImage dst_image = image.Handle();
|
||||
if (swizzles.empty() || source_buffer == VK_NULL_HANDLE || dst_image == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
const VideoCommon::SwizzleParameters& sw = swizzles.front();
|
||||
const auto params = VideoCommon::Accelerated::MakeBlockLinearSwizzle2DParams(sw, image.info);
|
||||
|
||||
const u32 width = sw.num_tiles.width;
|
||||
const u32 height = sw.num_tiles.height;
|
||||
const u32 texel_width = image.info.size.width;
|
||||
const u32 texel_height = image.info.size.height;
|
||||
const u32 depth = image.info.resources.layers;
|
||||
const u32 bytes_per_block = 1u << params.bytes_per_block_log2;
|
||||
const VkDeviceSize output_size =
|
||||
static_cast<VkDeviceSize>(width) * height * depth * bytes_per_block;
|
||||
|
||||
const StagingBufferRef output =
|
||||
staging_buffer_pool.Request(static_cast<size_t>(output_size), MemoryUsage::DeviceLocal);
|
||||
|
||||
BlockLinearUnswizzle2DPushConstants pc{};
|
||||
pc.dim = {width, height, depth};
|
||||
pc.bytes_per_block_log2 = params.bytes_per_block_log2;
|
||||
pc.origin = params.origin;
|
||||
pc.layer_stride = params.layer_stride;
|
||||
pc.block_size = params.block_size;
|
||||
pc.x_shift = params.x_shift;
|
||||
pc.block_height = params.block_height;
|
||||
pc.block_height_mask = params.block_height_mask;
|
||||
const u32 layers = image.info.resources.layers;
|
||||
const VkImageAspectFlags aspect = image.AspectMask();
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
|
||||
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||
compute_pass_descriptor_queue.AddBuffer(swizzled.buffer, sw.buffer_offset + swizzled.offset,
|
||||
image.guest_size_bytes - sw.buffer_offset);
|
||||
compute_pass_descriptor_queue.AddBuffer(output.buffer, output.offset, output_size);
|
||||
|
||||
const void* descriptor_data = compute_pass_descriptor_queue.UpdateData();
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
|
||||
const u32 gx = Common::DivCeil(width, 16u);
|
||||
const u32 gy = Common::DivCeil(height, 8u);
|
||||
const bool is_initialized = image.ExchangeInitialization();
|
||||
|
||||
const VkBuffer out_buffer = output.buffer;
|
||||
const VkDeviceSize out_offset = output.offset;
|
||||
const VkImage dst_image = image.Handle();
|
||||
const VkImageAspectFlags aspect = image.AspectMask();
|
||||
|
||||
scheduler.Record([this, set, descriptor_data, pc, gx, gy, depth, output_size, out_buffer,
|
||||
out_offset, dst_image, aspect, texel_width, texel_height,
|
||||
is_initialized](vk::CommandBuffer cmdbuf) {
|
||||
if (dst_image == VK_NULL_HANDLE || out_buffer == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(pc), &pc);
|
||||
cmdbuf.Dispatch(gx, gy, depth);
|
||||
|
||||
const VkBufferMemoryBarrier buffer_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.buffer = out_buffer,
|
||||
.offset = out_offset,
|
||||
.size = output_size,
|
||||
};
|
||||
const VkImageMemoryBarrier pre_copy{
|
||||
VkAccessFlags pre_access = VK_ACCESS_NONE;
|
||||
VkImageLayout pre_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkPipelineStageFlags pre_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
if (image.ExchangeInitialization()) {
|
||||
pre_access = VK_ACCESS_SHADER_READ_BIT;
|
||||
pre_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
pre_stage = vk::PIPELINE_STAGE_GRAPHICS_COMPUTE;
|
||||
}
|
||||
scheduler.Record([dst_image, aspect, pre_access, pre_layout,
|
||||
pre_stage](vk::CommandBuffer cmdbuf) {
|
||||
const VkImageMemoryBarrier barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_READ_BIT
|
||||
: VK_ACCESS_NONE),
|
||||
.srcAccessMask = pre_access,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.oldLayout = pre_layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -1063,27 +1018,96 @@ void BlockLinearUnswizzle2DPass::Unswizzle(
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
(is_initialized ? vk::PIPELINE_STAGE_GRAPHICS_COMPUTE
|
||||
: VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT),
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, buffer_barrier, pre_copy);
|
||||
cmdbuf.PipelineBarrier(pre_stage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, {}, barrier);
|
||||
});
|
||||
|
||||
const VkBufferImageCopy copy{
|
||||
.bufferOffset = out_offset,
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource{
|
||||
.aspectMask = aspect,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = depth,
|
||||
},
|
||||
.imageOffset = {0, 0, 0},
|
||||
.imageExtent = {texel_width, texel_height, 1},
|
||||
};
|
||||
cmdbuf.CopyBufferToImage(out_buffer, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy);
|
||||
for (const VideoCommon::SwizzleParameters& sw : swizzles) {
|
||||
const auto params =
|
||||
VideoCommon::Accelerated::MakeBlockLinearSwizzle2DParams(sw, image.info);
|
||||
const u32 width = sw.num_tiles.width;
|
||||
const u32 height = sw.num_tiles.height;
|
||||
const u32 bytes_per_block = 1u << params.bytes_per_block_log2;
|
||||
const VkDeviceSize output_size =
|
||||
static_cast<VkDeviceSize>(width) * height * layers * bytes_per_block;
|
||||
if (output_size == 0) {
|
||||
continue;
|
||||
}
|
||||
const u32 level = static_cast<u32>(sw.level);
|
||||
const u32 texel_width = (std::max)(1u, image.info.size.width >> level);
|
||||
const u32 texel_height = (std::max)(1u, image.info.size.height >> level);
|
||||
|
||||
const VkImageMemoryBarrier post_copy{
|
||||
const StagingBufferRef output =
|
||||
staging_buffer_pool.Request(static_cast<size_t>(output_size), MemoryUsage::DeviceLocal);
|
||||
|
||||
BlockLinearUnswizzle2DPushConstants pc{};
|
||||
pc.dim = {width, height, layers};
|
||||
pc.bytes_per_block_log2 = params.bytes_per_block_log2;
|
||||
pc.origin = params.origin;
|
||||
pc.layer_stride = params.layer_stride;
|
||||
pc.block_size = params.block_size;
|
||||
pc.x_shift = params.x_shift;
|
||||
pc.block_height = params.block_height;
|
||||
pc.block_height_mask = params.block_height_mask;
|
||||
|
||||
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||
compute_pass_descriptor_queue.AddBuffer(source_buffer, sw.buffer_offset + source_offset,
|
||||
image.guest_size_bytes - sw.buffer_offset);
|
||||
compute_pass_descriptor_queue.AddBuffer(output.buffer, output.offset, output_size);
|
||||
|
||||
const void* descriptor_data = compute_pass_descriptor_queue.UpdateData();
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
|
||||
const u32 gx = Common::DivCeil(width, 16u);
|
||||
const u32 gy = Common::DivCeil(height, 8u);
|
||||
const VkBuffer out_buffer = output.buffer;
|
||||
const VkDeviceSize out_offset = output.offset;
|
||||
|
||||
scheduler.Record([this, set, descriptor_data, pc, gx, gy, layers, output_size, out_buffer,
|
||||
out_offset, dst_image, aspect, texel_width, texel_height,
|
||||
level](vk::CommandBuffer cmdbuf) {
|
||||
if (out_buffer == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(pc), &pc);
|
||||
cmdbuf.Dispatch(gx, gy, layers);
|
||||
|
||||
const VkBufferMemoryBarrier buffer_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.buffer = out_buffer,
|
||||
.offset = out_offset,
|
||||
.size = output_size,
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, buffer_barrier, {});
|
||||
|
||||
const VkBufferImageCopy copy{
|
||||
.bufferOffset = out_offset,
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource{
|
||||
.aspectMask = aspect,
|
||||
.mipLevel = level,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = layers,
|
||||
},
|
||||
.imageOffset = {0, 0, 0},
|
||||
.imageExtent = {texel_width, texel_height, 1},
|
||||
};
|
||||
cmdbuf.CopyBufferToImage(out_buffer, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
copy);
|
||||
});
|
||||
}
|
||||
|
||||
scheduler.Record([dst_image, aspect](vk::CommandBuffer cmdbuf) {
|
||||
const VkImageMemoryBarrier barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
@@ -1101,8 +1125,8 @@ void BlockLinearUnswizzle2DPass::Unswizzle(
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
|
||||
0, {}, {}, post_copy);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0, {}, {}, barrier);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1288,13 +1312,20 @@ void BlockLinearUnswizzle3DBufferPass::Unswizzle(
|
||||
.offset = out_offset,
|
||||
.size = output_size,
|
||||
};
|
||||
VkAccessFlags pre_copy_access = VK_ACCESS_NONE;
|
||||
VkImageLayout pre_copy_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkPipelineStageFlags pre_copy_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
if (is_initialized) {
|
||||
pre_copy_access = VK_ACCESS_SHADER_READ_BIT;
|
||||
pre_copy_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
pre_copy_stage = vk::PIPELINE_STAGE_GRAPHICS_COMPUTE;
|
||||
}
|
||||
const VkImageMemoryBarrier pre_copy{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_READ_BIT
|
||||
: VK_ACCESS_NONE),
|
||||
.srcAccessMask = pre_copy_access,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.oldLayout = pre_copy_layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -1307,9 +1338,7 @@ void BlockLinearUnswizzle3DBufferPass::Unswizzle(
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
(is_initialized ? vk::PIPELINE_STAGE_GRAPHICS_COMPUTE
|
||||
: VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT),
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | pre_copy_stage,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, buffer_barrier, pre_copy);
|
||||
|
||||
const VkBufferImageCopy copy{
|
||||
|
||||
@@ -178,6 +178,9 @@ public:
|
||||
void Unswizzle(Image& image, const StagingBufferRef& swizzled,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||
|
||||
void UnswizzleFrom(Image& image, VkBuffer source_buffer, VkDeviceSize source_offset,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||
|
||||
private:
|
||||
Scheduler& scheduler;
|
||||
StagingBufferPool& staging_buffer_pool;
|
||||
|
||||
@@ -3157,7 +3157,7 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
||||
return bl2d_unswizzle_pass->Unswizzle(image, map, swizzles);
|
||||
}
|
||||
|
||||
if (bl3db_unswizzle_pass &&
|
||||
if (bl3db_unswizzle_pass && z_count == 0 &&
|
||||
BlockLinearUnswizzle3DBufferPass::IsSupported(device, image.info)) {
|
||||
return bl3db_unswizzle_pass->Unswizzle(image, map, swizzles);
|
||||
}
|
||||
@@ -3177,6 +3177,66 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
bool TextureCacheRuntime::IsUnifiedMemoryBindable() const noexcept {
|
||||
const HostMemoryImport* const import = memory_allocator.GetHostMemoryImport();
|
||||
return import != nullptr && import->IsValid() && import->IsBindable();
|
||||
}
|
||||
|
||||
u64 TextureCacheRuntime::UnifiedMemoryBase() const noexcept {
|
||||
const HostMemoryImport* const import = memory_allocator.GetHostMemoryImport();
|
||||
if (import == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return import->GetBaseOffset();
|
||||
}
|
||||
|
||||
u64 TextureCacheRuntime::UnifiedMemorySize() const noexcept {
|
||||
const HostMemoryImport* const import = memory_allocator.GetHostMemoryImport();
|
||||
if (import == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return import->GetSize();
|
||||
}
|
||||
|
||||
u64 TextureCacheRuntime::UnifiedMemoryWindowSize() const noexcept {
|
||||
const HostMemoryImport* const import = memory_allocator.GetHostMemoryImport();
|
||||
if (import == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return import->GetWindowSize();
|
||||
}
|
||||
|
||||
bool TextureCacheRuntime::CanUploadImageDirectly(const VideoCommon::ImageInfo& info) const {
|
||||
return bl2d_unswizzle_pass.has_value() &&
|
||||
BlockLinearUnswizzle2DPass::IsSupported(device, info);
|
||||
}
|
||||
|
||||
bool TextureCacheRuntime::UploadImageDirectly(
|
||||
Image& image, size_t window_index, u64 window_offset,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
if ((window_offset % device.GetStorageBufferAlignment()) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (image.guest_size_bytes > device.GetMaxStorageBufferRange()) {
|
||||
return false;
|
||||
}
|
||||
const HostMemoryImport* const import = memory_allocator.GetHostMemoryImport();
|
||||
if (import == nullptr || window_index >= import->GetWindowCount()) {
|
||||
return false;
|
||||
}
|
||||
const VkBuffer window_buffer = import->GetWindowBuffer(window_index);
|
||||
if (window_buffer == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
bl2d_unswizzle_pass->UnswizzleFrom(image, window_buffer,
|
||||
static_cast<VkDeviceSize>(window_offset), swizzles);
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 TextureCacheRuntime::CurrentTick() const noexcept {
|
||||
return scheduler.CurrentTick();
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::TransitionImageLayout(Image& image) {
|
||||
if (!image.ExchangeInitialization()) {
|
||||
VkImageMemoryBarrier barrier{
|
||||
|
||||
@@ -101,6 +101,21 @@ public:
|
||||
std::span<const VideoCommon::SwizzleParameters>,
|
||||
u32 z_start, u32 z_count);
|
||||
|
||||
[[nodiscard]] bool IsUnifiedMemoryBindable() const noexcept;
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemoryBase() const noexcept;
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemorySize() const noexcept;
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemoryWindowSize() const noexcept;
|
||||
|
||||
[[nodiscard]] bool CanUploadImageDirectly(const VideoCommon::ImageInfo& info) const;
|
||||
|
||||
bool UploadImageDirectly(Image& image, size_t window_index, u64 window_offset,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||
|
||||
[[nodiscard]] u64 CurrentTick() const noexcept;
|
||||
|
||||
void InsertUploadMemoryBarrier() {}
|
||||
|
||||
void TransitionImageLayout(Image& image);
|
||||
@@ -588,6 +603,7 @@ struct TextureCacheParams {
|
||||
static constexpr bool HAS_DEVICE_MEMORY_INFO = true;
|
||||
static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = true;
|
||||
static constexpr bool HAS_MSAA_DOWNLOADS = true;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = true;
|
||||
|
||||
using Runtime = Vulkan::TextureCacheRuntime;
|
||||
using Image = Vulkan::Image;
|
||||
|
||||
@@ -95,6 +95,8 @@ struct ImageBase {
|
||||
u32 scale_rating = 0;
|
||||
u64 scale_tick = 0;
|
||||
bool has_scaled = false;
|
||||
bool direct_upload_used = false;
|
||||
bool direct_upload_blocked = false;
|
||||
|
||||
size_t channel = 0;
|
||||
|
||||
|
||||
@@ -585,6 +585,10 @@ FramebufferId TextureCache<P>::GetFramebufferId(const RenderTargets& key) {
|
||||
template <class P>
|
||||
void TextureCache<P>::WriteMemory(DAddr cpu_addr, size_t size) {
|
||||
ForEachImageInRegion(cpu_addr, size, [this](ImageId image_id, Image& image) {
|
||||
if (image.direct_upload_used) {
|
||||
image.direct_upload_used = false;
|
||||
image.direct_upload_blocked = true;
|
||||
}
|
||||
if (True(image.flags & ImageFlagBits::CpuModified)) {
|
||||
return;
|
||||
}
|
||||
@@ -1145,11 +1149,59 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
|
||||
QueueAsyncUnswizzle(image, image_id);
|
||||
return;
|
||||
}
|
||||
if (True(image.flags & ImageFlagBits::AcceleratedUpload) &&
|
||||
TryUploadFromUnifiedMemory(image)) {
|
||||
runtime.InsertUploadMemoryBarrier();
|
||||
return;
|
||||
}
|
||||
auto staging = runtime.UploadStagingBuffer(MapSizeBytes(image));
|
||||
UploadImageContents(image, staging);
|
||||
runtime.InsertUploadMemoryBarrier();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool TextureCache<P>::TryUploadFromUnifiedMemory([[maybe_unused]] Image& image) {
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
if (image.direct_upload_blocked || image.guest_size_bytes == 0) {
|
||||
return false;
|
||||
}
|
||||
if (!runtime.IsUnifiedMemoryBindable() || !runtime.CanUploadImageDirectly(image.info)) {
|
||||
return false;
|
||||
}
|
||||
const u64 window_size = runtime.UnifiedMemoryWindowSize();
|
||||
if (window_size == 0) {
|
||||
return false;
|
||||
}
|
||||
const u8* const first = gpu_memory->GetSpan(image.gpu_addr, image.guest_size_bytes);
|
||||
if (first == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const u64 phys_offset = static_cast<u64>(first - device_memory.GetPhysicalBase());
|
||||
const u64 unified_base = runtime.UnifiedMemoryBase();
|
||||
if (phys_offset < unified_base) {
|
||||
return false;
|
||||
}
|
||||
const u64 relative = phys_offset - unified_base;
|
||||
const u64 unified_size = runtime.UnifiedMemorySize();
|
||||
if (relative >= unified_size || unified_size - relative < image.guest_size_bytes) {
|
||||
return false;
|
||||
}
|
||||
const u64 local_offset = relative % window_size;
|
||||
if (window_size - local_offset < image.guest_size_bytes) {
|
||||
return false;
|
||||
}
|
||||
const auto swizzles = FullUploadSwizzles(image.info);
|
||||
if (!runtime.UploadImageDirectly(image, static_cast<size_t>(relative / window_size),
|
||||
local_offset, FixSmallVectorADL(swizzles))) {
|
||||
return false;
|
||||
}
|
||||
image.direct_upload_used = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
template <typename StagingBuffer>
|
||||
void TextureCache<P>::UploadImageContents(Image& image, StagingBuffer& staging) {
|
||||
|
||||
@@ -108,6 +108,7 @@ class TextureCache : public VideoCommon::ChannelSetupCaches<TextureCacheChannelI
|
||||
static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
|
||||
/// True when the API can do asynchronous texture downloads.
|
||||
static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = P::IMPLEMENTS_ASYNC_DOWNLOADS;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = P::USE_UNIFIED_MEMORY;
|
||||
|
||||
static constexpr size_t UNSET_CHANNEL{(std::numeric_limits<size_t>::max)()};
|
||||
|
||||
@@ -307,6 +308,8 @@ private:
|
||||
|
||||
void RefreshContents(Image& image, ImageId image_id);
|
||||
|
||||
bool TryUploadFromUnifiedMemory(Image& image);
|
||||
|
||||
/// Upload data from guest to an image
|
||||
template <typename StagingBuffer>
|
||||
void UploadImageContents(Image& image, StagingBuffer& staging_buffer);
|
||||
|
||||
@@ -651,6 +651,17 @@ namespace Vulkan {
|
||||
return MemoryCommit(allocator, a, info);
|
||||
}
|
||||
|
||||
HostMemoryImport *MemoryAllocator::CreateHostMemoryImport(
|
||||
void *base, size_t size, std::span<AHardwareBuffer *const> hardware_buffers,
|
||||
size_t hardware_buffer_window, size_t hardware_buffer_base) {
|
||||
unified_memory = std::make_unique<HostMemoryImport>(
|
||||
device, base, size, hardware_buffers, hardware_buffer_window, hardware_buffer_base);
|
||||
if (!unified_memory->IsValid()) {
|
||||
unified_memory.reset();
|
||||
}
|
||||
return unified_memory.get();
|
||||
}
|
||||
|
||||
MemoryCommit MemoryAllocator::Commit(const vk::Buffer &buffer, MemoryUsage usage) {
|
||||
// Allocate memory appropriate for this buffer automatically
|
||||
const auto vma_usage = MemoryUsageVma(usage);
|
||||
|
||||
@@ -192,6 +192,15 @@ namespace Vulkan {
|
||||
/// Commits memory required by the buffer and binds it (for buffers created outside VMA).
|
||||
MemoryCommit Commit(const vk::Buffer &buffer, MemoryUsage usage);
|
||||
|
||||
HostMemoryImport *CreateHostMemoryImport(void *base, size_t size,
|
||||
std::span<AHardwareBuffer *const> hardware_buffers,
|
||||
size_t hardware_buffer_window,
|
||||
size_t hardware_buffer_base);
|
||||
|
||||
[[nodiscard]] HostMemoryImport *GetHostMemoryImport() const noexcept {
|
||||
return unified_memory.get();
|
||||
}
|
||||
|
||||
private:
|
||||
static bool IsAutoUsage(VmaMemoryUsage u) noexcept {
|
||||
switch (u) {
|
||||
@@ -209,6 +218,7 @@ namespace Vulkan {
|
||||
const VkPhysicalDeviceMemoryProperties properties; ///< Physical device memory properties.
|
||||
VkDeviceSize buffer_image_granularity; ///< Adjacent buffer/image granularity
|
||||
u32 valid_memory_types{~0u};
|
||||
std::unique_ptr<HostMemoryImport> unified_memory;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
Reference in New Issue
Block a user