mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-10-20 21:09:37 +02:00
Some cleanups on the vertex buffer path
This commit is contained in:
parent
eb18c5b8bd
commit
f229172d3b
11 changed files with 74 additions and 117 deletions
|
|
@ -20,8 +20,6 @@ namespace VideoCommon {
|
||||||
|
|
||||||
enum class BufferFlagBits {
|
enum class BufferFlagBits {
|
||||||
Picked = 1 << 0,
|
Picked = 1 << 0,
|
||||||
CachedWrites = 1 << 1,
|
|
||||||
PreemtiveDownload = 1 << 2,
|
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits)
|
DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits)
|
||||||
|
|
||||||
|
|
@ -58,15 +56,6 @@ public:
|
||||||
flags |= BufferFlagBits::Picked;
|
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
|
/// Increases the likeliness of this being a stream buffer
|
||||||
void IncreaseStreamScore(int score) noexcept {
|
void IncreaseStreamScore(int score) noexcept {
|
||||||
stream_score += score;
|
stream_score += score;
|
||||||
|
|
@ -87,15 +76,6 @@ public:
|
||||||
return True(flags & BufferFlagBits::Picked);
|
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
|
/// Returns the base CPU address of the buffer
|
||||||
[[nodiscard]] VAddr CpuAddr() const noexcept {
|
[[nodiscard]] VAddr CpuAddr() const noexcept {
|
||||||
return cpu_addr;
|
return cpu_addr;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
|
|
@ -121,25 +122,6 @@ void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
|
||||||
memory_tracker.MarkRegionAsCpuModified(device_addr, 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>
|
template <class P>
|
||||||
bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
|
bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
|
||||||
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
||||||
|
|
@ -422,7 +404,7 @@ void BufferCache<P>::UnbindGraphicsStorageBuffers(size_t stage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
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) {
|
u32 cbuf_offset, bool is_written) {
|
||||||
const bool already_enabled =
|
const bool already_enabled =
|
||||||
((channel_state->enabled_storage_buffers[stage] >> ssbo_index) & 1U) != 0;
|
((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,
|
LOG_WARNING(HW_GPU,
|
||||||
"Skipping graphics storage buffer {} due to driver limit {}",
|
"Skipping graphics storage buffer {} due to driver limit {}",
|
||||||
ssbo_index, max_bindings);
|
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;
|
const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
|
||||||
channel_state->storage_buffers[stage][ssbo_index] =
|
channel_state->storage_buffers[stage][ssbo_index] =
|
||||||
StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
|
StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
|
||||||
return (channel_state->storage_buffers[stage][ssbo_index].buffer_id != NULL_BUFFER_ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
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>
|
template <class P>
|
||||||
Binding& BufferCache<P>::VertexBufferSlot(u32 index) {
|
Binding& BufferCache<P>::VertexBufferSlot(u32 index) {
|
||||||
ASSERT(index < NUM_VERTEX_BUFFERS);
|
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_begin = index_buffer_ref.StartAddress();
|
||||||
const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
|
const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
|
||||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
|
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);
|
u64 address_size = 0;
|
||||||
const u32 draw_size = (index_buffer_ref.count + index_buffer_ref.first) * u32(index_buffer_ref.FormatSizeInBytes());
|
if (gpu_addr_end > gpu_addr_begin) {
|
||||||
const u32 size = (std::min)(address_size, draw_size);
|
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) {
|
if (size == 0 || !device_addr) {
|
||||||
channel_state->index_buffer = NULL_BINDING;
|
channel_state->index_buffer = NULL_BINDING;
|
||||||
return;
|
return;
|
||||||
|
|
@ -1288,15 +1264,22 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
|
||||||
const GPUVAddr gpu_addr_begin = array.Address();
|
const GPUVAddr gpu_addr_begin = array.Address();
|
||||||
const GPUVAddr gpu_addr_end = limit.Address() + 1;
|
const GPUVAddr gpu_addr_end = limit.Address() + 1;
|
||||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
|
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);
|
if (array.enable == 0 || !device_addr || 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) {
|
|
||||||
channel_state->vertex_buffers[index] = NULL_BINDING;
|
channel_state->vertex_buffers[index] = NULL_BINDING;
|
||||||
UpdateVertexBufferSlot(index, NULL_BINDING);
|
UpdateVertexBufferSlot(index, NULL_BINDING);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || size >= 64_MiB) {
|
// TODO: Analyze stride and number of vertices
|
||||||
size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
|
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 BufferId buffer_id = FindBuffer(*device_addr, size);
|
||||||
const Binding binding{
|
const Binding binding{
|
||||||
|
|
@ -1578,9 +1561,10 @@ template <class P>
|
||||||
BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
|
BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
|
||||||
DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
|
DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
|
||||||
device_addr = Common::AlignDown(device_addr, 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 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);
|
const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
|
||||||
auto& new_buffer = slot_buffers[new_buffer_id];
|
auto& new_buffer = slot_buffers[new_buffer_id];
|
||||||
const size_t size_bytes = new_buffer.SizeBytes();
|
const size_t size_bytes = new_buffer.SizeBytes();
|
||||||
|
|
|
||||||
|
|
@ -217,8 +217,6 @@ public:
|
||||||
|
|
||||||
void WriteMemory(DAddr device_addr, u64 size);
|
void WriteMemory(DAddr device_addr, u64 size);
|
||||||
|
|
||||||
void CachedWriteMemory(DAddr device_addr, u64 size);
|
|
||||||
|
|
||||||
bool OnCPUWrite(DAddr device_addr, u64 size);
|
bool OnCPUWrite(DAddr device_addr, u64 size);
|
||||||
|
|
||||||
void DownloadMemory(DAddr device_addr, u64 size);
|
void DownloadMemory(DAddr device_addr, u64 size);
|
||||||
|
|
@ -248,7 +246,7 @@ public:
|
||||||
|
|
||||||
void UnbindGraphicsStorageBuffers(size_t stage);
|
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);
|
bool is_written);
|
||||||
|
|
||||||
void UnbindGraphicsTextureBuffers(size_t stage);
|
void UnbindGraphicsTextureBuffers(size_t stage);
|
||||||
|
|
@ -376,8 +374,6 @@ private:
|
||||||
|
|
||||||
void BindHostTransformFeedbackBuffers();
|
void BindHostTransformFeedbackBuffers();
|
||||||
|
|
||||||
void BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
|
|
||||||
|
|
||||||
void BindHostComputeUniformBuffers();
|
void BindHostComputeUniformBuffers();
|
||||||
|
|
||||||
void BindHostComputeStorageBuffers();
|
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) {
|
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
||||||
// TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
|
// TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
|
||||||
std::array<GLuint, 32> buffer_handles;
|
std::array<GLuint, 32> buffer_handles;
|
||||||
|
|
|
||||||
|
|
@ -99,8 +99,6 @@ public:
|
||||||
|
|
||||||
void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size);
|
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 BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||||
|
|
||||||
void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size);
|
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) {
|
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
||||||
boost::container::static_vector<VkBuffer, VideoCommon::NUM_VERTEX_BUFFERS> buffer_handles(bindings.buffers.size());
|
boost::container::static_vector<VkBuffer, VideoCommon::NUM_VERTEX_BUFFERS> buffer_handles(bindings.buffers.size());
|
||||||
for (u32 i = 0; i < bindings.buffers.size(); ++i) {
|
for (u32 i = 0; i < bindings.buffers.size(); ++i) {
|
||||||
|
|
|
||||||
|
|
@ -138,8 +138,6 @@ public:
|
||||||
|
|
||||||
void BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count);
|
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 BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||||
|
|
||||||
void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size);
|
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)(
|
const size_t num_vertex_arrays = (std::min)(
|
||||||
Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings()));
|
Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings()));
|
||||||
for (size_t index = 0; index < num_vertex_arrays; ++index) {
|
for (size_t index = 0; index < num_vertex_arrays; ++index) {
|
||||||
const bool instanced = key.state.binding_divisors[index] != 0;
|
const bool instanced = ((key.state.enabled_divisors >> index) & 1) != 0;
|
||||||
const auto rate =
|
auto rate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
if (instanced) {
|
||||||
|
rate = VK_VERTEX_INPUT_RATE_INSTANCE;
|
||||||
|
}
|
||||||
vertex_bindings.push_back({
|
vertex_bindings.push_back({
|
||||||
.binding = static_cast<u32>(index),
|
.binding = static_cast<u32>(index),
|
||||||
.stride = key.state.vertex_strides[index],
|
.stride = key.state.vertex_strides[index],
|
||||||
|
|
@ -705,7 +707,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||||
if (instanced) {
|
if (instanced) {
|
||||||
vertex_binding_divisors.push_back({
|
vertex_binding_divisors.push_back({
|
||||||
.binding = static_cast<u32>(index),
|
.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) {
|
for (u32 binding = 0; binding < max_bindings; ++binding) {
|
||||||
const auto& input_binding{regs.vertex_streams[binding]};
|
const auto& input_binding{regs.vertex_streams[binding]};
|
||||||
const bool is_instanced{regs.vertex_stream_instances.IsInstancingEnabled(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({
|
bindings.push_back({
|
||||||
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT,
|
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.binding = binding,
|
.binding = binding,
|
||||||
.stride = input_binding.stride,
|
.stride = input_binding.stride,
|
||||||
.inputRate = is_instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX,
|
.inputRate = input_rate,
|
||||||
.divisor = is_instanced ? input_binding.frequency : 1,
|
.divisor = divisor,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1219,6 +1219,11 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
|
||||||
SetNext(next, properties.transform_feedback);
|
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) {
|
if (extensions.maintenance5) {
|
||||||
properties.maintenance5.sType =
|
properties.maintenance5.sType =
|
||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR;
|
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, ProvokingVertex, PROVOKING_VERTEX, provoking_vertex) \
|
||||||
FEATURE(EXT, Robustness2, ROBUSTNESS_2, robustness2) \
|
FEATURE(EXT, Robustness2, ROBUSTNESS_2, robustness2) \
|
||||||
FEATURE(EXT, TransformFeedback, TRANSFORM_FEEDBACK, transform_feedback) \
|
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(EXT, VertexInputDynamicState, VERTEX_INPUT_DYNAMIC_STATE, vertex_input_dynamic_state) \
|
||||||
FEATURE(KHR, Maintenance5, MAINTENANCE_5, maintenance5) \
|
FEATURE(KHR, Maintenance5, MAINTENANCE_5, maintenance5) \
|
||||||
FEATURE(KHR, Maintenance6, MAINTENANCE_6, maintenance6) \
|
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_STENCIL_EXPORT, shader_stencil_export) \
|
||||||
EXTENSION(EXT, SHADER_VIEWPORT_INDEX_LAYER, shader_viewport_index_layer) \
|
EXTENSION(EXT, SHADER_VIEWPORT_INDEX_LAYER, shader_viewport_index_layer) \
|
||||||
EXTENSION(EXT, TOOLING_INFO, tooling_info) \
|
EXTENSION(EXT, TOOLING_INFO, tooling_info) \
|
||||||
EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \
|
|
||||||
EXTENSION(KHR, CREATE_RENDERPASS_2, create_renderpass2) \
|
EXTENSION(KHR, CREATE_RENDERPASS_2, create_renderpass2) \
|
||||||
EXTENSION(KHR, DEPTH_STENCIL_RESOLVE, depth_stencil_resolve) \
|
EXTENSION(KHR, DEPTH_STENCIL_RESOLVE, depth_stencil_resolve) \
|
||||||
EXTENSION(KHR, DRAW_INDIRECT_COUNT, draw_indirect_count) \
|
EXTENSION(KHR, DRAW_INDIRECT_COUNT, draw_indirect_count) \
|
||||||
|
|
@ -690,6 +690,32 @@ FN_MAX_LIMIT_LIST
|
||||||
return features.host_query_reset.hostQueryReset != VK_FALSE;
|
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.
|
/// Returns true if the device supports VK_EXT_transform_feedback.
|
||||||
bool IsExtTransformFeedbackSupported() const {
|
bool IsExtTransformFeedbackSupported() const {
|
||||||
return extensions.transform_feedback;
|
return extensions.transform_feedback;
|
||||||
|
|
@ -1190,6 +1216,7 @@ private:
|
||||||
VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer{};
|
VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer{};
|
||||||
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
||||||
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
||||||
|
VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_attribute_divisor{};
|
||||||
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
||||||
VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve{};
|
VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve{};
|
||||||
VkPhysicalDeviceCustomBorderColorPropertiesEXT custom_border_color{};
|
VkPhysicalDeviceCustomBorderColorPropertiesEXT custom_border_color{};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue