|
|
|
@ -31,6 +31,7 @@
|
|
|
|
|
#include "video_core/engines/maxwell_3d.h"
|
|
|
|
|
#include "video_core/memory_manager.h"
|
|
|
|
|
#include "video_core/rasterizer_interface.h"
|
|
|
|
|
#include "video_core/surface.h"
|
|
|
|
|
#include "video_core/texture_cache/slot_vector.h"
|
|
|
|
|
#include "video_core/texture_cache/types.h"
|
|
|
|
|
|
|
|
|
@ -42,11 +43,14 @@ MICROPROFILE_DECLARE(GPU_DownloadMemory);
|
|
|
|
|
|
|
|
|
|
using BufferId = SlotId;
|
|
|
|
|
|
|
|
|
|
using VideoCore::Surface::PixelFormat;
|
|
|
|
|
|
|
|
|
|
constexpr u32 NUM_VERTEX_BUFFERS = 32;
|
|
|
|
|
constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
|
|
|
|
|
constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
|
|
|
|
|
constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
|
|
|
|
|
constexpr u32 NUM_STORAGE_BUFFERS = 16;
|
|
|
|
|
constexpr u32 NUM_TEXTURE_BUFFERS = 16;
|
|
|
|
|
constexpr u32 NUM_STAGES = 5;
|
|
|
|
|
|
|
|
|
|
using namespace Common::Literals;
|
|
|
|
@ -66,6 +70,7 @@ class BufferCache {
|
|
|
|
|
P::HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT;
|
|
|
|
|
static constexpr bool NEEDS_BIND_UNIFORM_INDEX = P::NEEDS_BIND_UNIFORM_INDEX;
|
|
|
|
|
static constexpr bool NEEDS_BIND_STORAGE_INDEX = P::NEEDS_BIND_STORAGE_INDEX;
|
|
|
|
|
static constexpr bool NEEDS_BIND_TEXTURE_BUFFER_INDEX = P::NEEDS_BIND_TEXTURE_BUFFER_INDEX;
|
|
|
|
|
static constexpr bool USE_MEMORY_MAPS = P::USE_MEMORY_MAPS;
|
|
|
|
|
|
|
|
|
|
static constexpr BufferId NULL_BUFFER_ID{0};
|
|
|
|
@ -96,6 +101,10 @@ class BufferCache {
|
|
|
|
|
BufferId buffer_id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct TextureBufferBinding : Binding {
|
|
|
|
|
PixelFormat format;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static constexpr Binding NULL_BINDING{
|
|
|
|
|
.cpu_addr = 0,
|
|
|
|
|
.size = 0,
|
|
|
|
@ -142,11 +151,21 @@ public:
|
|
|
|
|
void BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
|
|
|
|
|
bool is_written);
|
|
|
|
|
|
|
|
|
|
void UnbindGraphicsTextureBuffers(size_t stage);
|
|
|
|
|
|
|
|
|
|
void BindGraphicsTextureBuffer(size_t stage, size_t tbo_index, GPUVAddr gpu_addr, u32 size,
|
|
|
|
|
PixelFormat format);
|
|
|
|
|
|
|
|
|
|
void UnbindComputeStorageBuffers();
|
|
|
|
|
|
|
|
|
|
void BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
|
|
|
|
|
bool is_written);
|
|
|
|
|
|
|
|
|
|
void UnbindComputeTextureBuffers();
|
|
|
|
|
|
|
|
|
|
void BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size,
|
|
|
|
|
PixelFormat format);
|
|
|
|
|
|
|
|
|
|
void FlushCachedWrites();
|
|
|
|
|
|
|
|
|
|
/// Return true when there are uncommitted buffers to be downloaded
|
|
|
|
@ -254,12 +273,16 @@ private:
|
|
|
|
|
|
|
|
|
|
void BindHostGraphicsStorageBuffers(size_t stage);
|
|
|
|
|
|
|
|
|
|
void BindHostGraphicsTextureBuffers(size_t stage);
|
|
|
|
|
|
|
|
|
|
void BindHostTransformFeedbackBuffers();
|
|
|
|
|
|
|
|
|
|
void BindHostComputeUniformBuffers();
|
|
|
|
|
|
|
|
|
|
void BindHostComputeStorageBuffers();
|
|
|
|
|
|
|
|
|
|
void BindHostComputeTextureBuffers();
|
|
|
|
|
|
|
|
|
|
void DoUpdateGraphicsBuffers(bool is_indexed);
|
|
|
|
|
|
|
|
|
|
void DoUpdateComputeBuffers();
|
|
|
|
@ -274,6 +297,8 @@ private:
|
|
|
|
|
|
|
|
|
|
void UpdateStorageBuffers(size_t stage);
|
|
|
|
|
|
|
|
|
|
void UpdateTextureBuffers(size_t stage);
|
|
|
|
|
|
|
|
|
|
void UpdateTransformFeedbackBuffers();
|
|
|
|
|
|
|
|
|
|
void UpdateTransformFeedbackBuffer(u32 index);
|
|
|
|
@ -282,6 +307,8 @@ private:
|
|
|
|
|
|
|
|
|
|
void UpdateComputeStorageBuffers();
|
|
|
|
|
|
|
|
|
|
void UpdateComputeTextureBuffers();
|
|
|
|
|
|
|
|
|
|
void MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] BufferId FindBuffer(VAddr cpu_addr, u32 size);
|
|
|
|
@ -323,6 +350,9 @@ private:
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr) const;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size,
|
|
|
|
|
PixelFormat format);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] std::span<const u8> ImmediateBufferWithData(VAddr cpu_addr, size_t size);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] std::span<u8> ImmediateBuffer(size_t wanted_capacity);
|
|
|
|
@ -347,10 +377,12 @@ private:
|
|
|
|
|
std::array<Binding, NUM_VERTEX_BUFFERS> vertex_buffers;
|
|
|
|
|
std::array<std::array<Binding, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES> uniform_buffers;
|
|
|
|
|
std::array<std::array<Binding, NUM_STORAGE_BUFFERS>, NUM_STAGES> storage_buffers;
|
|
|
|
|
std::array<std::array<TextureBufferBinding, NUM_TEXTURE_BUFFERS>, NUM_STAGES> texture_buffers;
|
|
|
|
|
std::array<Binding, NUM_TRANSFORM_FEEDBACK_BUFFERS> transform_feedback_buffers;
|
|
|
|
|
|
|
|
|
|
std::array<Binding, NUM_COMPUTE_UNIFORM_BUFFERS> compute_uniform_buffers;
|
|
|
|
|
std::array<Binding, NUM_STORAGE_BUFFERS> compute_storage_buffers;
|
|
|
|
|
std::array<TextureBufferBinding, NUM_TEXTURE_BUFFERS> compute_texture_buffers;
|
|
|
|
|
|
|
|
|
|
std::array<u32, NUM_STAGES> enabled_uniform_buffers{};
|
|
|
|
|
u32 enabled_compute_uniform_buffers = 0;
|
|
|
|
@ -360,6 +392,9 @@ private:
|
|
|
|
|
u32 enabled_compute_storage_buffers = 0;
|
|
|
|
|
u32 written_compute_storage_buffers = 0;
|
|
|
|
|
|
|
|
|
|
std::array<u32, NUM_STAGES> enabled_texture_buffers{};
|
|
|
|
|
u32 enabled_compute_texture_buffers = 0;
|
|
|
|
|
|
|
|
|
|
std::array<u32, NUM_STAGES> fast_bound_uniform_buffers{};
|
|
|
|
|
|
|
|
|
|
std::array<u32, 16> uniform_cache_hits{};
|
|
|
|
@ -619,6 +654,7 @@ void BufferCache<P>::BindHostStageBuffers(size_t stage) {
|
|
|
|
|
MICROPROFILE_SCOPE(GPU_BindUploadBuffers);
|
|
|
|
|
BindHostGraphicsUniformBuffers(stage);
|
|
|
|
|
BindHostGraphicsStorageBuffers(stage);
|
|
|
|
|
BindHostGraphicsTextureBuffers(stage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
@ -626,6 +662,7 @@ void BufferCache<P>::BindHostComputeBuffers() {
|
|
|
|
|
MICROPROFILE_SCOPE(GPU_BindUploadBuffers);
|
|
|
|
|
BindHostComputeUniformBuffers();
|
|
|
|
|
BindHostComputeStorageBuffers();
|
|
|
|
|
BindHostComputeTextureBuffers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
@ -660,6 +697,18 @@ void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
|
|
|
|
|
storage_buffers[stage][ssbo_index] = StorageBufferBinding(ssbo_addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::UnbindGraphicsTextureBuffers(size_t stage) {
|
|
|
|
|
enabled_texture_buffers[stage] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::BindGraphicsTextureBuffer(size_t stage, size_t tbo_index, GPUVAddr gpu_addr,
|
|
|
|
|
u32 size, PixelFormat format) {
|
|
|
|
|
enabled_texture_buffers[stage] |= 1U << tbo_index;
|
|
|
|
|
texture_buffers[stage][tbo_index] = GetTextureBufferBinding(gpu_addr, size, format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::UnbindComputeStorageBuffers() {
|
|
|
|
|
enabled_compute_storage_buffers = 0;
|
|
|
|
@ -680,6 +729,18 @@ void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index,
|
|
|
|
|
compute_storage_buffers[ssbo_index] = StorageBufferBinding(ssbo_addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::UnbindComputeTextureBuffers() {
|
|
|
|
|
enabled_compute_texture_buffers = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size,
|
|
|
|
|
PixelFormat format) {
|
|
|
|
|
enabled_compute_texture_buffers |= 1U << tbo_index;
|
|
|
|
|
compute_texture_buffers[tbo_index] = GetTextureBufferBinding(gpu_addr, size, format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::FlushCachedWrites() {
|
|
|
|
|
for (const BufferId buffer_id : cached_write_buffer_ids) {
|
|
|
|
@ -988,6 +1049,26 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::BindHostGraphicsTextureBuffers(size_t stage) {
|
|
|
|
|
u32 binding_index = 0;
|
|
|
|
|
ForEachEnabledBit(enabled_texture_buffers[stage], [&](u32 index) {
|
|
|
|
|
const TextureBufferBinding& binding = texture_buffers[stage][index];
|
|
|
|
|
Buffer& buffer = slot_buffers[binding.buffer_id];
|
|
|
|
|
const u32 size = binding.size;
|
|
|
|
|
SynchronizeBuffer(buffer, binding.cpu_addr, size);
|
|
|
|
|
|
|
|
|
|
const u32 offset = buffer.Offset(binding.cpu_addr);
|
|
|
|
|
const PixelFormat format = binding.format;
|
|
|
|
|
if constexpr (NEEDS_BIND_TEXTURE_BUFFER_INDEX) {
|
|
|
|
|
runtime.BindTextureBuffer(binding_index, buffer, offset, size, format);
|
|
|
|
|
++binding_index;
|
|
|
|
|
} else {
|
|
|
|
|
runtime.BindTextureBuffer(buffer, offset, size, format);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::BindHostTransformFeedbackBuffers() {
|
|
|
|
|
if (maxwell3d.regs.tfb_enabled == 0) {
|
|
|
|
@ -1050,6 +1131,26 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::BindHostComputeTextureBuffers() {
|
|
|
|
|
u32 binding_index = 0;
|
|
|
|
|
ForEachEnabledBit(enabled_compute_texture_buffers, [&](u32 index) {
|
|
|
|
|
const TextureBufferBinding& binding = compute_texture_buffers[index];
|
|
|
|
|
Buffer& buffer = slot_buffers[binding.buffer_id];
|
|
|
|
|
const u32 size = binding.size;
|
|
|
|
|
SynchronizeBuffer(buffer, binding.cpu_addr, size);
|
|
|
|
|
|
|
|
|
|
const u32 offset = buffer.Offset(binding.cpu_addr);
|
|
|
|
|
const PixelFormat format = binding.format;
|
|
|
|
|
if constexpr (NEEDS_BIND_TEXTURE_BUFFER_INDEX) {
|
|
|
|
|
runtime.BindTextureBuffer(binding_index, buffer, offset, size, format);
|
|
|
|
|
++binding_index;
|
|
|
|
|
} else {
|
|
|
|
|
runtime.BindTextureBuffer(buffer, offset, size, format);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
|
|
|
|
|
if (is_indexed) {
|
|
|
|
@ -1060,6 +1161,7 @@ void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
|
|
|
|
|
for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
|
|
|
|
|
UpdateUniformBuffers(stage);
|
|
|
|
|
UpdateStorageBuffers(stage);
|
|
|
|
|
UpdateTextureBuffers(stage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1067,6 +1169,7 @@ template <class P>
|
|
|
|
|
void BufferCache<P>::DoUpdateComputeBuffers() {
|
|
|
|
|
UpdateComputeUniformBuffers();
|
|
|
|
|
UpdateComputeStorageBuffers();
|
|
|
|
|
UpdateComputeTextureBuffers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
@ -1166,6 +1269,14 @@ void BufferCache<P>::UpdateStorageBuffers(size_t stage) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::UpdateTextureBuffers(size_t stage) {
|
|
|
|
|
ForEachEnabledBit(enabled_texture_buffers[stage], [&](u32 index) {
|
|
|
|
|
Binding& binding = texture_buffers[stage][index];
|
|
|
|
|
binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::UpdateTransformFeedbackBuffers() {
|
|
|
|
|
if (maxwell3d.regs.tfb_enabled == 0) {
|
|
|
|
@ -1227,6 +1338,14 @@ void BufferCache<P>::UpdateComputeStorageBuffers() {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::UpdateComputeTextureBuffers() {
|
|
|
|
|
ForEachEnabledBit(enabled_compute_texture_buffers, [&](u32 index) {
|
|
|
|
|
Binding& binding = compute_texture_buffers[index];
|
|
|
|
|
binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) {
|
|
|
|
|
Buffer& buffer = slot_buffers[buffer_id];
|
|
|
|
@ -1581,6 +1700,25 @@ typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr s
|
|
|
|
|
return binding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
typename BufferCache<P>::TextureBufferBinding BufferCache<P>::GetTextureBufferBinding(
|
|
|
|
|
GPUVAddr gpu_addr, u32 size, PixelFormat format) {
|
|
|
|
|
const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
|
|
|
|
|
TextureBufferBinding binding;
|
|
|
|
|
if (!cpu_addr || size == 0) {
|
|
|
|
|
binding.cpu_addr = 0;
|
|
|
|
|
binding.size = 0;
|
|
|
|
|
binding.buffer_id = NULL_BUFFER_ID;
|
|
|
|
|
binding.format = PixelFormat::Invalid;
|
|
|
|
|
} else {
|
|
|
|
|
binding.cpu_addr = *cpu_addr;
|
|
|
|
|
binding.size = size;
|
|
|
|
|
binding.buffer_id = BufferId{};
|
|
|
|
|
binding.format = format;
|
|
|
|
|
}
|
|
|
|
|
return binding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class P>
|
|
|
|
|
std::span<const u8> BufferCache<P>::ImmediateBufferWithData(VAddr cpu_addr, size_t size) {
|
|
|
|
|
u8* const base_pointer = cpu_memory.GetPointer(cpu_addr);
|
|
|
|
|