mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-28 15:31:12 +02:00
Compare commits
6 Commits
e88923331c
...
06dba55923
| Author | SHA1 | Date | |
|---|---|---|---|
| 06dba55923 | |||
| 8d19ee6dc5 | |||
| 3e91569d36 | |||
| 6010f60803 | |||
| c14b1de71e | |||
| 14cc49e727 |
@@ -700,6 +700,10 @@ public:
|
||||
constexpr u64 MapSlotsPerWindow = 64;
|
||||
const u64 affordable_windows = permissible_maps / MapSlotsPerWindow;
|
||||
budget = (std::min)(budget, affordable_windows * window_size);
|
||||
const u64 available = Common::GetAvailablePhysicalMemory();
|
||||
if (available != 0) {
|
||||
budget = (std::min)(budget, available / 2);
|
||||
}
|
||||
budget = (std::min)(budget, static_cast<u64>(backing_size));
|
||||
budget = Common::AlignDown(budget, window_size);
|
||||
constexpr u64 MinimumBudget = 256ULL << 20;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/memory_detect.h"
|
||||
|
||||
@@ -97,4 +98,39 @@ u64 GetPermissibleMapCount() {
|
||||
return count - ReservedMaps;
|
||||
}
|
||||
|
||||
u64 GetAvailablePhysicalMemory() {
|
||||
#ifdef _WIN32
|
||||
MEMORYSTATUSEX memorystatus;
|
||||
memorystatus.dwLength = sizeof(memorystatus);
|
||||
if (GlobalMemoryStatusEx(&memorystatus) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return memorystatus.ullAvailPhys;
|
||||
#elif defined(__linux__)
|
||||
static constexpr char AvailableKey[] = "MemAvailable:";
|
||||
if (std::FILE* const file = std::fopen("/proc/meminfo", "re")) {
|
||||
char line[256];
|
||||
u64 available = 0;
|
||||
while (std::fgets(line, sizeof(line), file) != nullptr) {
|
||||
if (std::strncmp(line, AvailableKey, sizeof(AvailableKey) - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
available = std::strtoull(line + sizeof(AvailableKey) - 1, nullptr, 10) * 1024;
|
||||
break;
|
||||
}
|
||||
std::fclose(file);
|
||||
if (available != 0) {
|
||||
return available;
|
||||
}
|
||||
}
|
||||
struct sysinfo meminfo;
|
||||
if (sysinfo(&meminfo) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<u64>(meminfo.freeram) * static_cast<u64>(meminfo.mem_unit);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -23,4 +23,6 @@ struct MemoryInfo {
|
||||
|
||||
[[nodiscard]] u64 GetPermissibleMapCount();
|
||||
|
||||
[[nodiscard]] u64 GetAvailablePhysicalMemory();
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
|
||||
// Operation modes: RGBA -> 1, RGBY -> 3, LERP -> 4
|
||||
#define OPERATION_MODE 1
|
||||
#define EDGE_THRESHOLD (8.0 / 255.0)
|
||||
#define DIRECTION_EPSILON 6.5e-05
|
||||
#define DEVIATION_FLOOR 6.0e-02
|
||||
|
||||
layout(push_constant) uniform constants {
|
||||
vec2 scale;
|
||||
@@ -21,20 +21,37 @@ layout(set = 0, binding = 0) uniform sampler2D sampler0;
|
||||
layout(location=0) in vec2 texcoord;
|
||||
layout(location=0) out vec4 frag_color;
|
||||
|
||||
vec4 weightY(vec4 dx, vec4 dy, vec4 std) {
|
||||
vec4 x = ((dx * dx) + (dy * dy)) * 0.55f + std;
|
||||
return (x - 1.f) * (x - 4.f) * 3.8125f; // approx. of (x - 1) * (x - 4)^3
|
||||
mediump vec4 fastLanczos2(mediump vec4 x) {
|
||||
mediump vec4 wA = x - 4.0f;
|
||||
mediump vec4 wB = x * wA - wA;
|
||||
wA *= wA;
|
||||
return wB * wA;
|
||||
}
|
||||
|
||||
mediump vec2 edgeDirection(mediump vec4 left, mediump vec4 right) {
|
||||
mediump float RxLz = right.x - left.z;
|
||||
mediump float RwLy = right.w - left.y;
|
||||
mediump vec2 delta = vec2(RxLz + RwLy, RxLz - RwLy);
|
||||
mediump float length_inv =
|
||||
inversesqrt((delta.x * delta.x + DIRECTION_EPSILON) + delta.y * delta.y);
|
||||
return delta * length_inv;
|
||||
}
|
||||
|
||||
mediump vec4 weightY(mediump vec4 dx, mediump vec4 dy, mediump vec4 c, mediump float std,
|
||||
mediump vec2 dir) {
|
||||
mediump vec4 edge_dis = dx * dir.y + dy * dir.x;
|
||||
mediump vec4 x = (dx * dx + dy * dy) +
|
||||
(edge_dis * edge_dis) * (clamp((c * c) * std, 0.0f, 1.0f) * 0.7f - 1.0f);
|
||||
return fastLanczos2(x);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 color = textureLod(sampler0, texcoord.xy, 0.0f);
|
||||
// image coord
|
||||
vec2 icoord = (texcoord * size + vec2(-0.5f, 0.5f));
|
||||
vec2 icoord_pixel = floor(icoord);
|
||||
vec2 coord = icoord_pixel * scale;
|
||||
vec2 pl = icoord - icoord_pixel;
|
||||
// left: 0, right: 1, upDown: 2
|
||||
mat3x4 dg = mat3x4(
|
||||
mediump vec4 color = textureLod(sampler0, texcoord.xy, 0.0f);
|
||||
highp vec2 icoord = (texcoord * size + vec2(-0.5f, 0.5f));
|
||||
highp vec2 icoord_pixel = floor(icoord);
|
||||
highp vec2 coord = icoord_pixel * scale;
|
||||
mediump vec2 pl = icoord - icoord_pixel;
|
||||
mediump mat3x4 dg = mat3x4(
|
||||
textureGather(sampler0, coord, 1),
|
||||
textureGather(sampler0, coord + vec2(2.f * scale.x, 0.0f), 1),
|
||||
vec4(
|
||||
@@ -42,42 +59,40 @@ void main() {
|
||||
textureGather(sampler0, coord + vec2(scale.x, +scale.y), 1).yx
|
||||
)
|
||||
);
|
||||
float edgeVote = abs(dg[0].z - dg[0].y) + abs(color.y - dg[0].y) + abs(color.y - dg[0].z);
|
||||
mediump float edgeVote =
|
||||
abs(dg[0].z - dg[0].y) + abs(color.y - dg[0].y) + abs(color.y - dg[0].z);
|
||||
if (edgeVote > EDGE_THRESHOLD) {
|
||||
float mean = (dg[0].y + dg[0].z + dg[1].x + dg[1].w) * 0.25f;
|
||||
mediump float mean = (dg[0].y + dg[0].z + dg[1].x + dg[1].w) * 0.25f;
|
||||
dg = dg - mean;
|
||||
vec4 sum = abs(dg[0]) + abs(dg[1]) + abs(dg[2]);
|
||||
float std = 2.181818f / (sum.x + sum.y + sum.z + sum.w);
|
||||
mat2x4 w = mat2x4(
|
||||
weightY(
|
||||
pl.xxxx + vec4(+1.0f, +0.0f, +0.0f, +1.0f),
|
||||
pl.yyyy + vec4(-1.0f, -1.0f, +0.0f, +0.0f),
|
||||
clamp(abs(dg[0]) * std, 0.0f, 1.0f)
|
||||
) + weightY(
|
||||
pl.xxxx + vec4(-1.0f, -2.0f, -2.0f, -1.0f),
|
||||
pl.yyyy + vec4(-1.0f, -1.0f, +0.0f, +0.0f),
|
||||
clamp(abs(dg[1]) * std, 0.0f, 1.0f)
|
||||
) + weightY(
|
||||
pl.xxxx + vec4(+0.0f, -1.0f, -1.0f, +0.0f),
|
||||
pl.yyyy + vec4(+1.0f, +1.0f, -2.0f, -2.0f),
|
||||
clamp(abs(dg[2]) * std, 0.0f, 1.0f)
|
||||
),
|
||||
dg[0] + dg[1] + dg[2]
|
||||
mediump float sum = dot(abs(dg[0]) + abs(dg[1]) + abs(dg[2]), vec4(1.0f));
|
||||
mediump float sum_mean = 1.014185e+01f / max(sum, DEVIATION_FLOOR);
|
||||
mediump float std = sum_mean * sum_mean;
|
||||
mediump vec2 dir = edgeDirection(dg[0], dg[1]);
|
||||
mediump vec4 w0 = weightY(
|
||||
pl.xxxx + vec4(+1.0f, +0.0f, +0.0f, +1.0f),
|
||||
pl.yyyy + vec4(-1.0f, -1.0f, +0.0f, +0.0f),
|
||||
dg[0], std, dir
|
||||
);
|
||||
// compute final y with bounds
|
||||
vec2 yb = vec2(
|
||||
min(min(dg[0].y, dg[0].z), min(dg[1].x, dg[1].w)), // min
|
||||
max(max(dg[0].y, dg[0].z), max(dg[1].x, dg[1].w)) // max
|
||||
mediump vec4 w1 = weightY(
|
||||
pl.xxxx + vec4(-1.0f, -2.0f, -2.0f, -1.0f),
|
||||
pl.yyyy + vec4(-1.0f, -1.0f, +0.0f, +0.0f),
|
||||
dg[1], std, dir
|
||||
);
|
||||
vec2 fvy = vec2(
|
||||
w[0].x + w[0].y + w[0].z + w[0].w,
|
||||
w[1].x + w[1].y + w[1].z + w[1].w
|
||||
mediump vec4 w2 = weightY(
|
||||
pl.xxxx + vec4(+0.0f, -1.0f, -1.0f, +0.0f),
|
||||
pl.yyyy + vec4(+1.0f, +1.0f, -2.0f, -2.0f),
|
||||
dg[2], std, dir
|
||||
);
|
||||
float fy = clamp((fvy.y / fvy.x) * edge_sharpness, yb[0], yb[1]);
|
||||
// Smooth high contrast input
|
||||
float dy = clamp(fy - color.y + mean, -23.0f / 255.0f, 23.0f / 255.0f);
|
||||
mediump float sum_w = dot(w0 + w1 + w2, vec4(1.0f));
|
||||
mediump float sum_wc = dot(w0 * dg[0] + w1 * dg[1] + w2 * dg[2], vec4(1.0f));
|
||||
mediump vec2 yb = vec2(
|
||||
min(min(dg[0].y, dg[0].z), min(dg[1].x, dg[1].w)),
|
||||
max(max(dg[0].y, dg[0].z), max(dg[1].x, dg[1].w))
|
||||
);
|
||||
mediump float fy = clamp((sum_wc / sum_w) * edge_sharpness, yb[0], yb[1]);
|
||||
mediump float dy = clamp(fy - color.y + mean, -23.0f / 255.0f, 23.0f / 255.0f);
|
||||
color = clamp(color + dy, 0.0f, 1.0f);
|
||||
}
|
||||
color.w = 1.0f; //assume alpha channel is not used
|
||||
color.w = 1.0f;
|
||||
frag_color.xyzw = color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -12,6 +13,7 @@
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/div_ceil.h"
|
||||
@@ -955,10 +957,14 @@ 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::GetFormatType(info.format) !=
|
||||
VideoCore::Surface::SurfaceType::ColorTexture) {
|
||||
return false;
|
||||
}
|
||||
if (VideoCore::Surface::IsPixelFormatASTC(info.format) && !device.IsOptimalAstcSupported()) {
|
||||
@@ -974,83 +980,62 @@ 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 u32 layers = image.info.resources.layers;
|
||||
const VkImageAspectFlags aspect = image.AspectMask();
|
||||
|
||||
const VkDeviceSize output_alignment =
|
||||
(std::max)(device.GetStorageBufferAlignment(), VkDeviceSize{16});
|
||||
VkDeviceSize total_output = 0;
|
||||
for (const VideoCommon::SwizzleParameters& sw : swizzles) {
|
||||
const auto params =
|
||||
VideoCommon::Accelerated::MakeBlockLinearSwizzle2DParams(sw, image.info);
|
||||
const VkDeviceSize level_size = static_cast<VkDeviceSize>(sw.num_tiles.width) *
|
||||
sw.num_tiles.height * layers *
|
||||
(1ULL << params.bytes_per_block_log2);
|
||||
if (level_size == 0) {
|
||||
continue;
|
||||
}
|
||||
total_output = Common::AlignUp(total_output, output_alignment) + level_size;
|
||||
}
|
||||
if (total_output == 0) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
staging_buffer_pool.Request(static_cast<size_t>(total_output), MemoryUsage::DeviceLocal);
|
||||
const VkBuffer out_buffer = output.buffer;
|
||||
if (out_buffer == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
VkDeviceSize level_offset = 0;
|
||||
|
||||
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 +1048,92 @@ 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{
|
||||
level_offset = Common::AlignUp(level_offset, output_alignment);
|
||||
const VkDeviceSize out_offset = output.offset + level_offset;
|
||||
level_offset += output_size;
|
||||
|
||||
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(out_buffer, out_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);
|
||||
|
||||
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) {
|
||||
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 +1151,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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1198,6 +1248,10 @@ bool BlockLinearUnswizzle3DBufferPass::IsSupported(const Device& device,
|
||||
if (info.size.depth <= 1) {
|
||||
return false;
|
||||
}
|
||||
if (VideoCore::Surface::GetFormatType(info.format) !=
|
||||
VideoCore::Surface::SurfaceType::ColorTexture) {
|
||||
return false;
|
||||
}
|
||||
if (VideoCore::Surface::IsPixelFormatASTC(info.format)) {
|
||||
return false;
|
||||
}
|
||||
@@ -1288,13 +1342,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 +1368,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;
|
||||
|
||||
@@ -1901,11 +1901,9 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
|
||||
} else if (runtime->bl2d_unswizzle_pass &&
|
||||
BlockLinearUnswizzle2DPass::IsSupported(runtime->device, info)) {
|
||||
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
||||
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
|
||||
} else if (runtime->bl3db_unswizzle_pass &&
|
||||
BlockLinearUnswizzle3DBufferPass::IsSupported(runtime->device, info)) {
|
||||
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
||||
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
|
||||
}
|
||||
if (IsPixelFormatBCn(info.format) && !runtime->device.IsOptimalBcnSupported()) {
|
||||
flags |= VideoCommon::ImageFlagBits::Converted;
|
||||
@@ -3149,7 +3147,7 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles,
|
||||
u32 z_start, u32 z_count) {
|
||||
|
||||
if (IsPixelFormatASTC(image.info.format)) {
|
||||
if (astc_decoder_pass && WillUseAcceleratedAstcDecode(device, image.info)) {
|
||||
return astc_decoder_pass->Assemble(image, map, swizzles);
|
||||
}
|
||||
|
||||
@@ -3157,7 +3155,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 +3175,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);
|
||||
|
||||
@@ -490,13 +490,29 @@ namespace Vulkan {
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
|
||||
const bool want_address = device.IsBufferDeviceAddressSupported();
|
||||
VkBufferUsageFlags minimal_usage = TransferUsage | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
if (want_address) {
|
||||
shader_usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
minimal_usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
}
|
||||
|
||||
const auto reset_windows = [&] {
|
||||
for (Window &window : windows) {
|
||||
if (window.buffer != VK_NULL_HANDLE) {
|
||||
logical.DestroyBufferRaw(window.buffer);
|
||||
}
|
||||
}
|
||||
windows.clear();
|
||||
imported_size = 0;
|
||||
};
|
||||
|
||||
bindable = import_all(shader_usage, want_address);
|
||||
if (!bindable) {
|
||||
imported_size = 0;
|
||||
reset_windows();
|
||||
bindable = import_all(minimal_usage, want_address);
|
||||
}
|
||||
if (!bindable) {
|
||||
reset_windows();
|
||||
import_all(TransferUsage, false);
|
||||
}
|
||||
if (windows.empty()) {
|
||||
@@ -651,6 +667,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