Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f0f6e6306 | ||
|
|
d43238b9af | ||
|
|
2addf1556e | ||
|
|
883cdead8b | ||
|
|
104bfa3a8f | ||
|
|
023c4758e9 | ||
|
|
b9239c4944 | ||
|
|
f229172d3b | ||
|
|
eb18c5b8bd | ||
|
|
0c7d068112 | ||
|
|
f29a23738a | ||
|
|
7e5e326842 | ||
|
|
f93e4031ba | ||
|
|
7e55b4b563 | ||
|
|
ee5049f0d3 | ||
|
|
15de6e0e08 | ||
|
|
75519010d2 | ||
|
|
3e61e6da87 | ||
|
|
8242e54e42 | ||
|
|
47b310266e | ||
|
|
3cfac4abcd | ||
|
|
92c52342b8 | ||
|
|
db2bdde9b3 | ||
|
|
ce0b15dcf7 | ||
|
|
db922e50e3 | ||
|
|
ca52cf679a |
24 changed files with 844 additions and 200 deletions
|
|
@ -20,8 +20,6 @@ namespace VideoCommon {
|
|||
|
||||
enum class BufferFlagBits {
|
||||
Picked = 1 << 0,
|
||||
CachedWrites = 1 << 1,
|
||||
PreemtiveDownload = 1 << 2,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits)
|
||||
|
||||
|
|
@ -58,15 +56,6 @@ public:
|
|||
flags |= BufferFlagBits::Picked;
|
||||
}
|
||||
|
||||
void MarkPreemtiveDownload() noexcept {
|
||||
flags |= BufferFlagBits::PreemtiveDownload;
|
||||
}
|
||||
|
||||
/// Unmark buffer as picked
|
||||
void Unpick() noexcept {
|
||||
flags &= ~BufferFlagBits::Picked;
|
||||
}
|
||||
|
||||
/// Increases the likeliness of this being a stream buffer
|
||||
void IncreaseStreamScore(int score) noexcept {
|
||||
stream_score += score;
|
||||
|
|
@ -87,15 +76,6 @@ public:
|
|||
return True(flags & BufferFlagBits::Picked);
|
||||
}
|
||||
|
||||
/// Returns true when the buffer has pending cached writes
|
||||
[[nodiscard]] bool HasCachedWrites() const noexcept {
|
||||
return True(flags & BufferFlagBits::CachedWrites);
|
||||
}
|
||||
|
||||
bool IsPreemtiveDownload() const noexcept {
|
||||
return True(flags & BufferFlagBits::PreemtiveDownload);
|
||||
}
|
||||
|
||||
/// Returns the base CPU address of the buffer
|
||||
[[nodiscard]] VAddr CpuAddr() const noexcept {
|
||||
return cpu_addr;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
|
||||
|
|
@ -121,25 +122,6 @@ void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
|
|||
memory_tracker.MarkRegionAsCpuModified(device_addr, size);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::CachedWriteMemory(DAddr device_addr, u64 size) {
|
||||
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
||||
if (!is_dirty) {
|
||||
return;
|
||||
}
|
||||
DAddr aligned_start = Common::AlignDown(device_addr, DEVICE_PAGESIZE);
|
||||
DAddr aligned_end = Common::AlignUp(device_addr + size, DEVICE_PAGESIZE);
|
||||
if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
|
||||
WriteMemory(device_addr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
tmp_buffer.resize_destructive(size);
|
||||
device_memory.ReadBlockUnsafe(device_addr, tmp_buffer.data(), size);
|
||||
|
||||
InlineMemoryImplementation(device_addr, size, tmp_buffer);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
|
||||
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
||||
|
|
@ -422,7 +404,7 @@ void BufferCache<P>::UnbindGraphicsStorageBuffers(size_t stage) {
|
|||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index,
|
||||
void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index,
|
||||
u32 cbuf_offset, bool is_written) {
|
||||
const bool already_enabled =
|
||||
((channel_state->enabled_storage_buffers[stage] >> ssbo_index) & 1U) != 0;
|
||||
|
|
@ -433,7 +415,7 @@ bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
|
|||
LOG_WARNING(HW_GPU,
|
||||
"Skipping graphics storage buffer {} due to driver limit {}",
|
||||
ssbo_index, max_bindings);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -449,7 +431,6 @@ bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
|
|||
const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
|
||||
channel_state->storage_buffers[stage][ssbo_index] =
|
||||
StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
|
||||
return (channel_state->storage_buffers[stage][ssbo_index].buffer_id != NULL_BUFFER_ID);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
|
|
@ -762,16 +743,6 @@ void BufferCache<P>::BindHostIndexBuffer() {
|
|||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size,
|
||||
u32 stride) {
|
||||
if constexpr (IS_OPENGL) {
|
||||
runtime.BindVertexBuffer(index, buffer, offset, size, stride);
|
||||
} else {
|
||||
runtime.BindVertexBuffer(index, buffer.Handle(), offset, size, stride);
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
Binding& BufferCache<P>::VertexBufferSlot(u32 index) {
|
||||
ASSERT(index < NUM_VERTEX_BUFFERS);
|
||||
|
|
@ -1197,7 +1168,7 @@ void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
|
|||
if (is_indexed) {
|
||||
UpdateIndexBuffer();
|
||||
}
|
||||
UpdateVertexBuffers();
|
||||
UpdateVertexBuffers(is_indexed);
|
||||
UpdateTransformFeedbackBuffers();
|
||||
for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
|
||||
UpdateUniformBuffers(stage);
|
||||
|
|
@ -1251,9 +1222,14 @@ void BufferCache<P>::UpdateIndexBuffer() {
|
|||
const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress();
|
||||
const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
|
||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
|
||||
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
|
||||
const u32 draw_size = (index_buffer_ref.count + index_buffer_ref.first) * u32(index_buffer_ref.FormatSizeInBytes());
|
||||
const u32 size = (std::min)(address_size, draw_size);
|
||||
u64 address_size = 0;
|
||||
if (gpu_addr_end > gpu_addr_begin) {
|
||||
address_size = (std::min)(gpu_addr_end - gpu_addr_begin,
|
||||
u64{(std::numeric_limits<u32>::max)()});
|
||||
}
|
||||
const u64 draw_size = (u64{index_buffer_ref.count} + u64{index_buffer_ref.first}) *
|
||||
u64{index_buffer_ref.FormatSizeInBytes()};
|
||||
const u32 size = static_cast<u32>((std::min)(address_size, draw_size));
|
||||
if (size == 0 || !device_addr) {
|
||||
channel_state->index_buffer = NULL_BINDING;
|
||||
return;
|
||||
|
|
@ -1266,20 +1242,142 @@ void BufferCache<P>::UpdateIndexBuffer() {
|
|||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::UpdateVertexBuffers() {
|
||||
u64 BufferCache<P>::DrawMaxIndex() {
|
||||
if (max_index_scanned) {
|
||||
return cached_max_index;
|
||||
}
|
||||
max_index_scanned = true;
|
||||
cached_max_index = 0;
|
||||
const auto& index_buffer_ref = maxwell3d->draw_manager.draw_state.index_buffer;
|
||||
const u32 count = index_buffer_ref.count;
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
index_scan_buffer.resize_destructive(count);
|
||||
gpu_memory->ReadBlockUnsafe(index_buffer_ref.IndexStart(), index_scan_buffer.data(),
|
||||
size_t{count} * sizeof(u32));
|
||||
u32 restart_index = (std::numeric_limits<u32>::max)();
|
||||
if (maxwell3d->regs.primitive_restart.enabled != 0) {
|
||||
restart_index = maxwell3d->regs.primitive_restart.index;
|
||||
}
|
||||
u32 max_index = 0;
|
||||
for (u32 i = 0; i < count; ++i) {
|
||||
const u32 value = index_scan_buffer[i];
|
||||
if (value == restart_index) {
|
||||
continue;
|
||||
}
|
||||
max_index = (std::max)(max_index, value);
|
||||
}
|
||||
cached_max_index = max_index;
|
||||
return cached_max_index;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
u64 BufferCache<P>::StreamAttributeExtent(u32 index) {
|
||||
using VertexAttribute = typename Maxwell::VertexAttribute;
|
||||
if (stream_extents_valid) {
|
||||
return stream_extents[index];
|
||||
}
|
||||
stream_extents_valid = true;
|
||||
stream_extents.fill(0);
|
||||
for (size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
|
||||
const auto& attribute = maxwell3d->regs.vertex_attrib_format[i];
|
||||
if (attribute.constant != 0 || attribute.size == VertexAttribute::Size::Invalid) {
|
||||
continue;
|
||||
}
|
||||
const u32 buffer = attribute.buffer.Value();
|
||||
if (buffer >= NUM_VERTEX_BUFFERS) {
|
||||
continue;
|
||||
}
|
||||
const u64 end = static_cast<u64>(attribute.offset.Value()) +
|
||||
static_cast<u64>(attribute.SizeInBytes());
|
||||
stream_extents[buffer] = (std::max)(stream_extents[buffer], end);
|
||||
}
|
||||
return stream_extents[index];
|
||||
}
|
||||
|
||||
template <class P>
|
||||
u64 BufferCache<P>::DrawVertexBound(u32 index, bool is_indexed) {
|
||||
const auto& array = maxwell3d->regs.vertex_streams[index];
|
||||
if (array.enable == 0) {
|
||||
return 0;
|
||||
}
|
||||
const u64 extent = StreamAttributeExtent(index);
|
||||
if (extent == 0) {
|
||||
return 0;
|
||||
}
|
||||
const u64 stride = static_cast<u64>(array.stride);
|
||||
if (stride == 0) {
|
||||
return extent;
|
||||
}
|
||||
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
||||
u64 elements = 0;
|
||||
if (maxwell3d->regs.vertex_stream_instances.IsInstancingEnabled(index)) {
|
||||
if (draw_instance_count == 0) {
|
||||
return 0;
|
||||
}
|
||||
const u64 base_instance = static_cast<u64>(draw_state.base_instance);
|
||||
elements = base_instance + 1;
|
||||
if (array.frequency != 0) {
|
||||
elements = (base_instance + static_cast<u64>(draw_instance_count) - 1) /
|
||||
static_cast<u64>(array.frequency) +
|
||||
1;
|
||||
}
|
||||
} else if (!is_indexed) {
|
||||
elements = static_cast<u64>(draw_state.vertex_buffer.first) +
|
||||
static_cast<u64>(draw_state.vertex_buffer.count);
|
||||
} else {
|
||||
const auto format = draw_state.index_buffer.format;
|
||||
u64 max_index = 0xFF;
|
||||
if (format == Maxwell::IndexFormat::UnsignedShort) {
|
||||
max_index = 0xFFFF;
|
||||
} else if (format != Maxwell::IndexFormat::UnsignedByte) {
|
||||
const auto& limit = maxwell3d->regs.vertex_stream_limits[index];
|
||||
const GPUVAddr gpu_addr_begin = array.Address();
|
||||
const GPUVAddr gpu_addr_end = limit.Address() + 1;
|
||||
if (gpu_addr_end <= gpu_addr_begin) {
|
||||
return 0;
|
||||
}
|
||||
const bool walks = gpu_addr_end - gpu_addr_begin >= IMPLAUSIBLE_VERTEX_SIZE ||
|
||||
!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end);
|
||||
if (!walks) {
|
||||
return 0;
|
||||
}
|
||||
max_index = DrawMaxIndex();
|
||||
}
|
||||
elements = static_cast<u64>(draw_state.base_index) + max_index + 1;
|
||||
}
|
||||
if (elements == 0) {
|
||||
return extent;
|
||||
}
|
||||
return (elements - 1) * stride + extent;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::UpdateVertexBuffers(bool is_indexed) {
|
||||
auto& flags = maxwell3d->dirty.flags;
|
||||
max_index_scanned = false;
|
||||
stream_extents_valid = false;
|
||||
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
|
||||
const u64 bound = DrawVertexBound(index, is_indexed);
|
||||
if (bound <= last_draw_bounds[index]) {
|
||||
continue;
|
||||
}
|
||||
flags[Dirty::VertexBuffer0 + index] = true;
|
||||
flags[Dirty::VertexBuffers] = true;
|
||||
}
|
||||
if (!maxwell3d->dirty.flags[Dirty::VertexBuffers]) {
|
||||
return;
|
||||
}
|
||||
flags[Dirty::VertexBuffers] = false;
|
||||
|
||||
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
|
||||
UpdateVertexBuffer(index);
|
||||
UpdateVertexBuffer(index, is_indexed);
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::UpdateVertexBuffer(u32 index) {
|
||||
void BufferCache<P>::UpdateVertexBuffer(u32 index, bool is_indexed) {
|
||||
if (!maxwell3d->dirty.flags[Dirty::VertexBuffer0 + index]) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1288,15 +1386,31 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
|
|||
const GPUVAddr gpu_addr_begin = array.Address();
|
||||
const GPUVAddr gpu_addr_end = limit.Address() + 1;
|
||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
|
||||
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
|
||||
u32 size = address_size; // TODO: Analyze stride and number of vertices
|
||||
if (array.enable == 0 || size == 0 || !device_addr) {
|
||||
if (array.enable == 0 || !device_addr || gpu_addr_end <= gpu_addr_begin) {
|
||||
channel_state->vertex_buffers[index] = NULL_BINDING;
|
||||
UpdateVertexBufferSlot(index, NULL_BINDING);
|
||||
return;
|
||||
}
|
||||
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || size >= 64_MiB) {
|
||||
size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
|
||||
// TODO: Analyze stride and number of vertices
|
||||
constexpr u64 implausible_size = IMPLAUSIBLE_VERTEX_SIZE;
|
||||
u64 address_size = gpu_addr_end - gpu_addr_begin;
|
||||
if (address_size > u64{(std::numeric_limits<u32>::max)()}) {
|
||||
address_size = implausible_size;
|
||||
}
|
||||
const u64 draw_bound = DrawVertexBound(index, is_indexed);
|
||||
last_draw_bounds[index] = (std::numeric_limits<u64>::max)();
|
||||
if (draw_bound != 0) {
|
||||
last_draw_bounds[index] = draw_bound;
|
||||
address_size = (std::min)(address_size, draw_bound);
|
||||
}
|
||||
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || address_size >= implausible_size) {
|
||||
address_size = gpu_memory->MaxContinuousRange(gpu_addr_begin, address_size);
|
||||
}
|
||||
const u32 size = static_cast<u32>(address_size);
|
||||
if (size == 0) {
|
||||
channel_state->vertex_buffers[index] = NULL_BINDING;
|
||||
UpdateVertexBufferSlot(index, NULL_BINDING);
|
||||
return;
|
||||
}
|
||||
const BufferId buffer_id = FindBuffer(*device_addr, size);
|
||||
const Binding binding{
|
||||
|
|
@ -1578,9 +1692,10 @@ template <class P>
|
|||
BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
|
||||
DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
|
||||
device_addr = Common::AlignDown(device_addr, CACHING_PAGESIZE);
|
||||
wanted_size = static_cast<u32>(device_addr_end - device_addr);
|
||||
constexpr u64 max_buffer_size = u64{(std::numeric_limits<u32>::max)()};
|
||||
wanted_size = static_cast<u32>((std::min)(device_addr_end - device_addr, max_buffer_size));
|
||||
const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
|
||||
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
|
||||
const u32 size = static_cast<u32>((std::min)(overlap.end - overlap.begin, max_buffer_size));
|
||||
const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
|
||||
auto& new_buffer = slot_buffers[new_buffer_id];
|
||||
const size_t size_bytes = new_buffer.SizeBytes();
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ constexpr u32 NUM_VERTEX_BUFFERS = 16;
|
|||
#else
|
||||
constexpr u32 NUM_VERTEX_BUFFERS = 32;
|
||||
#endif
|
||||
constexpr u64 IMPLAUSIBLE_VERTEX_SIZE = 64_MiB;
|
||||
constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
|
||||
constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
|
||||
constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
|
||||
|
|
@ -217,8 +218,6 @@ public:
|
|||
|
||||
void WriteMemory(DAddr device_addr, u64 size);
|
||||
|
||||
void CachedWriteMemory(DAddr device_addr, u64 size);
|
||||
|
||||
bool OnCPUWrite(DAddr device_addr, u64 size);
|
||||
|
||||
void DownloadMemory(DAddr device_addr, u64 size);
|
||||
|
|
@ -248,7 +247,7 @@ public:
|
|||
|
||||
void UnbindGraphicsStorageBuffers(size_t stage);
|
||||
|
||||
bool BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
|
||||
void BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
|
||||
bool is_written);
|
||||
|
||||
void UnbindGraphicsTextureBuffers(size_t stage);
|
||||
|
|
@ -309,6 +308,10 @@ public:
|
|||
current_draw_indirect = current_draw_indirect_;
|
||||
}
|
||||
|
||||
void SetDrawInstanceCount(u32 draw_instance_count_) {
|
||||
draw_instance_count = draw_instance_count_;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount();
|
||||
|
||||
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
|
||||
|
|
@ -376,8 +379,6 @@ private:
|
|||
|
||||
void BindHostTransformFeedbackBuffers();
|
||||
|
||||
void BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
|
||||
|
||||
void BindHostComputeUniformBuffers();
|
||||
|
||||
void BindHostComputeStorageBuffers();
|
||||
|
|
@ -390,9 +391,15 @@ private:
|
|||
|
||||
void UpdateIndexBuffer();
|
||||
|
||||
void UpdateVertexBuffers();
|
||||
void UpdateVertexBuffers(bool is_indexed);
|
||||
|
||||
void UpdateVertexBuffer(u32 index);
|
||||
void UpdateVertexBuffer(u32 index, bool is_indexed);
|
||||
|
||||
[[nodiscard]] u64 DrawVertexBound(u32 index, bool is_indexed);
|
||||
|
||||
[[nodiscard]] u64 DrawMaxIndex();
|
||||
|
||||
[[nodiscard]] u64 StreamAttributeExtent(u32 index);
|
||||
|
||||
void UpdateDrawIndirect();
|
||||
|
||||
|
|
@ -484,6 +491,14 @@ private:
|
|||
|
||||
const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{};
|
||||
|
||||
u32 draw_instance_count = 0;
|
||||
std::array<u64, NUM_VERTEX_BUFFERS> last_draw_bounds{};
|
||||
Common::ScratchBuffer<u32> index_scan_buffer;
|
||||
u64 cached_max_index = 0;
|
||||
bool max_index_scanned = false;
|
||||
std::array<u64, NUM_VERTEX_BUFFERS> stream_extents{};
|
||||
bool stream_extents_valid = false;
|
||||
|
||||
u32 last_index_count = 0;
|
||||
|
||||
u32 enabled_vertex_buffers_mask = 0;
|
||||
|
|
|
|||
|
|
@ -206,6 +206,40 @@ foreach(VARIANT IN ITEMS ${SHADER_TYPE_VARIANTS})
|
|||
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
|
||||
endforeach()
|
||||
|
||||
set(SHADER_DEFINE_VARIANTS
|
||||
"block_linear_unswizzle_2d.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||
"pitch_unswizzle.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||
"block_linear_unswizzle_3d.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||
)
|
||||
|
||||
foreach(VARIANT IN ITEMS ${SHADER_DEFINE_VARIANTS})
|
||||
string(REPLACE "|" ";" VARIANT_PARTS ${VARIANT})
|
||||
list(GET VARIANT_PARTS 0 VARIANT_FILENAME)
|
||||
list(GET VARIANT_PARTS 1 VARIANT_SUFFIX)
|
||||
list(GET VARIANT_PARTS 2 VARIANT_DEFINE)
|
||||
|
||||
set(VARIANT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${VARIANT_FILENAME})
|
||||
get_filename_component(VARIANT_STEM ${VARIANT_FILENAME} NAME_WE)
|
||||
get_filename_component(VARIANT_EXT ${VARIANT_FILENAME} EXT)
|
||||
string(REPLACE "." "" VARIANT_EXT ${VARIANT_EXT})
|
||||
set(VARIANT_NAME ${VARIANT_STEM}_${VARIANT_SUFFIX}_${VARIANT_EXT})
|
||||
|
||||
string(TOUPPER ${VARIANT_NAME}_SPV VARIANT_VARIABLE_NAME)
|
||||
set(VARIANT_HEADER_FILE ${SHADER_DIR}/${VARIANT_NAME}_spv.h)
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${VARIANT_HEADER_FILE}
|
||||
COMMAND
|
||||
${GLSLANGVALIDATOR} -V ${QUIET_FLAG} -I"${FIDELITYFX_INCLUDE_DIR}" ${GLSL_FLAGS}
|
||||
-D${VARIANT_DEFINE}
|
||||
--variable-name ${VARIANT_VARIABLE_NAME} -o ${VARIANT_HEADER_FILE} ${VARIANT_SOURCE}
|
||||
--target-env ${SPIR_V_VERSION}
|
||||
MAIN_DEPENDENCY
|
||||
${VARIANT_SOURCE}
|
||||
)
|
||||
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
|
||||
endforeach()
|
||||
|
||||
foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES})
|
||||
get_filename_component(FILENAME ${FILEPATH} NAME)
|
||||
string(REPLACE "." "_" HEADER_NAME ${FILENAME})
|
||||
|
|
|
|||
|
|
@ -5,9 +5,13 @@
|
|||
|
||||
#ifdef VULKAN
|
||||
|
||||
#ifndef HAS_EXTENDED_TYPES
|
||||
#define HAS_EXTENDED_TYPES 1
|
||||
#endif
|
||||
#if HAS_EXTENDED_TYPES
|
||||
#extension GL_EXT_shader_16bit_storage : require
|
||||
#extension GL_EXT_shader_8bit_storage : require
|
||||
#define HAS_EXTENDED_TYPES 1
|
||||
#endif
|
||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||
#define END_PUSH_CONSTANTS };
|
||||
#define UNIFORM(n)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,13 @@
|
|||
|
||||
#ifdef VULKAN
|
||||
|
||||
#ifndef HAS_EXTENDED_TYPES
|
||||
#define HAS_EXTENDED_TYPES 1
|
||||
#endif
|
||||
#if HAS_EXTENDED_TYPES
|
||||
#extension GL_EXT_shader_16bit_storage : require
|
||||
#extension GL_EXT_shader_8bit_storage : require
|
||||
#define HAS_EXTENDED_TYPES 1
|
||||
#endif
|
||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||
#define END_PUSH_CONSTANTS };
|
||||
#define UNIFORM(n)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,13 @@
|
|||
|
||||
#ifdef VULKAN
|
||||
|
||||
#ifndef HAS_EXTENDED_TYPES
|
||||
#define HAS_EXTENDED_TYPES 1
|
||||
#endif
|
||||
#if HAS_EXTENDED_TYPES
|
||||
#extension GL_EXT_shader_16bit_storage : require
|
||||
#extension GL_EXT_shader_8bit_storage : require
|
||||
#define HAS_EXTENDED_TYPES 1
|
||||
#endif
|
||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||
#define END_PUSH_CONSTANTS };
|
||||
#define UNIFORM(n)
|
||||
|
|
|
|||
|
|
@ -226,22 +226,6 @@ void BufferCacheRuntime::BindIndexBuffer(Buffer& buffer, u32 offset, u32 size) {
|
|||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size,
|
||||
u32 stride) {
|
||||
if (index >= max_attributes) {
|
||||
return;
|
||||
}
|
||||
if (has_unified_vertex_buffers) {
|
||||
buffer.MakeResident(GL_READ_ONLY);
|
||||
glBindVertexBuffer(index, 0, 0, static_cast<GLsizei>(stride));
|
||||
glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, index,
|
||||
buffer.HostGpuAddr() + offset, static_cast<GLsizeiptr>(size));
|
||||
} else {
|
||||
glBindVertexBuffer(index, buffer.Handle(), static_cast<GLintptr>(offset),
|
||||
static_cast<GLsizei>(stride));
|
||||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
||||
// TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
|
||||
std::array<GLuint, 32> buffer_handles;
|
||||
|
|
|
|||
|
|
@ -99,8 +99,6 @@ public:
|
|||
|
||||
void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size);
|
||||
|
||||
void BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
|
||||
|
||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||
|
||||
void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size);
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
|||
}
|
||||
|
||||
void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
|
||||
buffer_cache.SetDrawInstanceCount(instance_count);
|
||||
PrepareDraw(is_indexed, [this, is_indexed, instance_count](GLenum primitive_mode) {
|
||||
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
||||
const GLuint base_instance = GLuint(draw_state.base_instance);
|
||||
|
|
@ -304,6 +305,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
|
|||
void RasterizerOpenGL::DrawIndirect() {
|
||||
const auto& params = maxwell3d->draw_manager.indirect_state;
|
||||
buffer_cache.SetDrawIndirect(¶ms);
|
||||
buffer_cache.SetDrawInstanceCount(0);
|
||||
PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) {
|
||||
if (params.is_byte_count) {
|
||||
const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
|
||||
|
|
|
|||
|
|
@ -585,29 +585,6 @@ void BufferCacheRuntime::BindQuadIndexBuffer(PrimitiveTopology topology, u32 fir
|
|||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride) {
|
||||
if (index >= device.GetMaxVertexInputBindings()) {
|
||||
return;
|
||||
}
|
||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
||||
const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
|
||||
const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
|
||||
const VkDeviceSize vk_stride = stride;
|
||||
cmdbuf.BindVertexBuffers2EXT(index, 1, &buffer, &vk_offset, &vk_size, &vk_stride);
|
||||
});
|
||||
} else {
|
||||
if (!device.HasNullDescriptor() && buffer == VK_NULL_HANDLE) {
|
||||
ReserveNullBuffer();
|
||||
buffer = *null_buffer;
|
||||
offset = 0;
|
||||
}
|
||||
scheduler.Record([index, buffer, offset](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindVertexBuffer(index, buffer, 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) {
|
||||
|
|
|
|||
|
|
@ -138,8 +138,6 @@ public:
|
|||
|
||||
void BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count);
|
||||
|
||||
void BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride);
|
||||
|
||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||
|
||||
void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,13 @@
|
|||
#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_comp_spv.h"
|
||||
#include "video_core/host_shaders/block_linear_unswizzle_2d_nonarrow_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_comp_spv.h"
|
||||
#include "video_core/host_shaders/block_linear_unswizzle_3d_nonarrow_comp_spv.h"
|
||||
#include "video_core/host_shaders/pitch_unswizzle_comp_spv.h"
|
||||
#include "video_core/host_shaders/pitch_unswizzle_nonarrow_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 +878,291 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
|
|||
});
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u32 UNSWIZZLE_BINDING_INPUT_BUFFER = 0;
|
||||
constexpr u32 UNSWIZZLE_BINDING_OUTPUT_IMAGE = 1;
|
||||
constexpr size_t UNSWIZZLE_NUM_BINDINGS = 2;
|
||||
|
||||
constexpr std::array<VkDescriptorSetLayoutBinding, UNSWIZZLE_NUM_BINDINGS>
|
||||
UNSWIZZLE_DESCRIPTOR_SET_BINDINGS{{
|
||||
{
|
||||
.binding = UNSWIZZLE_BINDING_INPUT_BUFFER,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
.pImmutableSamplers = nullptr,
|
||||
},
|
||||
{
|
||||
.binding = UNSWIZZLE_BINDING_OUTPUT_IMAGE,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
.pImmutableSamplers = nullptr,
|
||||
},
|
||||
}};
|
||||
|
||||
constexpr std::array<VkDescriptorUpdateTemplateEntry, UNSWIZZLE_NUM_BINDINGS>
|
||||
UNSWIZZLE_DESCRIPTOR_UPDATE_TEMPLATE{{
|
||||
{
|
||||
.dstBinding = UNSWIZZLE_BINDING_INPUT_BUFFER,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.offset = UNSWIZZLE_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry),
|
||||
.stride = sizeof(DescriptorUpdateEntry),
|
||||
},
|
||||
{
|
||||
.dstBinding = UNSWIZZLE_BINDING_OUTPUT_IMAGE,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
.offset = UNSWIZZLE_BINDING_OUTPUT_IMAGE * sizeof(DescriptorUpdateEntry),
|
||||
.stride = sizeof(DescriptorUpdateEntry),
|
||||
},
|
||||
}};
|
||||
|
||||
constexpr DescriptorBankInfo UNSWIZZLE_BANK_INFO{
|
||||
.uniform_buffers = 0,
|
||||
.storage_buffers = 1,
|
||||
.texture_buffers = 0,
|
||||
.image_buffers = 0,
|
||||
.textures = 0,
|
||||
.images = 1,
|
||||
.score = 2,
|
||||
};
|
||||
|
||||
[[nodiscard]] std::span<const u32> UnswizzleSpv(const Device& device,
|
||||
std::span<const u32> extended,
|
||||
std::span<const u32> narrow) {
|
||||
if (device.IsStorageBuffer8BitAccessSupported() &&
|
||||
device.IsStorageBuffer16BitAccessSupported()) {
|
||||
return extended;
|
||||
}
|
||||
return narrow;
|
||||
}
|
||||
|
||||
struct PitchUnswizzlePushConstants {
|
||||
alignas(8) std::array<u32, 2> origin;
|
||||
alignas(8) std::array<s32, 2> destination;
|
||||
u32 bytes_per_block;
|
||||
u32 pitch;
|
||||
};
|
||||
|
||||
void RecordUnswizzleEntryBarrier(Scheduler& scheduler, VkPipeline vk_pipeline, VkImage vk_image,
|
||||
VkImageAspectFlags aspect_mask, bool is_initialized) {
|
||||
scheduler.Record([vk_pipeline, vk_image, aspect_mask,
|
||||
is_initialized](vk::CommandBuffer cmdbuf) {
|
||||
VkAccessFlags src_access = VK_ACCESS_NONE;
|
||||
VkImageLayout old_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
if (is_initialized) {
|
||||
src_access = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
old_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
const VkImageMemoryBarrier image_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = src_access,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.oldLayout = old_layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = vk_image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect_mask,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
VkPipelineStageFlags src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
if (is_initialized) {
|
||||
src_stage = vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER;
|
||||
}
|
||||
cmdbuf.PipelineBarrier(src_stage, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
|
||||
});
|
||||
}
|
||||
|
||||
void RecordUnswizzleExitBarrier(Scheduler& scheduler, VkImage vk_image,
|
||||
VkImageAspectFlags aspect_mask) {
|
||||
scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
|
||||
const VkImageMemoryBarrier image_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = vk_image,
|
||||
.subresourceRange{
|
||||
.aspectMask = aspect_mask,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, 0, image_barrier);
|
||||
});
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
BlockLinearUnswizzle2DPass::BlockLinearUnswizzle2DPass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||
: ComputePass(device_, scheduler_, descriptor_pool_, UNSWIZZLE_DESCRIPTOR_SET_BINDINGS,
|
||||
UNSWIZZLE_DESCRIPTOR_UPDATE_TEMPLATE, UNSWIZZLE_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(
|
||||
VideoCommon::Accelerated::BlockLinearSwizzle2DParams)>,
|
||||
UnswizzleSpv(device_, BLOCK_LINEAR_UNSWIZZLE_2D_COMP_SPV,
|
||||
BLOCK_LINEAR_UNSWIZZLE_2D_NONARROW_COMP_SPV)),
|
||||
scheduler{scheduler_}, compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||
|
||||
BlockLinearUnswizzle2DPass::~BlockLinearUnswizzle2DPass() = default;
|
||||
|
||||
void BlockLinearUnswizzle2DPass::Unswizzle(
|
||||
Image& image, const StagingBufferRef& map,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
using namespace VideoCommon::Accelerated;
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
const VkPipeline vk_pipeline = *pipeline;
|
||||
const VkImageAspectFlags aspect_mask = image.AspectMask();
|
||||
const VkImage vk_image = image.Handle();
|
||||
const bool is_initialized = image.ExchangeInitialization();
|
||||
RecordUnswizzleEntryBarrier(scheduler, vk_pipeline, vk_image, aspect_mask, is_initialized);
|
||||
|
||||
const u32 num_layers = static_cast<u32>(image.info.resources.layers);
|
||||
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
||||
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
||||
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
|
||||
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
|
||||
|
||||
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
|
||||
image.guest_size_bytes - swizzle.buffer_offset);
|
||||
compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
|
||||
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||
|
||||
const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
|
||||
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_layers, params,
|
||||
descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, params);
|
||||
cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, num_layers);
|
||||
});
|
||||
}
|
||||
RecordUnswizzleExitBarrier(scheduler, vk_image, aspect_mask);
|
||||
}
|
||||
|
||||
BlockLinearUnswizzleImage3DPass::BlockLinearUnswizzleImage3DPass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||
: ComputePass(device_, scheduler_, descriptor_pool_, UNSWIZZLE_DESCRIPTOR_SET_BINDINGS,
|
||||
UNSWIZZLE_DESCRIPTOR_UPDATE_TEMPLATE, UNSWIZZLE_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(BlockLinearSwizzle3DParams)>,
|
||||
UnswizzleSpv(device_, BLOCK_LINEAR_UNSWIZZLE_3D_COMP_SPV,
|
||||
BLOCK_LINEAR_UNSWIZZLE_3D_NONARROW_COMP_SPV)),
|
||||
scheduler{scheduler_}, compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||
|
||||
BlockLinearUnswizzleImage3DPass::~BlockLinearUnswizzleImage3DPass() = default;
|
||||
|
||||
void BlockLinearUnswizzleImage3DPass::Unswizzle(
|
||||
Image& image, const StagingBufferRef& map,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
using namespace VideoCommon::Accelerated;
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
const VkPipeline vk_pipeline = *pipeline;
|
||||
const VkImageAspectFlags aspect_mask = image.AspectMask();
|
||||
const VkImage vk_image = image.Handle();
|
||||
const bool is_initialized = image.ExchangeInitialization();
|
||||
RecordUnswizzleEntryBarrier(scheduler, vk_pipeline, vk_image, aspect_mask, is_initialized);
|
||||
|
||||
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
||||
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
||||
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 16U);
|
||||
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
|
||||
const u32 num_dispatches_z = Common::DivCeil(swizzle.num_tiles.depth, 8U);
|
||||
|
||||
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
|
||||
image.guest_size_bytes - swizzle.buffer_offset);
|
||||
compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
|
||||
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||
|
||||
const auto params = MakeBlockLinearSwizzle3DParams(swizzle, image.info);
|
||||
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, params,
|
||||
descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, params);
|
||||
cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, num_dispatches_z);
|
||||
});
|
||||
}
|
||||
RecordUnswizzleExitBarrier(scheduler, vk_image, aspect_mask);
|
||||
}
|
||||
|
||||
PitchUnswizzlePass::PitchUnswizzlePass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||
: ComputePass(device_, scheduler_, descriptor_pool_, UNSWIZZLE_DESCRIPTOR_SET_BINDINGS,
|
||||
UNSWIZZLE_DESCRIPTOR_UPDATE_TEMPLATE, UNSWIZZLE_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(PitchUnswizzlePushConstants)>,
|
||||
UnswizzleSpv(device_, PITCH_UNSWIZZLE_COMP_SPV,
|
||||
PITCH_UNSWIZZLE_NONARROW_COMP_SPV)),
|
||||
scheduler{scheduler_}, compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||
|
||||
PitchUnswizzlePass::~PitchUnswizzlePass() = default;
|
||||
|
||||
void PitchUnswizzlePass::Unswizzle(Image& image, const StagingBufferRef& map,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
const VkPipeline vk_pipeline = *pipeline;
|
||||
const VkImageAspectFlags aspect_mask = image.AspectMask();
|
||||
const VkImage vk_image = image.Handle();
|
||||
const bool is_initialized = image.ExchangeInitialization();
|
||||
RecordUnswizzleEntryBarrier(scheduler, vk_pipeline, vk_image, aspect_mask, is_initialized);
|
||||
|
||||
const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(image.info.format);
|
||||
const u32 pitch = image.info.pitch;
|
||||
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
||||
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
||||
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
|
||||
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
|
||||
|
||||
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
|
||||
image.guest_size_bytes - swizzle.buffer_offset);
|
||||
compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
|
||||
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||
|
||||
const PitchUnswizzlePushConstants params{
|
||||
.origin{0, 0},
|
||||
.destination{0, 0},
|
||||
.bytes_per_block = bytes_per_block,
|
||||
.pitch = pitch,
|
||||
};
|
||||
scheduler.Record([this, num_dispatches_x, num_dispatches_y, params,
|
||||
descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, params);
|
||||
cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, 1);
|
||||
});
|
||||
}
|
||||
RecordUnswizzleExitBarrier(scheduler, vk_image, aspect_mask);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
|||
|
|
@ -164,4 +164,49 @@ private:
|
|||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
class BlockLinearUnswizzle2DPass final : public ComputePass {
|
||||
public:
|
||||
explicit BlockLinearUnswizzle2DPass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||
~BlockLinearUnswizzle2DPass();
|
||||
|
||||
void Unswizzle(Image& image, const StagingBufferRef& map,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||
|
||||
private:
|
||||
Scheduler& scheduler;
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
class BlockLinearUnswizzleImage3DPass final : public ComputePass {
|
||||
public:
|
||||
explicit BlockLinearUnswizzleImage3DPass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||
~BlockLinearUnswizzleImage3DPass();
|
||||
|
||||
void Unswizzle(Image& image, const StagingBufferRef& map,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||
|
||||
private:
|
||||
Scheduler& scheduler;
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
class PitchUnswizzlePass final : public ComputePass {
|
||||
public:
|
||||
explicit PitchUnswizzlePass(const Device& device_, Scheduler& scheduler_,
|
||||
DescriptorPool& descriptor_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||
~PitchUnswizzlePass();
|
||||
|
||||
void Unswizzle(Image& image, const StagingBufferRef& map,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||
|
||||
private:
|
||||
Scheduler& scheduler;
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
|||
|
|
@ -694,9 +694,11 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||
const size_t num_vertex_arrays = (std::min)(
|
||||
Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings()));
|
||||
for (size_t index = 0; index < num_vertex_arrays; ++index) {
|
||||
const bool instanced = key.state.binding_divisors[index] != 0;
|
||||
const auto rate =
|
||||
instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
const bool instanced = ((key.state.enabled_divisors >> index) & 1) != 0;
|
||||
auto rate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
if (instanced) {
|
||||
rate = VK_VERTEX_INPUT_RATE_INSTANCE;
|
||||
}
|
||||
vertex_bindings.push_back({
|
||||
.binding = static_cast<u32>(index),
|
||||
.stride = key.state.vertex_strides[index],
|
||||
|
|
@ -705,7 +707,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||
if (instanced) {
|
||||
vertex_binding_divisors.push_back({
|
||||
.binding = static_cast<u32>(index),
|
||||
.divisor = key.state.binding_divisors[index],
|
||||
.divisor = device.GetVertexAttribDivisor(key.state.binding_divisors[index]),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,10 +137,12 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3
|
|||
max_y = (std::max)(max_y, 0);
|
||||
|
||||
if (src.enable) {
|
||||
scissor.offset.x = scale_up(src.min_x);
|
||||
const s32 min_x = static_cast<s32>(src.min_x.Value());
|
||||
const s32 max_x = static_cast<s32>(src.max_x.Value());
|
||||
scissor.offset.x = scale_up(min_x);
|
||||
scissor.offset.y = scale_up(min_y);
|
||||
scissor.extent.width = scale_up(src.max_x - src.min_x);
|
||||
scissor.extent.height = scale_up(max_y - min_y);
|
||||
scissor.extent.width = scale_up((std::max)(max_x - min_x, 0));
|
||||
scissor.extent.height = scale_up((std::max)(max_y - min_y, 0));
|
||||
} else {
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
|
|
@ -260,6 +262,7 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
|||
}
|
||||
|
||||
void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
|
||||
buffer_cache.SetDrawInstanceCount(instance_count);
|
||||
PrepareDraw(is_indexed, [this, is_indexed, instance_count] {
|
||||
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
||||
const u32 num_instances{instance_count};
|
||||
|
|
@ -295,6 +298,7 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
|
|||
void RasterizerVulkan::DrawIndirect() {
|
||||
const auto& params = maxwell3d->draw_manager.indirect_state;
|
||||
buffer_cache.SetDrawIndirect(¶ms);
|
||||
buffer_cache.SetDrawInstanceCount(0);
|
||||
PrepareDraw(params.is_indexed, [this, ¶ms] {
|
||||
const auto indirect_buffer = buffer_cache.GetDrawIndirectBuffer();
|
||||
const auto& buffer = indirect_buffer.first;
|
||||
|
|
@ -1917,13 +1921,19 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
|||
for (u32 binding = 0; binding < max_bindings; ++binding) {
|
||||
const auto& input_binding{regs.vertex_streams[binding]};
|
||||
const bool is_instanced{regs.vertex_stream_instances.IsInstancingEnabled(binding)};
|
||||
auto input_rate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
u32 divisor = 1;
|
||||
if (is_instanced) {
|
||||
input_rate = VK_VERTEX_INPUT_RATE_INSTANCE;
|
||||
divisor = device.GetVertexAttribDivisor(input_binding.frequency);
|
||||
}
|
||||
bindings.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT,
|
||||
.pNext = nullptr,
|
||||
.binding = binding,
|
||||
.stride = input_binding.stride,
|
||||
.inputRate = is_instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX,
|
||||
.divisor = is_instanced ? input_binding.frequency : 1,
|
||||
.inputRate = input_rate,
|
||||
.divisor = divisor,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -449,7 +449,9 @@ void Scheduler::EndRenderPass()
|
|||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
|
|
@ -460,7 +462,7 @@ void Scheduler::EndRenderPass()
|
|||
}
|
||||
cmdbuf.EndRenderPass();
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER,
|
||||
0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
|
||||
if (has_transform_feedback) {
|
||||
static constexpr VkMemoryBarrier XFB_OUTPUT_BARRIER{
|
||||
|
|
|
|||
|
|
@ -160,6 +160,55 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
|||
info.size.depth == 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] PixelFormat UnswizzleViewFormat(u32 bytes_per_block) {
|
||||
switch (bytes_per_block) {
|
||||
case 1:
|
||||
return PixelFormat::R8_UINT;
|
||||
case 2:
|
||||
return PixelFormat::R16_UINT;
|
||||
case 4:
|
||||
return PixelFormat::R32_UINT;
|
||||
case 8:
|
||||
return PixelFormat::R32G32_UINT;
|
||||
case 16:
|
||||
return PixelFormat::R32G32B32A32_UINT;
|
||||
default:
|
||||
return PixelFormat::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr u32 UNSWIZZLE_WORKGROUP_INVOCATIONS = 32 * 32;
|
||||
|
||||
[[nodiscard]] bool SupportsAcceleratedUnswizzleDevice(const Device& device) {
|
||||
return device.IsKhrImageFormatListSupported() &&
|
||||
device.GetMaxComputeWorkGroupInvocations() >= UNSWIZZLE_WORKGROUP_INVOCATIONS;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool SupportsAcceleratedUnswizzle(const Device& device, const ImageInfo& info) {
|
||||
if (!SupportsAcceleratedUnswizzleDevice(device)) {
|
||||
return false;
|
||||
}
|
||||
if (info.num_samples > 1) {
|
||||
return false;
|
||||
}
|
||||
if (info.type != ImageType::e2D && info.type != ImageType::e3D &&
|
||||
info.type != ImageType::Linear) {
|
||||
return false;
|
||||
}
|
||||
const PixelFormat view_format =
|
||||
UnswizzleViewFormat(VideoCore::Surface::BytesPerBlock(info.format));
|
||||
if (view_format == PixelFormat::Invalid) {
|
||||
return false;
|
||||
}
|
||||
if (!VideoCore::Surface::IsViewCompatible(info.format, view_format, false, true)) {
|
||||
return false;
|
||||
}
|
||||
const auto host_format =
|
||||
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, view_format);
|
||||
return device.IsFormatSupported(host_format.format, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT,
|
||||
FormatType::Optimal);
|
||||
}
|
||||
|
||||
[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info,
|
||||
std::optional<VkFormat> format_override = {}) {
|
||||
auto format_info =
|
||||
|
|
@ -248,8 +297,18 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
|||
return allocator.CreateImage(image_ci);
|
||||
}
|
||||
|
||||
[[nodiscard]] VkImageViewType StorageViewType(ImageType type) {
|
||||
if (type == ImageType::e3D) {
|
||||
return VK_IMAGE_VIEW_TYPE_3D;
|
||||
}
|
||||
if (type == ImageType::Linear) {
|
||||
return VK_IMAGE_VIEW_TYPE_2D;
|
||||
}
|
||||
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
}
|
||||
|
||||
[[nodiscard]] vk::ImageView MakeStorageView(const vk::Device& device, u32 level, VkImage image,
|
||||
VkFormat format) {
|
||||
VkFormat format, VkImageViewType view_type) {
|
||||
static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
|
@ -260,7 +319,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
|||
.pNext = &storage_image_view_usage_create_info,
|
||||
.flags = 0,
|
||||
.image = image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
||||
.viewType = view_type,
|
||||
.format = format,
|
||||
.components{
|
||||
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
|
|
@ -658,18 +717,11 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
|
|||
.subresourceRange = subresource_range,
|
||||
};
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
read_barrier);
|
||||
cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
|
||||
// TODO: Move this to another API
|
||||
cmdbuf.PipelineBarrier(
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
0, nullptr, nullptr, write_barrier);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0,
|
||||
nullptr, nullptr, write_barrier);
|
||||
}
|
||||
|
||||
[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region,
|
||||
|
|
@ -968,6 +1020,14 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
|
|||
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
||||
staging_buffer_pool, compute_pass_descriptor_queue);
|
||||
}
|
||||
if (SupportsAcceleratedUnswizzleDevice(device)) {
|
||||
bl_unswizzle_2d_pass.emplace(device, scheduler, descriptor_pool,
|
||||
compute_pass_descriptor_queue);
|
||||
bl_unswizzle_image_3d_pass.emplace(device, scheduler, descriptor_pool,
|
||||
compute_pass_descriptor_queue);
|
||||
pitch_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
||||
compute_pass_descriptor_queue);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::Finish() {
|
||||
|
|
@ -1902,16 +1962,12 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
|
|||
if (runtime->device.HasDebuggingToolAttached()) {
|
||||
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
|
||||
}
|
||||
if (False(flags & VideoCommon::ImageFlagBits::Converted) &&
|
||||
SupportsAcceleratedUnswizzle(runtime->device, info)) {
|
||||
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
||||
}
|
||||
current_image = &Image::original_image;
|
||||
storage_image_views.resize(info.resources.levels);
|
||||
if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
|
||||
const auto& device = runtime->device.GetLogical();
|
||||
const VkFormat storage_format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||
for (s32 level = 0; level < info.resources.levels; ++level) {
|
||||
storage_image_views[level] =
|
||||
MakeStorageView(device, level, *original_image, storage_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image::Image(const VideoCommon::NullImageParams& params) : VideoCommon::ImageBase{params} {}
|
||||
|
|
@ -2035,7 +2091,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
|
|||
temp_vk_image, info.format, info.num_samples,
|
||||
{image_copies.data(), image_copies.size()}, false);
|
||||
}
|
||||
initialized = true;
|
||||
InitializationFor(current_image) = true;
|
||||
runtime->ReleaseMsaaScratchImage(temp_vk_image);
|
||||
|
||||
if (is_rescaled) {
|
||||
|
|
@ -2056,7 +2112,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
|
|||
const VkBuffer src_buffer = buffer;
|
||||
const VkImage vk_image = *original_image;
|
||||
const VkImageAspectFlags vk_aspect_mask = aspect_mask;
|
||||
const bool was_initialized = std::exchange(initialized, true);
|
||||
const bool was_initialized = std::exchange(InitializationFor(&Image::original_image), true);
|
||||
|
||||
scheduler->Record([src_buffer, vk_image, vk_aspect_mask, was_initialized,
|
||||
vk_copies](vk::CommandBuffer cmdbuf) {
|
||||
|
|
@ -2321,16 +2377,46 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm
|
|||
DownloadMemory(buffers, offsets, copies);
|
||||
}
|
||||
|
||||
std::vector<vk::ImageView>& Image::StorageViewsFor(vk::Image Image::*image) {
|
||||
if (image == &Image::scaled_image) {
|
||||
if (scaled_storage_image_views.empty()) {
|
||||
scaled_storage_image_views.resize(info.resources.levels);
|
||||
}
|
||||
return scaled_storage_image_views;
|
||||
}
|
||||
return storage_image_views;
|
||||
}
|
||||
|
||||
bool& Image::InitializationFor(vk::Image Image::*image) noexcept {
|
||||
if (image == &Image::scaled_image) {
|
||||
return scaled_initialized;
|
||||
}
|
||||
return original_initialized;
|
||||
}
|
||||
|
||||
VkImageView Image::StorageImageView(s32 level) noexcept {
|
||||
auto& view = storage_image_views[level];
|
||||
const bool astc_decode = WillUseAcceleratedAstcDecode(runtime->device, info);
|
||||
const bool unswizzle_upload =
|
||||
!astc_decode && True(flags & ImageFlagBits::AcceleratedUpload);
|
||||
vk::Image Image::*target = current_image;
|
||||
if (astc_decode || unswizzle_upload) {
|
||||
target = &Image::original_image;
|
||||
}
|
||||
auto& view = StorageViewsFor(target)[level];
|
||||
if (!view) {
|
||||
auto format_info =
|
||||
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format);
|
||||
if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
|
||||
if (astc_decode) {
|
||||
format_info.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||
}
|
||||
view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*current_image),
|
||||
format_info.format);
|
||||
if (unswizzle_upload) {
|
||||
const PixelFormat view_format =
|
||||
UnswizzleViewFormat(VideoCore::Surface::BytesPerBlock(info.format));
|
||||
format_info = MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, false,
|
||||
view_format);
|
||||
}
|
||||
view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*target),
|
||||
format_info.format, StorageViewType(info.type));
|
||||
}
|
||||
return *view;
|
||||
}
|
||||
|
|
@ -2370,6 +2456,7 @@ bool Image::ScaleUp(bool ignore) {
|
|||
}
|
||||
if (NeedsScaleHelper()) {
|
||||
if (!BlitScaleHelper(true)) {
|
||||
flags &= ~ImageFlagBits::Rescaled;
|
||||
current_image = &Image::original_image;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2559,6 +2646,10 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
|
|||
if (device->IsExtAstcDecodeModeSupported() && IsLdrAstcFormat(format_info.format)) {
|
||||
view_next = &astc_decode_mode;
|
||||
}
|
||||
auto subresource_range = MakeSubresourceRange(aspect_mask, info.range);
|
||||
if (True(flags & VideoCommon::ImageViewFlagBits::Slice)) {
|
||||
subresource_range.levelCount = 1;
|
||||
}
|
||||
const VkImageViewCreateInfo create_info{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.pNext = view_next,
|
||||
|
|
@ -2567,7 +2658,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
|
|||
.viewType = VkImageViewType{},
|
||||
.format = format_info.format,
|
||||
.components = swizzle_mapping,
|
||||
.subresourceRange = MakeSubresourceRange(aspect_mask, info.range),
|
||||
.subresourceRange = subresource_range,
|
||||
};
|
||||
const auto create = [&](TextureType tex_type, std::optional<u32> num_layers) {
|
||||
VkImageViewCreateInfo ci{create_info};
|
||||
|
|
@ -3141,6 +3232,19 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
|||
return astc_decoder_pass->Assemble(image, map, swizzles);
|
||||
}
|
||||
|
||||
if (bl_unswizzle_2d_pass && image.info.type == ImageType::e2D) {
|
||||
return bl_unswizzle_2d_pass->Unswizzle(image, map, swizzles);
|
||||
}
|
||||
|
||||
if (bl_unswizzle_image_3d_pass && image.info.type == ImageType::e3D &&
|
||||
!IsPixelFormatBCn(image.info.format)) {
|
||||
return bl_unswizzle_image_3d_pass->Unswizzle(image, map, swizzles);
|
||||
}
|
||||
|
||||
if (pitch_unswizzle_pass && image.info.type == ImageType::Linear) {
|
||||
return pitch_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,9 @@ public:
|
|||
std::optional<ASTCDecoderPass> astc_decoder_pass;
|
||||
|
||||
std::optional<BlockLinearUnswizzle3DPass> bl3d_unswizzle_pass;
|
||||
std::optional<BlockLinearUnswizzle2DPass> bl_unswizzle_2d_pass;
|
||||
std::optional<BlockLinearUnswizzleImage3DPass> bl_unswizzle_image_3d_pass;
|
||||
std::optional<PitchUnswizzlePass> pitch_unswizzle_pass;
|
||||
const Settings::ResolutionScalingInfo& resolution;
|
||||
std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;
|
||||
|
||||
|
|
@ -350,7 +353,7 @@ public:
|
|||
|
||||
/// Returns true when the image is already initialized and mark it as initialized
|
||||
[[nodiscard]] bool ExchangeInitialization() noexcept {
|
||||
return std::exchange(initialized, true);
|
||||
return std::exchange(InitializationFor(current_image), true);
|
||||
}
|
||||
|
||||
VkImageView StorageImageView(s32 level) noexcept;
|
||||
|
|
@ -370,6 +373,10 @@ private:
|
|||
|
||||
bool NeedsScaleHelper() const;
|
||||
|
||||
std::vector<vk::ImageView>& StorageViewsFor(vk::Image Image::*image);
|
||||
|
||||
bool& InitializationFor(vk::Image Image::*image) noexcept;
|
||||
|
||||
Scheduler* scheduler{};
|
||||
TextureCacheRuntime* runtime{};
|
||||
|
||||
|
|
@ -387,8 +394,10 @@ private:
|
|||
vk::Image Image::*current_image{};
|
||||
|
||||
std::vector<vk::ImageView> storage_image_views;
|
||||
std::vector<vk::ImageView> scaled_storage_image_views;
|
||||
VkImageAspectFlags aspect_mask = 0;
|
||||
bool initialized = false;
|
||||
bool original_initialized = false;
|
||||
bool scaled_initialized = false;
|
||||
|
||||
std::optional<Framebuffer> scale_framebuffer;
|
||||
std::optional<Framebuffer> normal_framebuffer;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -23,8 +26,8 @@ struct BlockLinearSwizzle2DParams {
|
|||
};
|
||||
|
||||
struct BlockLinearSwizzle3DParams {
|
||||
std::array<u32, 3> origin;
|
||||
std::array<s32, 3> destination;
|
||||
alignas(16) std::array<u32, 3> origin;
|
||||
alignas(16) std::array<s32, 3> destination;
|
||||
u32 bytes_per_block_log2;
|
||||
u32 slice_size;
|
||||
u32 block_size;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue