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 <pixelyion@protonmail.com>
Co-authored-by: Billy Laws <blaws05@gmail.com>
This commit is contained in:
lynxnb 2022-06-23 00:14:58 +02:00
parent 8fc3bc75f4
commit e6cfdeb06a

View File

@ -1687,7 +1687,7 @@ namespace skyline::gpu::interconnect {
* @brief Retrieves an index buffer for converting a non-indexed quad list to a triangle list * @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 * @result A tuple containing a view over the index buffer, the index type and the index count
*/ */
std::tuple<BufferView, vk::IndexType, u32> GetQuadListConversionBuffer(u32 count) { std::tuple<BufferView, vk::IndexType, u32> GetNonIndexedQuadConversionBuffer(u32 count) {
vk::DeviceSize size{conversion::quads::GetRequiredBufferSize(count, vk::IndexType::eUint32)}; vk::DeviceSize size{conversion::quads::GetRequiredBufferSize(count, vk::IndexType::eUint32)};
if (!quadListConversionBuffer || quadListConversionBuffer->GetBackingSpan().size_bytes() < size) { if (!quadListConversionBuffer || quadListConversionBuffer->GetBackingSpan().size_bytes() < size) {
quadListConversionBuffer = std::make_shared<Buffer>(gpu, size); quadListConversionBuffer = std::make_shared<Buffer>(gpu, size);
@ -2820,38 +2820,39 @@ namespace skyline::gpu::interconnect {
vk::IndexType type{}; vk::IndexType type{};
}; };
auto boundIndexBuffer{std::make_shared<BoundIndexBuffer>()}; std::shared_ptr<BoundIndexBuffer> boundIndexBuffer{};
if constexpr (IsIndexed) { if constexpr (IsIndexed) {
if (needsQuadConversion)
throw exception("Indexed quad conversion is not supported");
auto indexBufferView{GetIndexBuffer(count)}; auto indexBufferView{GetIndexBuffer(count)};
if (needsQuadConversion) { std::scoped_lock lock(indexBufferView);
if (indexBufferView) {
throw exception("Indexed quad conversion is not supported"); boundIndexBuffer = std::make_shared<BoundIndexBuffer>();
} else { boundIndexBuffer->type = indexBuffer.type;
auto[bufferView, indexType, indexCount] = GetQuadListConversionBuffer(count); if (auto megaBufferOffset{indexBufferView.AcquireMegaBuffer(executor.megaBuffer)}) {
indexBufferView = bufferView; // 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
indexBuffer.type = indexType; boundIndexBuffer->handle = executor.megaBuffer.GetBacking();
count = indexCount; boundIndexBuffer->offset = megaBufferOffset;
} } else {
indexBufferView.RegisterUsage(executor.cycle, [=](const Buffer::BufferViewStorage &view, const std::shared_ptr<Buffer> &buffer) {
boundIndexBuffer->handle = buffer->GetBacking();
boundIndexBuffer->offset = view.offset;
});
} }
{ executor.AttachBuffer(indexBufferView);
std::scoped_lock lock(indexBufferView); } else if (needsQuadConversion) {
// Convert the guest-supplied quad list to an indexed triangle list
boundIndexBuffer->type = indexBuffer.type; auto[bufferView, indexType, indexCount] = GetNonIndexedQuadConversionBuffer(count);
if (auto megaBufferOffset{indexBufferView.AcquireMegaBuffer(executor.megaBuffer)}) { std::scoped_lock lock(bufferView);
// 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 count = indexCount;
boundIndexBuffer->handle = executor.megaBuffer.GetBacking(); boundIndexBuffer = std::make_shared<BoundIndexBuffer>();
boundIndexBuffer->offset = megaBufferOffset; boundIndexBuffer->type = indexType;
} else { boundIndexBuffer->handle = bufferView->buffer->GetBacking();
indexBufferView.RegisterUsage(executor.cycle, [=](const Buffer::BufferViewStorage &view, const std::shared_ptr<Buffer> &buffer) { boundIndexBuffer->offset = bufferView->view->offset;
boundIndexBuffer->handle = buffer->GetBacking(); executor.AttachBuffer(bufferView);
boundIndexBuffer->offset = view.offset;
});
}
executor.AttachBuffer(indexBufferView);
}
} }
// Vertex Buffer Setup // Vertex Buffer Setup
@ -3003,7 +3004,7 @@ namespace skyline::gpu::interconnect {
commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
if constexpr (IsIndexed) { if (IsIndexed || boundIndexBuffer) {
commandBuffer.bindIndexBuffer(boundIndexBuffer->handle, boundIndexBuffer->offset, boundIndexBuffer->type); commandBuffer.bindIndexBuffer(boundIndexBuffer->handle, boundIndexBuffer->offset, boundIndexBuffer->type);
commandBuffer.drawIndexed(count, instanceCount, first, vertexOffset, 0); commandBuffer.drawIndexed(count, instanceCount, first, vertexOffset, 0);
} else { } else {
@ -3015,10 +3016,7 @@ namespace skyline::gpu::interconnect {
} }
void Draw(u32 vertexCount, u32 firstVertex, u32 instanceCount) { void Draw(u32 vertexCount, u32 firstVertex, u32 instanceCount) {
if (needsQuadConversion) Draw<false>(vertexCount, firstVertex, instanceCount);
Draw<true>(vertexCount, firstVertex, instanceCount);
else
Draw<false>(vertexCount, firstVertex, instanceCount);
} }
void DrawIndexed(u32 indexCount, u32 firstIndex, u32 instanceCount, i32 vertexOffset) { void DrawIndexed(u32 indexCount, u32 firstIndex, u32 instanceCount, i32 vertexOffset) {