renderer_vulkan: Cleanup vertex array setup
* Also the function would commit more data then it requested leading to out of bound crashes
This commit is contained in:
@@ -178,7 +178,8 @@ void RasterizerVulkan::SyncFixedState() {
|
|||||||
|
|
||||||
void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_min,
|
void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_min,
|
||||||
u32 vs_input_index_max) {
|
u32 vs_input_index_max) {
|
||||||
auto [array_ptr, array_offset, invalidate] = vertex_buffer.Map(vs_input_size, 4);
|
const u32 vertex_size = vs_input_size + sizeof(Common::Vec4f) * 16;
|
||||||
|
auto [array_ptr, array_offset, invalidate] = vertex_buffer.Map(vertex_size, 4);
|
||||||
|
|
||||||
// The Nintendo 3DS has 12 attribute loaders which are used to tell the GPU
|
// The Nintendo 3DS has 12 attribute loaders which are used to tell the GPU
|
||||||
// how to interpret vertex data. The program firsts sets GPUREG_ATTR_BUF_BASE to the base
|
// how to interpret vertex data. The program firsts sets GPUREG_ATTR_BUF_BASE to the base
|
||||||
@@ -193,7 +194,7 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
|
|||||||
std::array<bool, 16> enable_attributes{};
|
std::array<bool, 16> enable_attributes{};
|
||||||
VertexLayout layout{};
|
VertexLayout layout{};
|
||||||
|
|
||||||
u32 buffer_offset = array_offset;
|
u32 buffer_offset = 0;
|
||||||
for (const auto& loader : vertex_attributes.attribute_loaders) {
|
for (const auto& loader : vertex_attributes.attribute_loaders) {
|
||||||
if (loader.component_count == 0 || loader.byte_count == 0) {
|
if (loader.component_count == 0 || loader.byte_count == 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -233,10 +234,10 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
|
|||||||
const PAddr data_addr =
|
const PAddr data_addr =
|
||||||
base_address + loader.data_offset + (vs_input_index_min * loader.byte_count);
|
base_address + loader.data_offset + (vs_input_index_min * loader.byte_count);
|
||||||
const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1;
|
const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1;
|
||||||
u32 data_size = loader.byte_count * vertex_num;
|
const u32 data_size = loader.byte_count * vertex_num;
|
||||||
|
|
||||||
res_cache.FlushRegion(data_addr, data_size, nullptr);
|
res_cache.FlushRegion(data_addr, data_size);
|
||||||
std::memcpy(array_ptr, VideoCore::g_memory->GetPhysicalPointer(data_addr), data_size);
|
std::memcpy(array_ptr + buffer_offset, VideoCore::g_memory->GetPhysicalPointer(data_addr), data_size);
|
||||||
|
|
||||||
// Create the binding associated with this loader
|
// Create the binding associated with this loader
|
||||||
VertexBinding& binding = layout.bindings[layout.binding_count];
|
VertexBinding& binding = layout.bindings[layout.binding_count];
|
||||||
@@ -245,20 +246,19 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
|
|||||||
binding.stride.Assign(loader.byte_count);
|
binding.stride.Assign(loader.byte_count);
|
||||||
|
|
||||||
// Keep track of the binding offsets so we can bind the vertex buffer later
|
// Keep track of the binding offsets so we can bind the vertex buffer later
|
||||||
binding_offsets[layout.binding_count++] = buffer_offset;
|
binding_offsets[layout.binding_count++] = array_offset + buffer_offset;
|
||||||
data_size = Common::AlignUp(data_size, 16);
|
buffer_offset += Common::AlignUp(data_size, 16);
|
||||||
array_ptr += data_size;
|
|
||||||
buffer_offset += data_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
array_ptr += buffer_offset;
|
||||||
|
|
||||||
// Reserve the last binding for fixed and default attributes
|
// Reserve the last binding for fixed and default attributes
|
||||||
// Place the default attrib at offset zero for easy access
|
// Place the default attrib at offset zero for easy access
|
||||||
constexpr Common::Vec4f default_attrib = Common::MakeVec(0.f, 0.f, 0.f, 1.f);
|
const Common::Vec4f default_attrib = Common::MakeVec(0.f, 0.f, 0.f, 1.f);
|
||||||
u32 offset = sizeof(Common::Vec4f);
|
|
||||||
std::memcpy(array_ptr, default_attrib.AsArray(), sizeof(Common::Vec4f));
|
std::memcpy(array_ptr, default_attrib.AsArray(), sizeof(Common::Vec4f));
|
||||||
array_ptr += sizeof(Common::Vec4f);
|
|
||||||
|
|
||||||
// Find all fixed attributes and assign them to the last binding
|
// Find all fixed attributes and assign them to the last binding
|
||||||
|
u32 offset = sizeof(Common::Vec4f);
|
||||||
for (std::size_t i = 0; i < 16; i++) {
|
for (std::size_t i = 0; i < 16; i++) {
|
||||||
if (vertex_attributes.IsDefaultAttribute(i)) {
|
if (vertex_attributes.IsDefaultAttribute(i)) {
|
||||||
const u32 reg = regs.vs.GetRegisterForAttribute(i);
|
const u32 reg = regs.vs.GetRegisterForAttribute(i);
|
||||||
@@ -268,7 +268,7 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
|
|||||||
attr.w.ToFloat32()};
|
attr.w.ToFloat32()};
|
||||||
|
|
||||||
const u32 data_size = sizeof(float) * static_cast<u32>(data.size());
|
const u32 data_size = sizeof(float) * static_cast<u32>(data.size());
|
||||||
std::memcpy(array_ptr, data.data(), data_size);
|
std::memcpy(array_ptr + offset, data.data(), data_size);
|
||||||
|
|
||||||
VertexAttribute& attribute = layout.attributes[layout.attribute_count++];
|
VertexAttribute& attribute = layout.attributes[layout.attribute_count++];
|
||||||
attribute.binding.Assign(layout.binding_count);
|
attribute.binding.Assign(layout.binding_count);
|
||||||
@@ -278,19 +278,15 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
|
|||||||
attribute.size.Assign(4);
|
attribute.size.Assign(4);
|
||||||
|
|
||||||
offset += data_size;
|
offset += data_size;
|
||||||
array_ptr += data_size;
|
|
||||||
enable_attributes[reg] = true;
|
enable_attributes[reg] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop one more time to find unused attributes and assign them to the default one
|
// Loop one more time to find unused attributes and assign them to the default one
|
||||||
// This needs to happen because i = 2 might be assigned to location = 3 so the loop
|
// If the attribute is just disabled, shove the default attribute to avoid
|
||||||
// above would skip setting it
|
// errors if the shader ever decides to use it.
|
||||||
for (u32 i = 0; i < 16; i++) {
|
for (u32 i = 0; i < 16; i++) {
|
||||||
// If the attribute is just disabled, shove the default attribute to avoid
|
|
||||||
// errors if the shader ever decides to use it. The pipeline cache can discard
|
|
||||||
// this if needed since it has access to the usage mask from the code generator
|
|
||||||
if (!enable_attributes[i]) {
|
if (!enable_attributes[i]) {
|
||||||
VertexAttribute& attribute = layout.attributes[layout.attribute_count++];
|
VertexAttribute& attribute = layout.attributes[layout.attribute_count++];
|
||||||
attribute.binding.Assign(layout.binding_count);
|
attribute.binding.Assign(layout.binding_count);
|
||||||
@@ -306,11 +302,12 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
|
|||||||
binding.binding.Assign(layout.binding_count);
|
binding.binding.Assign(layout.binding_count);
|
||||||
binding.fixed.Assign(1);
|
binding.fixed.Assign(1);
|
||||||
binding.stride.Assign(offset);
|
binding.stride.Assign(offset);
|
||||||
binding_offsets[layout.binding_count++] = buffer_offset;
|
|
||||||
buffer_offset += offset;
|
|
||||||
|
|
||||||
|
binding_offsets[layout.binding_count++] = array_offset + buffer_offset;
|
||||||
|
vertex_buffer.Commit(buffer_offset + offset);
|
||||||
|
|
||||||
|
// Update the pipeline vertex layout
|
||||||
pipeline_info.vertex_layout = layout;
|
pipeline_info.vertex_layout = layout;
|
||||||
vertex_buffer.Commit(buffer_offset - array_offset);
|
|
||||||
|
|
||||||
scheduler.Record([this, layout, offsets = binding_offsets](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
|
scheduler.Record([this, layout, offsets = binding_offsets](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
|
||||||
std::array<vk::Buffer, 16> buffers;
|
std::array<vk::Buffer, 16> buffers;
|
||||||
@@ -331,7 +328,7 @@ bool RasterizerVulkan::SetupGeometryShader() {
|
|||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
if (regs.pipeline.use_gs != Pica::PipelineRegs::UseGS::No) {
|
if (regs.pipeline.use_gs != Pica::PipelineRegs::UseGS::No) {
|
||||||
LOG_ERROR(Render_OpenGL, "Accelerate draw doesn't support geometry shader");
|
LOG_ERROR(Render_Vulkan, "Accelerate draw doesn't support geometry shader");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -154,6 +154,7 @@ void StreamBuffer::Flush() {
|
|||||||
const u32 flush_start = bucket_index * bucket_size + bucket.flush_cursor;
|
const u32 flush_start = bucket_index * bucket_size + bucket.flush_cursor;
|
||||||
const u32 flush_size = bucket.cursor - bucket.flush_cursor;
|
const u32 flush_size = bucket.cursor - bucket.flush_cursor;
|
||||||
ASSERT(flush_size <= bucket_size);
|
ASSERT(flush_size <= bucket_size);
|
||||||
|
ASSERT(flush_start + flush_size <= total_size);
|
||||||
|
|
||||||
if (flush_size > 0) [[likely]] {
|
if (flush_size > 0) [[likely]] {
|
||||||
// Ensure all staging writes are visible to the host memory domain
|
// Ensure all staging writes are visible to the host memory domain
|
||||||
|
Reference in New Issue
Block a user