From e6cfdeb06a82dc90d81bf54e04d1bc3fe62be47e Mon Sep 17 00:00:00 2001 From: lynxnb Date: Thu, 23 Jun 2022 00:14:58 +0200 Subject: [PATCH] Fix non-indexed quad draws Certain non-indexed quad draws would mistakenly take the indexed quad path because of the assumption that they would not have a bound index buffer. This resulted in a crash for most games using quads due to a faulty exception `Indexed quad conversion is not supported`, when in fact they were not using indexed quads. Co-authored-by: PixelyIon Co-authored-by: Billy Laws --- .../gpu/interconnect/graphics_context.h | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index 99cd1530..771e1020 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -1687,7 +1687,7 @@ namespace skyline::gpu::interconnect { * @brief Retrieves an index buffer for converting a non-indexed quad list to a triangle list * @result A tuple containing a view over the index buffer, the index type and the index count */ - std::tuple GetQuadListConversionBuffer(u32 count) { + std::tuple GetNonIndexedQuadConversionBuffer(u32 count) { vk::DeviceSize size{conversion::quads::GetRequiredBufferSize(count, vk::IndexType::eUint32)}; if (!quadListConversionBuffer || quadListConversionBuffer->GetBackingSpan().size_bytes() < size) { quadListConversionBuffer = std::make_shared(gpu, size); @@ -2820,38 +2820,39 @@ namespace skyline::gpu::interconnect { vk::IndexType type{}; }; - auto boundIndexBuffer{std::make_shared()}; + std::shared_ptr boundIndexBuffer{}; if constexpr (IsIndexed) { + if (needsQuadConversion) + throw exception("Indexed quad conversion is not supported"); + auto indexBufferView{GetIndexBuffer(count)}; - if (needsQuadConversion) { - if (indexBufferView) { - throw exception("Indexed quad conversion is not supported"); - } else { - auto[bufferView, indexType, indexCount] = GetQuadListConversionBuffer(count); - indexBufferView = bufferView; - indexBuffer.type = indexType; - count = indexCount; - } + std::scoped_lock lock(indexBufferView); + + boundIndexBuffer = std::make_shared(); + boundIndexBuffer->type = indexBuffer.type; + if (auto megaBufferOffset{indexBufferView.AcquireMegaBuffer(executor.megaBuffer)}) { + // If the buffer is megabuffered then since we don't get out data from the underlying buffer, rather the megabuffer which stays consistent throughout a single execution, we can skip registering usage + boundIndexBuffer->handle = executor.megaBuffer.GetBacking(); + boundIndexBuffer->offset = megaBufferOffset; + } else { + indexBufferView.RegisterUsage(executor.cycle, [=](const Buffer::BufferViewStorage &view, const std::shared_ptr &buffer) { + boundIndexBuffer->handle = buffer->GetBacking(); + boundIndexBuffer->offset = view.offset; + }); } - { - std::scoped_lock lock(indexBufferView); - - boundIndexBuffer->type = indexBuffer.type; - if (auto megaBufferOffset{indexBufferView.AcquireMegaBuffer(executor.megaBuffer)}) { - // If the buffer is megabuffered then since we don't get out data from the underlying buffer, rather the megabuffer which stays consistent throughout a single execution, we can skip registering usage - boundIndexBuffer->handle = executor.megaBuffer.GetBacking(); - boundIndexBuffer->offset = megaBufferOffset; - } else { - indexBufferView.RegisterUsage(executor.cycle, [=](const Buffer::BufferViewStorage &view, const std::shared_ptr &buffer) { - boundIndexBuffer->handle = buffer->GetBacking(); - boundIndexBuffer->offset = view.offset; - }); - } - - executor.AttachBuffer(indexBufferView); - } + executor.AttachBuffer(indexBufferView); + } else if (needsQuadConversion) { + // Convert the guest-supplied quad list to an indexed triangle list + auto[bufferView, indexType, indexCount] = GetNonIndexedQuadConversionBuffer(count); + std::scoped_lock lock(bufferView); + count = indexCount; + boundIndexBuffer = std::make_shared(); + boundIndexBuffer->type = indexType; + boundIndexBuffer->handle = bufferView->buffer->GetBacking(); + boundIndexBuffer->offset = bufferView->view->offset; + executor.AttachBuffer(bufferView); } // Vertex Buffer Setup @@ -3003,7 +3004,7 @@ namespace skyline::gpu::interconnect { commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - if constexpr (IsIndexed) { + if (IsIndexed || boundIndexBuffer) { commandBuffer.bindIndexBuffer(boundIndexBuffer->handle, boundIndexBuffer->offset, boundIndexBuffer->type); commandBuffer.drawIndexed(count, instanceCount, first, vertexOffset, 0); } else { @@ -3015,10 +3016,7 @@ namespace skyline::gpu::interconnect { } void Draw(u32 vertexCount, u32 firstVertex, u32 instanceCount) { - if (needsQuadConversion) - Draw(vertexCount, firstVertex, instanceCount); - else - Draw(vertexCount, firstVertex, instanceCount); + Draw(vertexCount, firstVertex, instanceCount); } void DrawIndexed(u32 indexCount, u32 firstIndex, u32 instanceCount, i32 vertexOffset) {