mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 12:41:50 +01:00
Implement Maxwell3D Index Buffers
Adds support for index buffers including U8 index buffers via the `VK_EXT_index_type_uint8` extension which has been added as an optional quirk but an exception will be thrown if the guest utilizes it but the host doesn't support it.
This commit is contained in:
parent
a4041364e1
commit
23cdfe2139
@ -1256,7 +1256,6 @@ namespace skyline::gpu::interconnect {
|
||||
/* Vertex Buffers */
|
||||
private:
|
||||
struct VertexBuffer {
|
||||
bool disabled{};
|
||||
vk::VertexInputBindingDescription bindingDescription{};
|
||||
vk::VertexInputBindingDivisorDescriptionEXT bindingDivisorDescription{};
|
||||
IOVA start{}, end{}; //!< IOVAs covering a contiguous region in GPU AS with the vertex buffer
|
||||
@ -1472,10 +1471,10 @@ namespace skyline::gpu::interconnect {
|
||||
|
||||
BufferView *GetVertexBuffer(size_t index) {
|
||||
auto &vertexBuffer{vertexBuffers.at(index)};
|
||||
if (vertexBuffer.disabled || vertexBuffer.start > vertexBuffer.end || vertexBuffer.start == 0 || vertexBuffer.end == 0)
|
||||
if (vertexBuffer.start > vertexBuffer.end || vertexBuffer.start == 0 || vertexBuffer.end == 0)
|
||||
return nullptr;
|
||||
else if (vertexBuffer.view)
|
||||
return &*vertexBuffer.view;
|
||||
return vertexBuffer.view.get();
|
||||
|
||||
if (vertexBuffer.guest.mappings.empty()) {
|
||||
auto mappings{channelCtx.asCtx->gmmu.TranslateRange(vertexBuffer.start, (vertexBuffer.end + 1) - vertexBuffer.start)};
|
||||
@ -1525,6 +1524,85 @@ namespace skyline::gpu::interconnect {
|
||||
UpdateRuntimeInformation(runtimeInfo.input_topology, shaderTopology, maxwell3d::PipelineStage::Geometry);
|
||||
}
|
||||
|
||||
/* Index Buffer */
|
||||
private:
|
||||
struct IndexBuffer {
|
||||
IOVA start{}, end{}; //!< IOVAs covering a contiguous region in GPU AS containing the index buffer (end does not represent the true extent of the index buffers, just a maximum possible extent and is set to extremely high values which cannot be used to create a buffer)
|
||||
vk::IndexType type{};
|
||||
vk::DeviceSize viewSize{}; //!< The size of the cached view
|
||||
std::shared_ptr<BufferView> view{}; //!< A cached view tied to the IOVAs and size to allow for a faster lookup
|
||||
|
||||
vk::DeviceSize GetIndexBufferSize(u32 elementCount) {
|
||||
switch (type) {
|
||||
case vk::IndexType::eUint8EXT:
|
||||
return sizeof(u8) * elementCount;
|
||||
case vk::IndexType::eUint16:
|
||||
return sizeof(u16) * elementCount;
|
||||
case vk::IndexType::eUint32:
|
||||
return sizeof(u32) * elementCount;
|
||||
|
||||
default:
|
||||
throw exception("Unsupported Vulkan Index Type: {}", vk::to_string(type));
|
||||
}
|
||||
}
|
||||
} indexBuffer{};
|
||||
|
||||
public:
|
||||
void SetIndexBufferStartIovaHigh(u32 high) {
|
||||
indexBuffer.start.high = high;
|
||||
indexBuffer.view.reset();
|
||||
}
|
||||
|
||||
void SetIndexBufferStartIovaLow(u32 low) {
|
||||
indexBuffer.start.low = low;
|
||||
indexBuffer.view.reset();
|
||||
}
|
||||
|
||||
void SetIndexBufferEndIovaHigh(u32 high) {
|
||||
indexBuffer.end.high = high;
|
||||
indexBuffer.view.reset();
|
||||
}
|
||||
|
||||
void SetIndexBufferEndIovaLow(u32 low) {
|
||||
indexBuffer.end.low = low;
|
||||
indexBuffer.view.reset();
|
||||
}
|
||||
|
||||
void SetIndexBufferFormat(maxwell3d::IndexBuffer::Format format) {
|
||||
indexBuffer.type = [format]() {
|
||||
using MaxwellFormat = maxwell3d::IndexBuffer::Format;
|
||||
using VkFormat = vk::IndexType;
|
||||
switch (format) {
|
||||
case MaxwellFormat::Uint8:
|
||||
return VkFormat::eUint8EXT;
|
||||
case MaxwellFormat::Uint16:
|
||||
return VkFormat::eUint16;
|
||||
case MaxwellFormat::Uint32:
|
||||
return VkFormat::eUint32;
|
||||
}
|
||||
}();
|
||||
|
||||
if (indexBuffer.type == vk::IndexType::eUint8EXT && !gpu.quirks.supportsUint8Indices)
|
||||
throw exception("Cannot use U8 index buffer without host GPU support");
|
||||
|
||||
indexBuffer.view.reset();
|
||||
}
|
||||
|
||||
BufferView *GetIndexBuffer(u32 elementCount) {
|
||||
auto size{indexBuffer.GetIndexBufferSize(elementCount)};
|
||||
if (indexBuffer.start > indexBuffer.end || indexBuffer.start == 0 || indexBuffer.end == 0 || size == 0)
|
||||
return nullptr;
|
||||
else if (indexBuffer.view && size == indexBuffer.viewSize)
|
||||
return indexBuffer.view.get();
|
||||
|
||||
GuestBuffer guestBuffer;
|
||||
auto mappings{channelCtx.asCtx->gmmu.TranslateRange(indexBuffer.start, size)};
|
||||
guestBuffer.mappings.assign(mappings.begin(), mappings.end());
|
||||
|
||||
indexBuffer.view = gpu.buffer.FindOrCreate(guestBuffer);
|
||||
return indexBuffer.view.get();
|
||||
}
|
||||
|
||||
/* Depth */
|
||||
vk::PipelineDepthStencilStateCreateInfo depthState{};
|
||||
|
||||
|
@ -27,6 +27,7 @@ namespace skyline::gpu {
|
||||
std::string_view extensionName{extension.extensionName};
|
||||
auto extensionVersion{extension.specVersion};
|
||||
switch (util::Hash(extensionName)) {
|
||||
EXT_SET("VK_EXT_index_type_uint8", supportsUint8Indices);
|
||||
EXT_SET("VK_EXT_provoking_vertex", supportsLastProvokingVertex);
|
||||
EXT_SET("VK_EXT_vertex_attribute_divisor", supportsVertexAttributeDivisor);
|
||||
EXT_SET("VK_EXT_shader_viewport_index_layer", supportsShaderViewportIndexLayer);
|
||||
@ -84,6 +85,6 @@ namespace skyline::gpu {
|
||||
}
|
||||
|
||||
std::string QuirkManager::Summary() {
|
||||
return fmt::format("\n* Supports Last Provoking Vertex: {}\n* Supports Logical Operations: {}\n* Supports Vertex Attribute Divisor: {}\n* Supports Vertex Attribute Zero Divisor: {}\n* Supports Multiple Viewports: {}\n* Supports Shader Viewport Index: {}\n* Supports SPIR-V 1.4: {}\n* Supports 16-bit FP: {}\n* Supports 8-bit Integers: {}\n* Supports 16-bit Integers: {}\n* Supports 64-bit Integers: {}\n* Supports Atomic 64-bit Integers: {}\n* Supports Floating Point Behavior Control: {}\n* Supports Image Read Without Format: {}\n* Supports Subgroup Vote: {}\n* Subgroup Size: {}", supportsLastProvokingVertex, supportsLogicOp, supportsVertexAttributeDivisor, supportsVertexAttributeZeroDivisor, supportsMultipleViewports, supportsShaderViewportIndexLayer, supportsSpirv14, supportsFloat16, supportsInt8, supportsInt16, supportsInt64, supportsAtomicInt64, supportsFloatControls, supportsImageReadWithoutFormat, supportsSubgroupVote, subgroupSize);
|
||||
return fmt::format("\n* Supports U8 Indices: {}\n* Supports Last Provoking Vertex: {}\n* Supports Logical Operations: {}\n* Supports Vertex Attribute Divisor: {}\n* Supports Vertex Attribute Zero Divisor: {}\n* Supports Multiple Viewports: {}\n* Supports Shader Viewport Index: {}\n* Supports SPIR-V 1.4: {}\n* Supports 16-bit FP: {}\n* Supports 8-bit Integers: {}\n* Supports 16-bit Integers: {}\n* Supports 64-bit Integers: {}\n* Supports Atomic 64-bit Integers: {}\n* Supports Floating Point Behavior Control: {}\n* Supports Image Read Without Format: {}\n* Supports Subgroup Vote: {}\n* Subgroup Size: {}", supportsUint8Indices, supportsLastProvokingVertex, supportsLogicOp, supportsVertexAttributeDivisor, supportsVertexAttributeZeroDivisor, supportsMultipleViewports, supportsShaderViewportIndexLayer, supportsSpirv14, supportsFloat16, supportsInt8, supportsInt16, supportsInt64, supportsAtomicInt64, supportsFloatControls, supportsImageReadWithoutFormat, supportsSubgroupVote, subgroupSize);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ namespace skyline::gpu {
|
||||
*/
|
||||
class QuirkManager {
|
||||
public:
|
||||
bool supportsUint8Indices{}; //!< If the device supports using uint8 indices in index buffers
|
||||
bool supportsLastProvokingVertex{}; //!< If the device supports setting the last vertex as the provoking vertex (with VK_EXT_provoking_vertex)
|
||||
bool supportsLogicOp{}; //!< If the device supports framebuffer logical operations during blending
|
||||
bool supportsVertexAttributeDivisor{}; //!< If the device supports a divisor for instance-rate vertex attributes (with VK_EXT_vertex_attribute_divisor)
|
||||
|
@ -715,5 +715,14 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
|
||||
};
|
||||
static_assert(sizeof(SetProgramInfo) == (sizeof(u32) * 0x10));
|
||||
|
||||
struct IndexBuffer {
|
||||
Address start, limit; //!< The IOVA bounds of the index buffer
|
||||
enum class Format : u32 {
|
||||
Uint8 = 0,
|
||||
Uint16 = 1,
|
||||
Uint32 = 2,
|
||||
} format;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
}
|
||||
|
@ -447,6 +447,22 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
|
||||
context.SetConstantBufferSelectorIovaLow(low);
|
||||
})
|
||||
|
||||
MAXWELL3D_STRUCT_STRUCT_CASE(indexBuffer, start, high, {
|
||||
context.SetIndexBufferStartIovaHigh(high);
|
||||
})
|
||||
MAXWELL3D_STRUCT_STRUCT_CASE(indexBuffer, start, low, {
|
||||
context.SetIndexBufferStartIovaLow(low);
|
||||
})
|
||||
MAXWELL3D_STRUCT_STRUCT_CASE(indexBuffer, limit, high, {
|
||||
context.SetIndexBufferEndIovaHigh(high);
|
||||
})
|
||||
MAXWELL3D_STRUCT_STRUCT_CASE(indexBuffer, limit, low, {
|
||||
context.SetIndexBufferEndIovaLow(low);
|
||||
})
|
||||
MAXWELL3D_STRUCT_CASE(indexBuffer, format, {
|
||||
context.SetIndexBufferFormat(format);
|
||||
})
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -222,6 +222,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
|
||||
|
||||
Register<0x5A1, u32> provokingVertexIsLast;
|
||||
|
||||
Register<0x5F2, type::IndexBuffer> indexBuffer;
|
||||
|
||||
Register<0x61F, float> depthBiasClamp;
|
||||
|
||||
Register<0x620, std::array<u32, type::VertexBufferCount>> isVertexInputRatePerInstance; //!< A per-VBO boolean denoting if the vertex input rate should be per vertex or per instance
|
||||
|
Loading…
Reference in New Issue
Block a user