mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-05 20:04:13 +00:00
Adjustments based on previous handlings for descriptors usage
This commit is contained in:
@@ -449,9 +449,18 @@ bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
|
||||
|
||||
const auto& cbufs = maxwell3d->state.shader_stages[stage];
|
||||
const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
|
||||
channel_state->storage_buffers[stage][ssbo_index] =
|
||||
StorageBufferBindingInfo& slot = channel_state->storage_buffers[stage][ssbo_index];
|
||||
const StorageBufferBindingInfo binding =
|
||||
StorageBufferBinding(ssbo_addr, cbuf_index, is_written, descriptor_count);
|
||||
return channel_state->storage_buffers[stage][ssbo_index].gpu_addr != 0;
|
||||
if (slot.gpu_addr != binding.gpu_addr || slot.size != binding.size ||
|
||||
slot.descriptor_count != binding.descriptor_count) {
|
||||
slot.gpu_addr = binding.gpu_addr;
|
||||
slot.size = binding.size;
|
||||
slot.descriptor_count = binding.descriptor_count;
|
||||
slot.mapping_generation = 0;
|
||||
slot.segments.clear();
|
||||
}
|
||||
return slot.gpu_addr != 0;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -525,8 +534,17 @@ void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index,
|
||||
|
||||
const auto& cbufs = launch_desc.const_buffer_config;
|
||||
const GPUVAddr ssbo_addr = cbufs[cbuf_index].Address() + cbuf_offset;
|
||||
channel_state->compute_storage_buffers[ssbo_index] =
|
||||
StorageBufferBindingInfo& slot = channel_state->compute_storage_buffers[ssbo_index];
|
||||
const StorageBufferBindingInfo binding =
|
||||
StorageBufferBinding(ssbo_addr, cbuf_index, is_written, descriptor_count);
|
||||
if (slot.gpu_addr != binding.gpu_addr || slot.size != binding.size ||
|
||||
slot.descriptor_count != binding.descriptor_count) {
|
||||
slot.gpu_addr = binding.gpu_addr;
|
||||
slot.size = binding.size;
|
||||
slot.descriptor_count = binding.descriptor_count;
|
||||
slot.mapping_generation = 0;
|
||||
slot.segments.clear();
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -1002,7 +1020,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
|
||||
boost::container::small_vector<u32, NUM_STORAGE_BUFFERS> segment_sizes;
|
||||
boost::container::small_vector<u32, NUM_STORAGE_BUFFERS * NUM_STORAGE_BUFFER_SEGMENTS> segment_sizes;
|
||||
bool uses_mapping{};
|
||||
ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) {
|
||||
const StorageBufferBindingInfo& binding = channel_state->storage_buffers[stage][index];
|
||||
@@ -1163,7 +1181,7 @@ void BufferCache<P>::BindHostComputeUniformBuffers() {
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::BindHostComputeStorageBuffers() {
|
||||
boost::container::small_vector<u32, NUM_STORAGE_BUFFERS> segment_sizes;
|
||||
boost::container::small_vector<u32, NUM_STORAGE_BUFFERS * NUM_STORAGE_BUFFER_SEGMENTS> segment_sizes;
|
||||
bool uses_mapping{};
|
||||
ForEachEnabledBit(channel_state->enabled_compute_storage_buffers, [&](u32 index) {
|
||||
const StorageBufferBindingInfo& binding = channel_state->compute_storage_buffers[index];
|
||||
@@ -1469,10 +1487,12 @@ void BufferCache<P>::UpdateComputeStorageBuffers() {
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::UpdateStorageBuffer(StorageBufferBindingInfo& binding) {
|
||||
binding.segments.clear();
|
||||
if (binding.gpu_addr == 0 || binding.size == 0) { return;}
|
||||
if (binding.gpu_addr == 0 || binding.size == 0) {
|
||||
binding.segments.clear();
|
||||
return;
|
||||
}
|
||||
if (binding.descriptor_count == 1) {
|
||||
// for safety gotta preserve the legacy path on possible hosts without storage-buffer descriptor indexing.
|
||||
binding.segments.clear();
|
||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(binding.gpu_addr);
|
||||
if (device_addr) {
|
||||
binding.segments.push_back(Binding{
|
||||
@@ -1484,30 +1504,32 @@ void BufferCache<P>::UpdateStorageBuffer(StorageBufferBindingInfo& binding) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto ranges = gpu_memory->GetSubmappedRange(binding.gpu_addr, binding.size);
|
||||
const size_t mapped_size =
|
||||
std::accumulate(ranges.begin(), ranges.end(), size_t{}, [](size_t total, const auto& range) { return total + range.second; });
|
||||
if (mapped_size != binding.size) {
|
||||
LOG_ERROR(HW_GPU, "Storage buffer range {:#x}+{:#x} is not fully mapped", binding.gpu_addr, binding.size);
|
||||
return;
|
||||
}
|
||||
if (ranges.size() > binding.descriptor_count) {
|
||||
LOG_ERROR(HW_GPU, "Storage buffer range {:#x}+{:#x} has {} physical segments, exceeding host capacity {}",
|
||||
binding.gpu_addr, binding.size, ranges.size(), binding.descriptor_count);
|
||||
return;
|
||||
}
|
||||
for (const auto& [gpu_addr, size] : ranges) {
|
||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
|
||||
if (!device_addr || size > (std::numeric_limits<u32>::max)()) {
|
||||
binding.segments.clear();
|
||||
return;
|
||||
const u64 generation = gpu_memory->MappingGeneration();
|
||||
if (binding.mapping_generation != generation || binding.segments.empty()) {
|
||||
binding.mapping_generation = generation;
|
||||
binding.segments.clear();
|
||||
const auto ranges = gpu_memory->GetSubmappedRange(binding.gpu_addr, binding.size);
|
||||
for (const auto& [gpu_addr, size] : ranges) {
|
||||
if (binding.segments.size() >= binding.descriptor_count) {
|
||||
break;
|
||||
}
|
||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
|
||||
if (!device_addr) {
|
||||
break;
|
||||
}
|
||||
u32 segment_size = (std::numeric_limits<u32>::max)();
|
||||
if (size < static_cast<size_t>(segment_size)) {
|
||||
segment_size = static_cast<u32>(size);
|
||||
}
|
||||
binding.segments.push_back(Binding{
|
||||
.device_addr = *device_addr,
|
||||
.size = segment_size,
|
||||
.buffer_id = BufferId{},
|
||||
});
|
||||
}
|
||||
const u32 segment_size = static_cast<u32>(size);
|
||||
binding.segments.push_back(Binding{
|
||||
.device_addr = *device_addr,
|
||||
.size = segment_size,
|
||||
.buffer_id = FindBuffer(*device_addr, segment_size),
|
||||
});
|
||||
}
|
||||
for (Binding& segment : binding.segments) {
|
||||
segment.buffer_id = FindBuffer(segment.device_addr, segment.size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ 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_STORAGE_BUFFERS = 32;
|
||||
constexpr u32 NUM_STORAGE_BUFFER_SEGMENTS = 8;
|
||||
constexpr u32 NUM_TEXTURE_BUFFERS = 32;
|
||||
constexpr u32 NUM_STAGES = 5;
|
||||
|
||||
@@ -90,11 +91,10 @@ struct TextureBufferBinding : Binding {
|
||||
};
|
||||
|
||||
struct StorageBufferBindingInfo {
|
||||
// another good one: guest SSBO is a virtual interval and may span discontiguous device-memory ranges.
|
||||
// exact case of missing character frames (high sample lane)
|
||||
GPUVAddr gpu_addr{};
|
||||
u32 size{};
|
||||
u32 descriptor_count{1};
|
||||
u64 mapping_generation{};
|
||||
boost::container::small_vector<Binding, 1> segments;
|
||||
};
|
||||
|
||||
|
||||
@@ -176,12 +176,14 @@ void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_)
|
||||
}
|
||||
|
||||
GPUVAddr MemoryManager::Map(GPUVAddr gpu_addr, DAddr dev_addr, std::size_t size, PTEKind kind, bool is_big_pages) {
|
||||
mapping_generation.fetch_add(1, std::memory_order_release);
|
||||
if (is_big_pages)
|
||||
return BigPageTableOp(gpu_addr, dev_addr, size, kind, EntryType::Mapped);
|
||||
return PageTableOp(gpu_addr, dev_addr, size, kind, EntryType::Mapped);
|
||||
}
|
||||
|
||||
GPUVAddr MemoryManager::MapSparse(GPUVAddr gpu_addr, std::size_t size, bool is_big_pages) {
|
||||
mapping_generation.fetch_add(1, std::memory_order_release);
|
||||
if (is_big_pages)
|
||||
return BigPageTableOp(gpu_addr, 0, size, PTEKind::INVALID, EntryType::Reserved);
|
||||
return PageTableOp(gpu_addr, 0, size, PTEKind::INVALID, EntryType::Reserved);
|
||||
@@ -191,6 +193,7 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
mapping_generation.fetch_add(1, std::memory_order_release);
|
||||
GetSubmappedRangeImpl<false>(gpu_addr, size, page_stash);
|
||||
|
||||
for (const auto& [map_addr, map_size] : page_stash) {
|
||||
|
||||
@@ -145,6 +145,10 @@ public:
|
||||
return gpu_addr < address_space_size;
|
||||
}
|
||||
|
||||
u64 MappingGeneration() const noexcept {
|
||||
return mapping_generation.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
PTEKind GetPageKind(GPUVAddr gpu_addr) const;
|
||||
|
||||
size_t GetMemoryLayoutSize(GPUVAddr gpu_addr,
|
||||
@@ -197,6 +201,8 @@ private:
|
||||
|
||||
VideoCore::RasterizerInterface* rasterizer = nullptr;
|
||||
|
||||
std::atomic<u64> mapping_generation{1};
|
||||
|
||||
enum class EntryType : u64 {
|
||||
Free = 0,
|
||||
Reserved = 1,
|
||||
|
||||
@@ -18,7 +18,7 @@ class Scheduler;
|
||||
|
||||
class DescriptorBufferRing final {
|
||||
static constexpr size_t FRAMES_IN_FLIGHT = 8;
|
||||
static constexpr VkDeviceSize TILER_FRAME_SIZE = 2 * 1024 * 1024;
|
||||
static constexpr VkDeviceSize TILER_FRAME_SIZE = 8 * 1024 * 1024;
|
||||
static constexpr VkDeviceSize DESKTOP_FRAME_SIZE = 4 * 1024 * 1024;
|
||||
|
||||
public:
|
||||
|
||||
@@ -315,7 +315,7 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
try {
|
||||
MakePipeline(render_pass);
|
||||
} catch (const vk::Exception& exception) {
|
||||
LOG_CRITICAL(Render_Vulkan, "Graphics pipeline build failed: {}", exception.what());
|
||||
LOG_DEBUG(Render_Vulkan, "Graphics pipeline build failed: {}", exception.what());
|
||||
std::scoped_lock lock{build_mutex};
|
||||
is_built = true;
|
||||
build_condvar.notify_one();
|
||||
@@ -581,7 +581,6 @@ bool GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
|
||||
const DescriptorBufferRing::Allocation alloc{
|
||||
descriptor_buffer_ring.Allocate(scheduler, descriptor_buffer_layout.size)};
|
||||
if (!alloc.host) {
|
||||
LOG_DEBUG(Render_Vulkan, "Failed to reserve descriptor memory, skipping draw");
|
||||
return false;
|
||||
}
|
||||
WriteDescriptorBuffer(device, descriptor_buffer_layout, entries, alloc.host);
|
||||
|
||||
@@ -62,11 +62,7 @@ using VideoCommon::FileEnvironment;
|
||||
using VideoCommon::GenericEnvironment;
|
||||
using VideoCommon::GraphicsEnvironment;
|
||||
|
||||
// SPIR-V descriptor arrays require a fixed pipeline-layout count.
|
||||
// Exploration ceiling; buffer-cache telemetry records the actual physical-range demand.
|
||||
// Keep this modest because every mapped SSBO binds the full fixed array on each update.
|
||||
const u32 MAX_MAPPED_STORAGE_BUFFER_DESCRIPTORS =
|
||||
(std::max)(6u, static_cast<u32>(Settings::values.debug_knobs.GetValue()));
|
||||
constexpr u32 MAX_MAPPED_STORAGE_BUFFER_DESCRIPTORS = 8;
|
||||
|
||||
constexpr u32 CACHE_VERSION = 19;
|
||||
constexpr size_t VULKAN_CACHE_FLUSH_PIPELINES = 128;
|
||||
|
||||
@@ -40,7 +40,7 @@ class UpdateDescriptorQueue final {
|
||||
static constexpr size_t FRAMES_IN_FLIGHT = 8;
|
||||
|
||||
public:
|
||||
static constexpr size_t GUEST_FRAME_PAYLOAD_SIZE = 0x80000;
|
||||
static constexpr size_t GUEST_FRAME_PAYLOAD_SIZE = 0x40000;
|
||||
static constexpr size_t COMPUTE_FRAME_PAYLOAD_SIZE = 0x20000;
|
||||
|
||||
explicit UpdateDescriptorQueue(const Device& device_, size_t frame_payload_size_,
|
||||
|
||||
Reference in New Issue
Block a user