mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 17:22:00 +01:00
Implement QuadList
support for non-indexed draws
This commit is contained in:
parent
bcaf7dfe1c
commit
0d9992cb8e
@ -171,6 +171,7 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/gpu/shader_manager.cpp
|
${source_DIR}/skyline/gpu/shader_manager.cpp
|
||||||
${source_DIR}/skyline/gpu/interconnect/command_executor.cpp
|
${source_DIR}/skyline/gpu/interconnect/command_executor.cpp
|
||||||
${source_DIR}/skyline/gpu/interconnect/command_nodes.cpp
|
${source_DIR}/skyline/gpu/interconnect/command_nodes.cpp
|
||||||
|
${source_DIR}/skyline/gpu/interconnect/conversion/quads.cpp
|
||||||
${source_DIR}/skyline/soc/smmu.cpp
|
${source_DIR}/skyline/soc/smmu.cpp
|
||||||
${source_DIR}/skyline/soc/host1x/syncpoint.cpp
|
${source_DIR}/skyline/soc/host1x/syncpoint.cpp
|
||||||
${source_DIR}/skyline/soc/host1x/command_fifo.cpp
|
${source_DIR}/skyline/soc/host1x/command_fifo.cpp
|
||||||
|
@ -87,6 +87,16 @@ namespace skyline::gpu {
|
|||||||
return backing.vkBuffer;
|
return backing.vkBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A span over the backing of this buffer
|
||||||
|
* @note This operation **must** be performed only on host-only buffers since synchronization is handled internally for guest-backed buffers
|
||||||
|
*/
|
||||||
|
span<u8> GetBackingSpan() {
|
||||||
|
if (guest)
|
||||||
|
throw exception("Attempted to get a span of a guest-backed buffer");
|
||||||
|
return span<u8>(backing);
|
||||||
|
}
|
||||||
|
|
||||||
Buffer(GPU &gpu, GuestBuffer guest);
|
Buffer(GPU &gpu, GuestBuffer guest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include "quads.h"
|
||||||
|
|
||||||
|
namespace skyline::gpu::interconnect::conversion::quads {
|
||||||
|
void GenerateQuadListConversionBuffer(u32 *dest, u32 vertexCount) {
|
||||||
|
#pragma clang loop vectorize(enable) interleave(enable) unroll(enable)
|
||||||
|
for (u32 i{}; i < vertexCount; i += 4) {
|
||||||
|
// Given a quad ABCD, we want to generate triangles ABC & CDA
|
||||||
|
// Triangle ABC
|
||||||
|
*(dest++) = i + 0;
|
||||||
|
*(dest++) = i + 1;
|
||||||
|
*(dest++) = i + 2;
|
||||||
|
|
||||||
|
// Triangle CDA
|
||||||
|
*(dest++) = i + 2;
|
||||||
|
*(dest++) = i + 3;
|
||||||
|
*(dest++) = i + 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
app/src/main/cpp/skyline/gpu/interconnect/conversion/quads.h
Normal file
33
app/src/main/cpp/skyline/gpu/interconnect/conversion/quads.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common/base.h>
|
||||||
|
|
||||||
|
namespace skyline::gpu::interconnect::conversion::quads {
|
||||||
|
constexpr u32 EmittedIndexCount{6}; //!< The number of indices needed to draw a quad with two triangles
|
||||||
|
constexpr u32 QuadVertexCount{4}; //!< The amount of vertices a quad is composed of
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The amount of indices emitted converting a buffer with the supplied element count
|
||||||
|
*/
|
||||||
|
constexpr u32 GetIndexCount(u32 count) {
|
||||||
|
return (count * EmittedIndexCount) / QuadVertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The minimum size (in bytes) required to store the quad index buffer of the given type after conversion
|
||||||
|
* @tparam T The type of an element in the index buffer
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
constexpr size_t GetRequiredBufferSize(u32 count) {
|
||||||
|
return GetIndexCount(count) * sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create an index buffer that repeats quad vertices to generate a triangle list
|
||||||
|
* @note The size of the supplied buffer should be at least the size returned by GetRequiredBufferSize()
|
||||||
|
*/
|
||||||
|
void GenerateQuadListConversionBuffer(u32 *dest, u32 vertexCount);
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
#include "command_executor.h"
|
#include "command_executor.h"
|
||||||
#include "types/tsc.h"
|
#include "types/tsc.h"
|
||||||
#include "types/tic.h"
|
#include "types/tic.h"
|
||||||
|
#include "conversion/quads.h"
|
||||||
|
|
||||||
namespace skyline::gpu::interconnect {
|
namespace skyline::gpu::interconnect {
|
||||||
namespace maxwell3d = soc::gm20b::engine::maxwell3d::type;
|
namespace maxwell3d = soc::gm20b::engine::maxwell3d::type;
|
||||||
@ -1581,6 +1582,25 @@ namespace skyline::gpu::interconnect {
|
|||||||
};
|
};
|
||||||
std::array<VertexAttribute, maxwell3d::VertexAttributeCount> vertexAttributes{};
|
std::array<VertexAttribute, maxwell3d::VertexAttributeCount> vertexAttributes{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool needsQuadConversion{}; //!< Whether the current primitive topology is quads and needs conversion to triangles
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Buffer> quadListConversionBuffer{}; //!< Index buffer used for QuadList conversion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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<BufferView, vk::IndexType, u32> GetQuadListConversionBuffer(u32 count) {
|
||||||
|
vk::DeviceSize size{conversion::quads::GetRequiredBufferSize<u32>(count)};
|
||||||
|
if (!quadListConversionBuffer || quadListConversionBuffer->GetBackingSpan().size_bytes() < size) {
|
||||||
|
quadListConversionBuffer = std::make_shared<Buffer>(gpu, size);
|
||||||
|
conversion::quads::GenerateQuadListConversionBuffer(quadListConversionBuffer->GetBackingSpan().cast<u32>().data(), count);
|
||||||
|
}
|
||||||
|
return {quadListConversionBuffer->GetView(0, size), vk::IndexType::eUint32, conversion::quads::GetIndexCount(count)};
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void SetVertexBufferStride(u32 index, u32 stride) {
|
void SetVertexBufferStride(u32 index, u32 stride) {
|
||||||
vertexBuffers[index].bindingDescription.stride = stride;
|
vertexBuffers[index].bindingDescription.stride = stride;
|
||||||
@ -1774,27 +1794,29 @@ namespace skyline::gpu::interconnect {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void SetPrimitiveTopology(maxwell3d::PrimitiveTopology topology) {
|
void SetPrimitiveTopology(maxwell3d::PrimitiveTopology topology) {
|
||||||
auto[vkTopology, shaderTopology] = [topology]() -> std::tuple<vk::PrimitiveTopology, ShaderCompiler::InputTopology> {
|
auto[vkTopology, shaderTopology, isQuad] = [topology]() -> std::tuple<vk::PrimitiveTopology, ShaderCompiler::InputTopology, bool> {
|
||||||
using MaxwellTopology = maxwell3d::PrimitiveTopology;
|
using MaxwellTopology = maxwell3d::PrimitiveTopology;
|
||||||
using VkTopology = vk::PrimitiveTopology;
|
using VkTopology = vk::PrimitiveTopology;
|
||||||
using ShaderTopology = ShaderCompiler::InputTopology;
|
using ShaderTopology = ShaderCompiler::InputTopology;
|
||||||
switch (topology) {
|
switch (topology) {
|
||||||
// @fmt:off
|
// @fmt:off
|
||||||
|
|
||||||
case MaxwellTopology::PointList: return {VkTopology::ePointList, ShaderTopology::Points};
|
case MaxwellTopology::PointList: return {VkTopology::ePointList, ShaderTopology::Points, false};
|
||||||
|
|
||||||
case MaxwellTopology::LineList: return {VkTopology::eLineList, ShaderTopology::Lines};
|
case MaxwellTopology::LineList: return {VkTopology::eLineList, ShaderTopology::Lines, false};
|
||||||
case MaxwellTopology::LineStrip: return {VkTopology::eLineStrip, ShaderTopology::Lines};
|
case MaxwellTopology::LineStrip: return {VkTopology::eLineStrip, ShaderTopology::Lines, false};
|
||||||
case MaxwellTopology::LineListWithAdjacency: return {VkTopology::eLineListWithAdjacency, ShaderTopology::LinesAdjacency};
|
case MaxwellTopology::LineListWithAdjacency: return {VkTopology::eLineListWithAdjacency, ShaderTopology::LinesAdjacency, false};
|
||||||
case MaxwellTopology::LineStripWithAdjacency: return {VkTopology::eLineStripWithAdjacency, ShaderTopology::LinesAdjacency};
|
case MaxwellTopology::LineStripWithAdjacency: return {VkTopology::eLineStripWithAdjacency, ShaderTopology::LinesAdjacency, false};
|
||||||
|
|
||||||
case MaxwellTopology::TriangleList: return {VkTopology::eTriangleList, ShaderTopology::Triangles};
|
case MaxwellTopology::TriangleList: return {VkTopology::eTriangleList, ShaderTopology::Triangles, false};
|
||||||
case MaxwellTopology::TriangleStrip: return {VkTopology::eTriangleStrip, ShaderTopology::Triangles};
|
case MaxwellTopology::TriangleStrip: return {VkTopology::eTriangleStrip, ShaderTopology::Triangles, false};
|
||||||
case MaxwellTopology::TriangleFan: return {VkTopology::eTriangleFan, ShaderTopology::Triangles};
|
case MaxwellTopology::TriangleFan: return {VkTopology::eTriangleFan, ShaderTopology::Triangles, false};
|
||||||
case MaxwellTopology::TriangleListWithAdjacency: return {VkTopology::eTriangleListWithAdjacency, ShaderTopology::TrianglesAdjacency};
|
case MaxwellTopology::TriangleListWithAdjacency: return {VkTopology::eTriangleListWithAdjacency, ShaderTopology::TrianglesAdjacency, false};
|
||||||
case MaxwellTopology::TriangleStripWithAdjacency: return {VkTopology::eTriangleStripWithAdjacency, ShaderTopology::TrianglesAdjacency};
|
case MaxwellTopology::TriangleStripWithAdjacency: return {VkTopology::eTriangleStripWithAdjacency, ShaderTopology::TrianglesAdjacency, false};
|
||||||
|
|
||||||
case MaxwellTopology::PatchList: return {VkTopology::ePatchList, ShaderTopology::Triangles};
|
case MaxwellTopology::QuadList: return {VkTopology::eTriangleList, ShaderTopology::Triangles, true};
|
||||||
|
|
||||||
|
case MaxwellTopology::PatchList: return {VkTopology::ePatchList, ShaderTopology::Triangles, false};
|
||||||
|
|
||||||
// @fmt:on
|
// @fmt:on
|
||||||
|
|
||||||
@ -1804,6 +1826,7 @@ namespace skyline::gpu::interconnect {
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
inputAssemblyState.topology = vkTopology;
|
inputAssemblyState.topology = vkTopology;
|
||||||
|
needsQuadConversion = isQuad;
|
||||||
UpdateRuntimeInformation(runtimeInfo.input_topology, shaderTopology, maxwell3d::PipelineStage::Geometry);
|
UpdateRuntimeInformation(runtimeInfo.input_topology, shaderTopology, maxwell3d::PipelineStage::Geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2595,6 +2618,18 @@ namespace skyline::gpu::interconnect {
|
|||||||
auto boundIndexBuffer{std::make_shared<BoundIndexBuffer>()};
|
auto boundIndexBuffer{std::make_shared<BoundIndexBuffer>()};
|
||||||
if constexpr (IsIndexed) {
|
if constexpr (IsIndexed) {
|
||||||
auto indexBufferView{GetIndexBuffer(count)};
|
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);
|
std::scoped_lock lock(indexBufferView);
|
||||||
|
|
||||||
|
@ -618,7 +618,10 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
|
|||||||
})
|
})
|
||||||
|
|
||||||
ENGINE_CASE(drawVertexCount, {
|
ENGINE_CASE(drawVertexCount, {
|
||||||
context.DrawVertex(drawVertexCount, *registers.drawVertexFirst);
|
if (context.needsQuadConversion)
|
||||||
|
context.DrawIndexed(drawVertexCount, *registers.drawVertexFirst, 0);
|
||||||
|
else
|
||||||
|
context.DrawVertex(drawVertexCount, *registers.drawVertexFirst);
|
||||||
})
|
})
|
||||||
|
|
||||||
ENGINE_CASE(drawIndexCount, {
|
ENGINE_CASE(drawIndexCount, {
|
||||||
|
Loading…
Reference in New Issue
Block a user