mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-02 02:58:46 +00:00
Some cleanups on the vertex buffer path
This commit is contained in:
@@ -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);
|
||||
@@ -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;
|
||||
@@ -1288,15 +1264,22 @@ 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
|
||||
u64 address_size = (std::min)(gpu_addr_end - gpu_addr_begin,
|
||||
u64{(std::numeric_limits<u32>::max)()});
|
||||
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || address_size >= 64_MiB) {
|
||||
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 +1561,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();
|
||||
|
||||
@@ -217,8 +217,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 +246,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);
|
||||
@@ -376,8 +374,6 @@ private:
|
||||
|
||||
void BindHostTransformFeedbackBuffers();
|
||||
|
||||
void BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
|
||||
|
||||
void BindHostComputeUniformBuffers();
|
||||
|
||||
void BindHostComputeStorageBuffers();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1917,13 +1917,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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1219,6 +1219,11 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
|
||||
SetNext(next, properties.transform_feedback);
|
||||
}
|
||||
if (extensions.vertex_attribute_divisor) {
|
||||
properties.vertex_attribute_divisor.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
|
||||
SetNext(next, properties.vertex_attribute_divisor);
|
||||
}
|
||||
if (extensions.maintenance5) {
|
||||
properties.maintenance5.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR;
|
||||
|
||||
@@ -70,6 +70,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
FEATURE(EXT, ProvokingVertex, PROVOKING_VERTEX, provoking_vertex) \
|
||||
FEATURE(EXT, Robustness2, ROBUSTNESS_2, robustness2) \
|
||||
FEATURE(EXT, TransformFeedback, TRANSFORM_FEEDBACK, transform_feedback) \
|
||||
FEATURE(EXT, VertexAttributeDivisor, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \
|
||||
FEATURE(EXT, VertexInputDynamicState, VERTEX_INPUT_DYNAMIC_STATE, vertex_input_dynamic_state) \
|
||||
FEATURE(KHR, Maintenance5, MAINTENANCE_5, maintenance5) \
|
||||
FEATURE(KHR, Maintenance6, MAINTENANCE_6, maintenance6) \
|
||||
@@ -92,7 +93,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
EXTENSION(EXT, SHADER_STENCIL_EXPORT, shader_stencil_export) \
|
||||
EXTENSION(EXT, SHADER_VIEWPORT_INDEX_LAYER, shader_viewport_index_layer) \
|
||||
EXTENSION(EXT, TOOLING_INFO, tooling_info) \
|
||||
EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \
|
||||
EXTENSION(KHR, CREATE_RENDERPASS_2, create_renderpass2) \
|
||||
EXTENSION(KHR, DEPTH_STENCIL_RESOLVE, depth_stencil_resolve) \
|
||||
EXTENSION(KHR, DRAW_INDIRECT_COUNT, draw_indirect_count) \
|
||||
@@ -690,6 +690,32 @@ FN_MAX_LIMIT_LIST
|
||||
return features.host_query_reset.hostQueryReset != VK_FALSE;
|
||||
}
|
||||
|
||||
u32 GetMaxVertexAttribDivisor() const {
|
||||
const u32 reported = properties.vertex_attribute_divisor.maxVertexAttribDivisor;
|
||||
if (reported == 0) {
|
||||
return 1;
|
||||
}
|
||||
return reported;
|
||||
}
|
||||
|
||||
bool IsVertexAttributeInstanceRateZeroDivisorSupported() const {
|
||||
return features.vertex_attribute_divisor.vertexAttributeInstanceRateZeroDivisor == VK_TRUE;
|
||||
}
|
||||
|
||||
u32 GetVertexAttribDivisor(u32 frequency) const {
|
||||
const u32 max_divisor = GetMaxVertexAttribDivisor();
|
||||
if (frequency == 0) {
|
||||
if (IsVertexAttributeInstanceRateZeroDivisorSupported()) {
|
||||
return 0;
|
||||
}
|
||||
return max_divisor;
|
||||
}
|
||||
if (frequency > max_divisor) {
|
||||
return max_divisor;
|
||||
}
|
||||
return frequency;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_transform_feedback.
|
||||
bool IsExtTransformFeedbackSupported() const {
|
||||
return extensions.transform_feedback;
|
||||
@@ -1190,6 +1216,7 @@ private:
|
||||
VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer{};
|
||||
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
||||
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
||||
VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_attribute_divisor{};
|
||||
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
||||
VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve{};
|
||||
VkPhysicalDeviceCustomBorderColorPropertiesEXT custom_border_color{};
|
||||
|
||||
Reference in New Issue
Block a user