mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-27 01:17:40 +00:00
[TEST] Bring the unswizzle work from tiled-gpu-v2 x2 + revert of vertex, indexes from AHB path
This commit is contained in:
@@ -821,20 +821,6 @@ void BufferCache<P>::BindHostIndexBuffer() {
|
||||
const u32 size = channel_state->index_buffer.size;
|
||||
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
||||
if (draw_state.inline_index_draw_indexes.empty()) {
|
||||
if constexpr (USE_UNIFIED_MEMORY && !HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||
const auto window =
|
||||
TryResolveUnifiedRange(channel_state->index_buffer.device_addr, size);
|
||||
if (window && runtime.IsUnifiedIndexRange(draw_state.topology,
|
||||
draw_state.index_buffer.format,
|
||||
window->offset)) {
|
||||
runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format,
|
||||
draw_state.index_buffer.first,
|
||||
draw_state.index_buffer.count,
|
||||
runtime.UnifiedWindowBuffer(window->window),
|
||||
static_cast<u32>(window->offset), size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size);
|
||||
} else {
|
||||
if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
|
||||
@@ -888,7 +874,6 @@ void BufferCache<P>::UpdateVertexBufferSlot(u32 index, const Binding& binding) {
|
||||
enabled_vertex_buffers_mask |= (1u << index);
|
||||
} else {
|
||||
enabled_vertex_buffers_mask &= ~(1u << index);
|
||||
unified_vertex_buffers_mask &= ~(1u << index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -921,39 +906,15 @@ void BufferCache<P>::BindHostVertexBuffers() {
|
||||
const Binding& binding = VertexBufferSlot(index);
|
||||
Buffer& buffer = slot_buffers[binding.buffer_id];
|
||||
TouchBuffer(buffer, binding.buffer_id);
|
||||
bool needs_bind = flags[Dirty::VertexBuffer0 + index];
|
||||
u32 unified_window = NO_UNIFIED_WINDOW;
|
||||
u64 unified_offset = 0;
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
const bool was_unified = ((unified_vertex_buffers_mask >> index) & 1) != 0;
|
||||
if (needs_bind || was_unified) {
|
||||
const auto window = TryResolveUnifiedRange(binding.device_addr, binding.size);
|
||||
if (window) {
|
||||
unified_window = static_cast<u32>(window->window);
|
||||
unified_offset = window->offset;
|
||||
}
|
||||
}
|
||||
if (was_unified && unified_window == NO_UNIFIED_WINDOW) {
|
||||
needs_bind = true;
|
||||
}
|
||||
}
|
||||
if (unified_window == NO_UNIFIED_WINDOW) {
|
||||
SynchronizeBuffer(buffer, binding.device_addr, binding.size);
|
||||
}
|
||||
if (!needs_bind) {
|
||||
SynchronizeBuffer(buffer, binding.device_addr, binding.size);
|
||||
if (!flags[Dirty::VertexBuffer0 + index]) {
|
||||
flush_bindings();
|
||||
continue;
|
||||
}
|
||||
flags[Dirty::VertexBuffer0 + index] = false;
|
||||
const u32 stride = maxwell3d->regs.vertex_streams[index].stride;
|
||||
u32 offset = static_cast<u32>(unified_offset);
|
||||
if (unified_window == NO_UNIFIED_WINDOW) {
|
||||
offset = buffer.Offset(binding.device_addr);
|
||||
buffer.MarkUsage(offset, binding.size);
|
||||
unified_vertex_buffers_mask &= ~(1u << index);
|
||||
} else {
|
||||
unified_vertex_buffers_mask |= 1u << index;
|
||||
}
|
||||
const u32 offset = buffer.Offset(binding.device_addr);
|
||||
buffer.MarkUsage(offset, binding.size);
|
||||
if (!bindings.buffers.empty() && index != last_index + 1) {
|
||||
flush_bindings();
|
||||
}
|
||||
@@ -964,7 +925,6 @@ void BufferCache<P>::BindHostVertexBuffers() {
|
||||
bindings.offsets.push_back(offset);
|
||||
bindings.sizes.push_back(binding.size);
|
||||
bindings.strides.push_back(stride);
|
||||
bindings.unified_windows.push_back(unified_window);
|
||||
last_index = index;
|
||||
}
|
||||
flush_bindings();
|
||||
@@ -972,31 +932,12 @@ void BufferCache<P>::BindHostVertexBuffers() {
|
||||
HostBindings<typename P::Buffer> host_bindings;
|
||||
bool any_valid{false};
|
||||
auto& flags = maxwell3d->dirty.flags;
|
||||
std::array<u32, NUM_VERTEX_BUFFERS> unified_windows;
|
||||
std::array<u64, NUM_VERTEX_BUFFERS> unified_offsets{};
|
||||
unified_windows.fill(NO_UNIFIED_WINDOW);
|
||||
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
|
||||
const Binding& binding = channel_state->vertex_buffers[index];
|
||||
Buffer& buffer = slot_buffers[binding.buffer_id];
|
||||
TouchBuffer(buffer, binding.buffer_id);
|
||||
bool needs_bind = flags[Dirty::VertexBuffer0 + index];
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
const bool was_unified = ((unified_vertex_buffers_mask >> index) & 1) != 0;
|
||||
if (needs_bind || was_unified) {
|
||||
const auto window = TryResolveUnifiedRange(binding.device_addr, binding.size);
|
||||
if (window) {
|
||||
unified_windows[index] = static_cast<u32>(window->window);
|
||||
unified_offsets[index] = window->offset;
|
||||
}
|
||||
}
|
||||
if (was_unified && unified_windows[index] == NO_UNIFIED_WINDOW) {
|
||||
needs_bind = true;
|
||||
}
|
||||
}
|
||||
if (unified_windows[index] == NO_UNIFIED_WINDOW) {
|
||||
SynchronizeBuffer(buffer, binding.device_addr, binding.size);
|
||||
}
|
||||
if (!needs_bind) {
|
||||
SynchronizeBuffer(buffer, binding.device_addr, binding.size);
|
||||
if (!flags[Dirty::VertexBuffer0 + index]) {
|
||||
continue;
|
||||
}
|
||||
flags[Dirty::VertexBuffer0 + index] = false;
|
||||
@@ -1015,20 +956,13 @@ void BufferCache<P>::BindHostVertexBuffers() {
|
||||
Buffer& buffer = slot_buffers[binding.buffer_id];
|
||||
|
||||
const u32 stride = maxwell3d->regs.vertex_streams[index].stride;
|
||||
u32 offset = static_cast<u32>(unified_offsets[index]);
|
||||
if (unified_windows[index] == NO_UNIFIED_WINDOW) {
|
||||
offset = buffer.Offset(binding.device_addr);
|
||||
buffer.MarkUsage(offset, binding.size);
|
||||
unified_vertex_buffers_mask &= ~(1u << index);
|
||||
} else {
|
||||
unified_vertex_buffers_mask |= 1u << index;
|
||||
}
|
||||
const u32 offset = buffer.Offset(binding.device_addr);
|
||||
buffer.MarkUsage(offset, binding.size);
|
||||
|
||||
host_bindings.buffers.push_back(&buffer);
|
||||
host_bindings.offsets.push_back(offset);
|
||||
host_bindings.sizes.push_back(binding.size);
|
||||
host_bindings.strides.push_back(stride);
|
||||
host_bindings.unified_windows.push_back(unified_windows[index]);
|
||||
}
|
||||
runtime.BindVertexBuffers(host_bindings);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
@@ -97,15 +96,12 @@ static constexpr Binding NULL_BINDING{
|
||||
.buffer_id = NULL_BUFFER_ID,
|
||||
};
|
||||
|
||||
static constexpr u32 NO_UNIFIED_WINDOW = (std::numeric_limits<u32>::max)();
|
||||
|
||||
template <typename Buffer>
|
||||
struct HostBindings {
|
||||
boost::container::static_vector<Buffer*, NUM_VERTEX_BUFFERS> buffers;
|
||||
boost::container::static_vector<u64, NUM_VERTEX_BUFFERS> offsets;
|
||||
boost::container::static_vector<u64, NUM_VERTEX_BUFFERS> sizes;
|
||||
boost::container::static_vector<u64, NUM_VERTEX_BUFFERS> strides;
|
||||
boost::container::static_vector<u32, NUM_VERTEX_BUFFERS> unified_windows;
|
||||
u32 min_index{NUM_VERTEX_BUFFERS};
|
||||
u32 max_index{0};
|
||||
};
|
||||
@@ -509,7 +505,6 @@ private:
|
||||
u32 last_index_count = 0;
|
||||
|
||||
u32 enabled_vertex_buffers_mask = 0;
|
||||
u32 unified_vertex_buffers_mask = 0;
|
||||
u64 vertex_buffers_serial = 0;
|
||||
std::array<Binding, 32> v_buffer{};
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@ set(SHADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/astc_decoder.comp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_float.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_2d.comp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_2d_buffer.comp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_msaa.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/blit_depth.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/blit_depth_msaa.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/blit_depth_stencil_msaa.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d.comp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d_bcn.comp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d_buffer.comp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_abgr8_to_d24s8.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_abgr8_to_d32f.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_d32f_to_abgr8.frag
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#version 430
|
||||
|
||||
#extension GL_EXT_shader_16bit_storage : require
|
||||
#extension GL_EXT_shader_8bit_storage : require
|
||||
|
||||
#define BINDING_INPUT_BUFFER 0
|
||||
#define BINDING_OUTPUT_BUFFER 1
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
uvec3 dim;
|
||||
uint bytes_per_block_log2;
|
||||
|
||||
uvec3 origin;
|
||||
uint layer_stride;
|
||||
|
||||
uint block_size;
|
||||
uint x_shift;
|
||||
uint block_height;
|
||||
uint block_height_mask;
|
||||
} pc;
|
||||
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU32 { uint u32data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU64 { uvec2 u64data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU128 { uvec4 u128data[]; };
|
||||
|
||||
layout(binding = BINDING_OUTPUT_BUFFER, std430) writeonly buffer OutputBuffer {
|
||||
uint out_u32[];
|
||||
};
|
||||
|
||||
layout(local_size_x = 16, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
const uint GOB_SIZE_X = 64;
|
||||
const uint GOB_SIZE_Y = 8;
|
||||
|
||||
const uint GOB_SIZE_X_SHIFT = 6;
|
||||
const uint GOB_SIZE_Y_SHIFT = 3;
|
||||
const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT;
|
||||
|
||||
const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1u, GOB_SIZE_Y - 1u);
|
||||
|
||||
uint SwizzleTable(uint pos) {
|
||||
const uint t[8] = uint[](
|
||||
0x12100200, 0x13110301, 0x16140604, 0x17150705,
|
||||
0x1a180a08, 0x1b190b09, 0x1e1c0e0c, 0x1f1d0f0d
|
||||
);
|
||||
const uint i = pos >> 4;
|
||||
const uint h = (t[i / 4] >> ((i % 4) * 8)) & 0xff;
|
||||
return (h << 4) | (pos & 0xf);
|
||||
}
|
||||
|
||||
uint SwizzleOffset(uvec2 pos) {
|
||||
pos = pos & SWIZZLE_MASK;
|
||||
return SwizzleTable(pos.y * 64u + pos.x);
|
||||
}
|
||||
|
||||
uvec4 ReadTexel(uint offset) {
|
||||
switch (pc.bytes_per_block_log2) {
|
||||
case 2u:
|
||||
return uvec4(u32data[offset / 4u], 0u, 0u, 0u);
|
||||
case 3u:
|
||||
return uvec4(u64data[offset / 8u], 0u, 0u);
|
||||
case 4u:
|
||||
return u128data[offset / 16u];
|
||||
}
|
||||
return uvec4(0u);
|
||||
}
|
||||
|
||||
void main() {
|
||||
uvec3 coord = gl_GlobalInvocationID;
|
||||
if (coord.x >= pc.dim.x || coord.y >= pc.dim.y || coord.z >= pc.dim.z) {
|
||||
return;
|
||||
}
|
||||
|
||||
uvec3 pos = coord + pc.origin;
|
||||
pos.x <<= pc.bytes_per_block_log2;
|
||||
|
||||
uint swizzle = SwizzleOffset(pos.xy);
|
||||
uint block_y = pos.y >> GOB_SIZE_Y_SHIFT;
|
||||
|
||||
uint offset = 0u;
|
||||
offset += pos.z * pc.layer_stride;
|
||||
offset += (block_y >> pc.block_height) * pc.block_size;
|
||||
offset += (block_y & pc.block_height_mask) << GOB_SIZE_SHIFT;
|
||||
offset += (pos.x >> GOB_SIZE_X_SHIFT) << pc.x_shift;
|
||||
offset += swizzle;
|
||||
|
||||
uvec4 texel = ReadTexel(offset);
|
||||
|
||||
uint words = 1u << (pc.bytes_per_block_log2 - 2u);
|
||||
uint linear_index = coord.x + coord.y * pc.dim.x + coord.z * pc.dim.x * pc.dim.y;
|
||||
uint out_idx = linear_index * words;
|
||||
|
||||
out_u32[out_idx] = texel.x;
|
||||
if (words > 1u) {
|
||||
out_u32[out_idx + 1u] = texel.y;
|
||||
}
|
||||
if (words > 2u) {
|
||||
out_u32[out_idx + 2u] = texel.z;
|
||||
out_u32[out_idx + 3u] = texel.w;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#version 430
|
||||
|
||||
#define BINDING_INPUT_BUFFER 0
|
||||
#define BINDING_OUTPUT_BUFFER 1
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
uvec3 dim;
|
||||
uint bytes_per_block_log2;
|
||||
|
||||
uvec3 origin;
|
||||
uint slice_size;
|
||||
|
||||
uint block_size;
|
||||
uint x_shift;
|
||||
uint block_height;
|
||||
uint block_height_mask;
|
||||
|
||||
uint block_depth;
|
||||
uint block_depth_mask;
|
||||
} pc;
|
||||
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU32 { uint u32data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU64 { uvec2 u64data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU128 { uvec4 u128data[]; };
|
||||
|
||||
layout(binding = BINDING_OUTPUT_BUFFER, std430) writeonly buffer OutputBuffer {
|
||||
uint out_u32[];
|
||||
};
|
||||
|
||||
layout(local_size_x = 8, local_size_y = 8, local_size_z = 4) in;
|
||||
|
||||
const uint GOB_SIZE_X = 64;
|
||||
const uint GOB_SIZE_Y = 8;
|
||||
|
||||
const uint GOB_SIZE_X_SHIFT = 6;
|
||||
const uint GOB_SIZE_Y_SHIFT = 3;
|
||||
const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT;
|
||||
|
||||
const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1u, GOB_SIZE_Y - 1u);
|
||||
|
||||
uint SwizzleTable(uint pos) {
|
||||
const uint t[8] = uint[](
|
||||
0x12100200, 0x13110301, 0x16140604, 0x17150705,
|
||||
0x1a180a08, 0x1b190b09, 0x1e1c0e0c, 0x1f1d0f0d
|
||||
);
|
||||
const uint i = pos >> 4;
|
||||
const uint h = (t[i / 4] >> ((i % 4) * 8)) & 0xff;
|
||||
return (h << 4) | (pos & 0xf);
|
||||
}
|
||||
|
||||
uint SwizzleOffset(uvec2 pos) {
|
||||
pos = pos & SWIZZLE_MASK;
|
||||
return SwizzleTable(pos.y * 64u + pos.x);
|
||||
}
|
||||
|
||||
uvec4 ReadTexel(uint offset) {
|
||||
switch (pc.bytes_per_block_log2) {
|
||||
case 2u:
|
||||
return uvec4(u32data[offset / 4u], 0u, 0u, 0u);
|
||||
case 3u:
|
||||
return uvec4(u64data[offset / 8u], 0u, 0u);
|
||||
case 4u:
|
||||
return u128data[offset / 16u];
|
||||
}
|
||||
return uvec4(0u);
|
||||
}
|
||||
|
||||
void main() {
|
||||
uvec3 coord = gl_GlobalInvocationID;
|
||||
if (coord.x >= pc.dim.x || coord.y >= pc.dim.y || coord.z >= pc.dim.z) {
|
||||
return;
|
||||
}
|
||||
|
||||
uvec3 pos = coord + pc.origin;
|
||||
pos.x <<= pc.bytes_per_block_log2;
|
||||
|
||||
uint swizzle = SwizzleOffset(pos.xy);
|
||||
uint block_y = pos.y >> GOB_SIZE_Y_SHIFT;
|
||||
|
||||
uint offset = 0u;
|
||||
offset += (pos.z >> pc.block_depth) * pc.slice_size;
|
||||
offset += (pos.z & pc.block_depth_mask) << (GOB_SIZE_SHIFT + pc.block_height);
|
||||
offset += (block_y >> pc.block_height) * pc.block_size;
|
||||
offset += (block_y & pc.block_height_mask) << GOB_SIZE_SHIFT;
|
||||
offset += (pos.x >> GOB_SIZE_X_SHIFT) << pc.x_shift;
|
||||
offset += swizzle;
|
||||
|
||||
uvec4 texel = ReadTexel(offset);
|
||||
|
||||
uint words = 1u << (pc.bytes_per_block_log2 - 2u);
|
||||
uint linear_index = coord.x + coord.y * pc.dim.x + coord.z * pc.dim.x * pc.dim.y;
|
||||
uint out_idx = linear_index * words;
|
||||
|
||||
out_u32[out_idx] = texel.x;
|
||||
if (words > 1u) {
|
||||
out_u32[out_idx + 1u] = texel.y;
|
||||
}
|
||||
if (words > 2u) {
|
||||
out_u32[out_idx + 2u] = texel.z;
|
||||
out_u32[out_idx + 3u] = texel.w;
|
||||
}
|
||||
}
|
||||
@@ -727,25 +727,6 @@ void BufferCacheRuntime::ClearBuffer(VkBuffer dest_buffer, u32 offset, size_t si
|
||||
});
|
||||
}
|
||||
|
||||
bool BufferCacheRuntime::IsUnifiedIndexRange(PrimitiveTopology topology, IndexFormat index_format,
|
||||
u64 offset) const {
|
||||
const VkIndexType vk_index_type = MaxwellToVK::IndexFormat(index_format);
|
||||
const bool needs_uint8_pass =
|
||||
vk_index_type == VK_INDEX_TYPE_UINT8_EXT && !device.IsExtIndexTypeUint8Supported();
|
||||
if (topology == PrimitiveTopology::Quads || topology == PrimitiveTopology::QuadStrip ||
|
||||
needs_uint8_pass) {
|
||||
return (offset % device.GetStorageBufferAlignment()) == 0;
|
||||
}
|
||||
switch (vk_index_type) {
|
||||
case VK_INDEX_TYPE_UINT32:
|
||||
return (offset % 4) == 0;
|
||||
case VK_INDEX_TYPE_UINT16:
|
||||
return (offset % 2) == 0;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindIndexBuffer(PrimitiveTopology topology, IndexFormat index_format,
|
||||
u32 base_vertex, u32 num_indices, VkBuffer buffer,
|
||||
u32 offset, [[maybe_unused]] u32 size) {
|
||||
@@ -821,11 +802,6 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset
|
||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
||||
boost::container::static_vector<VkBuffer, VideoCommon::NUM_VERTEX_BUFFERS> buffer_handles(bindings.buffers.size());
|
||||
for (u32 i = 0; i < bindings.buffers.size(); ++i) {
|
||||
if (i < bindings.unified_windows.size() &&
|
||||
bindings.unified_windows[i] != VideoCommon::NO_UNIFIED_WINDOW) {
|
||||
buffer_handles[i] = unified_memory->GetWindowBuffer(bindings.unified_windows[i]);
|
||||
continue;
|
||||
}
|
||||
auto handle = bindings.buffers[i]->Handle();
|
||||
if (handle == VK_NULL_HANDLE) {
|
||||
bindings.offsets[i] = 0;
|
||||
|
||||
@@ -218,9 +218,6 @@ public:
|
||||
(offset % device.GetStorageBufferAlignment()) == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsUnifiedIndexRange(PrimitiveTopology topology, IndexFormat index_format,
|
||||
u64 offset) const;
|
||||
|
||||
void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size,
|
||||
VideoCore::Surface::PixelFormat format) {
|
||||
guest_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format),
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
|
||||
#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
|
||||
#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
|
||||
#include "video_core/host_shaders/block_linear_unswizzle_2d_buffer_comp_spv.h"
|
||||
#include "video_core/host_shaders/block_linear_unswizzle_3d_bcn_comp_spv.h"
|
||||
#include "video_core/host_shaders/block_linear_unswizzle_3d_buffer_comp_spv.h"
|
||||
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
||||
#include "video_core/surface.h"
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||
@@ -872,4 +874,480 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
|
||||
});
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr u32 BL2D_BINDING_INPUT_BUFFER = 0;
|
||||
constexpr u32 BL2D_BINDING_OUTPUT_BUFFER = 1;
|
||||
|
||||
struct alignas(16) BlockLinearUnswizzle2DPushConstants {
|
||||
std::array<u32, 3> dim;
|
||||
u32 bytes_per_block_log2;
|
||||
std::array<u32, 3> origin;
|
||||
u32 layer_stride;
|
||||
u32 block_size;
|
||||
u32 x_shift;
|
||||
u32 block_height;
|
||||
u32 block_height_mask;
|
||||
};
|
||||
static_assert(sizeof(BlockLinearUnswizzle2DPushConstants) <= 128);
|
||||
|
||||
constexpr std::array<VkDescriptorSetLayoutBinding, 2> BL2D_BINDINGS{{
|
||||
{
|
||||
.binding = BL2D_BINDING_INPUT_BUFFER,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
.pImmutableSamplers = nullptr,
|
||||
},
|
||||
{
|
||||
.binding = BL2D_BINDING_OUTPUT_BUFFER,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
.pImmutableSamplers = nullptr,
|
||||
},
|
||||
}};
|
||||
|
||||
constexpr std::array<VkDescriptorUpdateTemplateEntry, 2> BL2D_TEMPLATE{{
|
||||
{
|
||||
.dstBinding = BL2D_BINDING_INPUT_BUFFER,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.offset = BL2D_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry),
|
||||
.stride = sizeof(DescriptorUpdateEntry),
|
||||
},
|
||||
{
|
||||
.dstBinding = BL2D_BINDING_OUTPUT_BUFFER,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.offset = BL2D_BINDING_OUTPUT_BUFFER * sizeof(DescriptorUpdateEntry),
|
||||
.stride = sizeof(DescriptorUpdateEntry),
|
||||
},
|
||||
}};
|
||||
|
||||
constexpr DescriptorBankInfo BL2D_BANK_INFO{
|
||||
.uniform_buffers = 0,
|
||||
.storage_buffers = 2,
|
||||
.texture_buffers = 0,
|
||||
.image_buffers = 0,
|
||||
.textures = 0,
|
||||
.images = 0,
|
||||
.score = 2,
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
BlockLinearUnswizzle2DPass::BlockLinearUnswizzle2DPass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
StagingBufferPool& staging_buffer_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||
: ComputePass(device_, scheduler_, descriptor_pool_, BL2D_BINDINGS, BL2D_TEMPLATE,
|
||||
BL2D_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(BlockLinearUnswizzle2DPushConstants)>,
|
||||
BLOCK_LINEAR_UNSWIZZLE_2D_BUFFER_COMP_SPV),
|
||||
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
|
||||
compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||
|
||||
BlockLinearUnswizzle2DPass::~BlockLinearUnswizzle2DPass() = default;
|
||||
|
||||
bool BlockLinearUnswizzle2DPass::IsSupported(const Device& device,
|
||||
const VideoCommon::ImageInfo& info) {
|
||||
if (info.type != VideoCommon::ImageType::e2D) {
|
||||
return false;
|
||||
}
|
||||
if (info.resources.levels != 1 || info.resources.layers != 1) {
|
||||
return false;
|
||||
}
|
||||
if (info.num_samples > 1) {
|
||||
return false;
|
||||
}
|
||||
if (VideoCore::Surface::IsPixelFormatASTC(info.format) && !device.IsOptimalAstcSupported()) {
|
||||
return false;
|
||||
}
|
||||
if (VideoCore::Surface::IsPixelFormatBCn(info.format) && !device.IsOptimalBcnSupported()) {
|
||||
return false;
|
||||
}
|
||||
const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format);
|
||||
return bytes_per_block == 4 || bytes_per_block == 8 || bytes_per_block == 16;
|
||||
}
|
||||
|
||||
void BlockLinearUnswizzle2DPass::Unswizzle(
|
||||
Image& image, const StagingBufferRef& swizzled,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
if (swizzles.empty()) {
|
||||
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;
|
||||
|
||||
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, width, 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{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_READ_BIT
|
||||
: VK_ACCESS_NONE),
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.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);
|
||||
|
||||
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);
|
||||
|
||||
const VkImageMemoryBarrier post_copy{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
|
||||
0, {}, {}, post_copy);
|
||||
});
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr u32 BL3DB_BINDING_INPUT_BUFFER = 0;
|
||||
constexpr u32 BL3DB_BINDING_OUTPUT_BUFFER = 1;
|
||||
|
||||
struct alignas(16) BlockLinearUnswizzle3DBufferPushConstants {
|
||||
std::array<u32, 3> dim;
|
||||
u32 bytes_per_block_log2;
|
||||
std::array<u32, 3> origin;
|
||||
u32 slice_size;
|
||||
u32 block_size;
|
||||
u32 x_shift;
|
||||
u32 block_height;
|
||||
u32 block_height_mask;
|
||||
u32 block_depth;
|
||||
u32 block_depth_mask;
|
||||
};
|
||||
static_assert(sizeof(BlockLinearUnswizzle3DBufferPushConstants) <= 128);
|
||||
|
||||
constexpr std::array<VkDescriptorSetLayoutBinding, 2> BL3DB_BINDINGS{{
|
||||
{
|
||||
.binding = BL3DB_BINDING_INPUT_BUFFER,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
.pImmutableSamplers = nullptr,
|
||||
},
|
||||
{
|
||||
.binding = BL3DB_BINDING_OUTPUT_BUFFER,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
.pImmutableSamplers = nullptr,
|
||||
},
|
||||
}};
|
||||
|
||||
constexpr std::array<VkDescriptorUpdateTemplateEntry, 2> BL3DB_TEMPLATE{{
|
||||
{
|
||||
.dstBinding = BL3DB_BINDING_INPUT_BUFFER,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.offset = BL3DB_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry),
|
||||
.stride = sizeof(DescriptorUpdateEntry),
|
||||
},
|
||||
{
|
||||
.dstBinding = BL3DB_BINDING_OUTPUT_BUFFER,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.offset = BL3DB_BINDING_OUTPUT_BUFFER * sizeof(DescriptorUpdateEntry),
|
||||
.stride = sizeof(DescriptorUpdateEntry),
|
||||
},
|
||||
}};
|
||||
|
||||
constexpr DescriptorBankInfo BL3DB_BANK_INFO{
|
||||
.uniform_buffers = 0,
|
||||
.storage_buffers = 2,
|
||||
.texture_buffers = 0,
|
||||
.image_buffers = 0,
|
||||
.textures = 0,
|
||||
.images = 0,
|
||||
.score = 2,
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
BlockLinearUnswizzle3DBufferPass::BlockLinearUnswizzle3DBufferPass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
StagingBufferPool& staging_buffer_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||
: ComputePass(device_, scheduler_, descriptor_pool_, BL3DB_BINDINGS, BL3DB_TEMPLATE,
|
||||
BL3DB_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(BlockLinearUnswizzle3DBufferPushConstants)>,
|
||||
BLOCK_LINEAR_UNSWIZZLE_3D_BUFFER_COMP_SPV),
|
||||
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
|
||||
compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||
|
||||
BlockLinearUnswizzle3DBufferPass::~BlockLinearUnswizzle3DBufferPass() = default;
|
||||
|
||||
bool BlockLinearUnswizzle3DBufferPass::IsSupported(const Device& device,
|
||||
const VideoCommon::ImageInfo& info) {
|
||||
if (info.type != VideoCommon::ImageType::e3D) {
|
||||
return false;
|
||||
}
|
||||
if (info.resources.levels != 1 || info.resources.layers != 1) {
|
||||
return false;
|
||||
}
|
||||
if (info.num_samples > 1) {
|
||||
return false;
|
||||
}
|
||||
if (info.size.depth <= 1) {
|
||||
return false;
|
||||
}
|
||||
if (VideoCore::Surface::IsPixelFormatASTC(info.format)) {
|
||||
return false;
|
||||
}
|
||||
if (VideoCore::Surface::IsPixelFormatBCn(info.format) && !device.IsOptimalBcnSupported()) {
|
||||
return false;
|
||||
}
|
||||
const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format);
|
||||
return bytes_per_block == 4 || bytes_per_block == 8 || bytes_per_block == 16;
|
||||
}
|
||||
|
||||
void BlockLinearUnswizzle3DBufferPass::Unswizzle(
|
||||
Image& image, const StagingBufferRef& swizzled,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
if (swizzles.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const VideoCommon::SwizzleParameters& sw = swizzles.front();
|
||||
const auto params = VideoCommon::Accelerated::MakeBlockLinearSwizzle3DParams(sw, image.info);
|
||||
|
||||
const u32 blocks_x = sw.num_tiles.width;
|
||||
const u32 blocks_y = sw.num_tiles.height;
|
||||
const u32 blocks_z = sw.num_tiles.depth;
|
||||
const u32 bytes_per_block = 1u << params.bytes_per_block_log2;
|
||||
const VkDeviceSize output_size =
|
||||
static_cast<VkDeviceSize>(blocks_x) * blocks_y * blocks_z * bytes_per_block;
|
||||
|
||||
const StagingBufferRef output =
|
||||
staging_buffer_pool.Request(static_cast<size_t>(output_size), MemoryUsage::DeviceLocal);
|
||||
|
||||
BlockLinearUnswizzle3DBufferPushConstants pc{};
|
||||
pc.dim = {blocks_x, blocks_y, blocks_z};
|
||||
pc.bytes_per_block_log2 = params.bytes_per_block_log2;
|
||||
pc.origin = params.origin;
|
||||
pc.slice_size = params.slice_size;
|
||||
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;
|
||||
pc.block_depth = params.block_depth;
|
||||
pc.block_depth_mask = params.block_depth_mask;
|
||||
|
||||
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(blocks_x, 8u);
|
||||
const u32 gy = Common::DivCeil(blocks_y, 8u);
|
||||
const u32 gz = Common::DivCeil(blocks_z, 4u);
|
||||
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();
|
||||
const VkExtent3D extent{
|
||||
.width = image.info.size.width,
|
||||
.height = image.info.size.height,
|
||||
.depth = image.info.size.depth,
|
||||
};
|
||||
|
||||
scheduler.Record([this, set, descriptor_data, pc, gx, gy, gz, output_size, out_buffer,
|
||||
out_offset, dst_image, aspect, extent,
|
||||
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, gz);
|
||||
|
||||
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{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_READ_BIT
|
||||
: VK_ACCESS_NONE),
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.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);
|
||||
|
||||
const VkBufferImageCopy copy{
|
||||
.bufferOffset = out_offset,
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource{
|
||||
.aspectMask = aspect,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.imageOffset = {0, 0, 0},
|
||||
.imageExtent = extent,
|
||||
};
|
||||
cmdbuf.CopyBufferToImage(out_buffer, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy);
|
||||
|
||||
const VkImageMemoryBarrier post_copy{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
|
||||
0, {}, {}, post_copy);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -164,4 +164,43 @@ private:
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
class BlockLinearUnswizzle2DPass final : public ComputePass {
|
||||
public:
|
||||
explicit BlockLinearUnswizzle2DPass(const Device& device_, Scheduler& scheduler_,
|
||||
DescriptorPool& descriptor_pool_,
|
||||
StagingBufferPool& staging_buffer_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||
~BlockLinearUnswizzle2DPass();
|
||||
|
||||
[[nodiscard]] static bool IsSupported(const Device& device,
|
||||
const VideoCommon::ImageInfo& info);
|
||||
|
||||
void Unswizzle(Image& image, const StagingBufferRef& swizzled,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||
|
||||
private:
|
||||
Scheduler& scheduler;
|
||||
StagingBufferPool& staging_buffer_pool;
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
class BlockLinearUnswizzle3DBufferPass final : public ComputePass {
|
||||
public:
|
||||
explicit BlockLinearUnswizzle3DBufferPass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
StagingBufferPool& staging_buffer_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||
~BlockLinearUnswizzle3DBufferPass();
|
||||
|
||||
[[nodiscard]] static bool IsSupported(const Device& device, const VideoCommon::ImageInfo& info);
|
||||
|
||||
void Unswizzle(Image& image, const StagingBufferRef& swizzled,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||
|
||||
private:
|
||||
Scheduler& scheduler;
|
||||
StagingBufferPool& staging_buffer_pool;
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -968,6 +968,10 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
|
||||
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
||||
staging_buffer_pool, compute_pass_descriptor_queue);
|
||||
}
|
||||
bl2d_unswizzle_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
|
||||
compute_pass_descriptor_queue);
|
||||
bl3db_unswizzle_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
|
||||
compute_pass_descriptor_queue);
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::Finish() {
|
||||
@@ -1894,6 +1898,14 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
|
||||
}
|
||||
flags |= VideoCommon::ImageFlagBits::Converted;
|
||||
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
|
||||
} 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;
|
||||
@@ -3141,6 +3153,15 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
||||
return astc_decoder_pass->Assemble(image, map, swizzles);
|
||||
}
|
||||
|
||||
if (bl2d_unswizzle_pass && BlockLinearUnswizzle2DPass::IsSupported(device, image.info)) {
|
||||
return bl2d_unswizzle_pass->Unswizzle(image, map, swizzles);
|
||||
}
|
||||
|
||||
if (bl3db_unswizzle_pass &&
|
||||
BlockLinearUnswizzle3DBufferPass::IsSupported(device, image.info)) {
|
||||
return bl3db_unswizzle_pass->Unswizzle(image, map, swizzles);
|
||||
}
|
||||
|
||||
if (!Settings::values.gpu_unswizzle_enabled.GetValue() || !bl3d_unswizzle_pass) {
|
||||
if (IsPixelFormatBCn(image.info.format) && image.info.type == ImageType::e3D) {
|
||||
ASSERT(false && "GPU unswizzle is disabled for BCn 3D texture");
|
||||
|
||||
@@ -159,6 +159,8 @@ public:
|
||||
std::optional<ASTCDecoderPass> astc_decoder_pass;
|
||||
|
||||
std::optional<BlockLinearUnswizzle3DPass> bl3d_unswizzle_pass;
|
||||
std::optional<BlockLinearUnswizzle2DPass> bl2d_unswizzle_pass;
|
||||
std::optional<BlockLinearUnswizzle3DBufferPass> bl3db_unswizzle_pass;
|
||||
const Settings::ResolutionScalingInfo& resolution;
|
||||
std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user