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 4f2bba66..e5b9dc81 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -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 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{}; diff --git a/app/src/main/cpp/skyline/gpu/quirk_manager.cpp b/app/src/main/cpp/skyline/gpu/quirk_manager.cpp index 5d291a2d..d46fb128 100644 --- a/app/src/main/cpp/skyline/gpu/quirk_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/quirk_manager.cpp @@ -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); } } diff --git a/app/src/main/cpp/skyline/gpu/quirk_manager.h b/app/src/main/cpp/skyline/gpu/quirk_manager.h index 58cc1ec1..1f27468d 100644 --- a/app/src/main/cpp/skyline/gpu/quirk_manager.h +++ b/app/src/main/cpp/skyline/gpu/quirk_manager.h @@ -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) diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h index a3e5e3ef..8dbcec4f 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h @@ -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) } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index 07fd071a..306207a1 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -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; } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index d2e60688..90031fe7 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -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> isVertexInputRatePerInstance; //!< A per-VBO boolean denoting if the vertex input rate should be per vertex or per instance