Implement Maxwell3D Vertex Buffer Bindings

This implements everything in Maxwell3D vertex buffer bindings including vertex attribute divisors which require the extension `VK_EXT_vertex_attribute_divisor` to emulate them correctly, this has been implemented in the form of of a quirk. It is dynamically enabled/disabled based on if the host GPU supports it and a warning is provided when it is used by the guest but the host GPU doesn't support it.
This commit is contained in:
PixelyIon 2021-11-16 10:32:01 +05:30
parent d163e4ffa6
commit ff5515d4d1
6 changed files with 83 additions and 1 deletions

View File

@ -43,6 +43,18 @@ namespace skyline::gpu::interconnect {
public: public:
GraphicsContext(GPU &gpu, soc::gm20b::ChannelContext &channelCtx, gpu::interconnect::CommandExecutor &executor) : gpu(gpu), channelCtx(channelCtx), executor(executor) { GraphicsContext(GPU &gpu, soc::gm20b::ChannelContext &channelCtx, gpu::interconnect::CommandExecutor &executor) : gpu(gpu), channelCtx(channelCtx), executor(executor) {
scissors.fill(DefaultScissor); scissors.fill(DefaultScissor);
u32 bindingIndex{};
for (auto &vertexBinding : vertexBindings)
vertexBinding.binding = bindingIndex++;
if (gpu.quirks.supportsVertexAttributeDivisor) {
bindingIndex = 0;
for (auto &vertexBindingDivisor : vertexBindingDivisors)
vertexBindingDivisor.binding = bindingIndex++;
} else {
vertexState.unlink<vk::PipelineVertexInputDivisorStateCreateInfoEXT>();
}
if (!gpu.quirks.supportsLastProvokingVertex) if (!gpu.quirks.supportsLastProvokingVertex)
rasterizerState.unlink<vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT>(); rasterizerState.unlink<vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT>();
} }
@ -751,5 +763,39 @@ namespace skyline::gpu::interconnect {
void SetColorBlendConstant(u32 index, float constant) { void SetColorBlendConstant(u32 index, float constant) {
blendState.blendConstants[index] = constant; blendState.blendConstants[index] = constant;
} }
/* Vertex Buffers */
private:
std::array<IOVA, maxwell3d::VertexBufferCount> vertexBindingIovas{};
std::array<vk::VertexInputBindingDescription, maxwell3d::VertexBufferCount> vertexBindings{};
std::array<vk::VertexInputBindingDivisorDescriptionEXT, maxwell3d::VertexBufferCount> vertexBindingDivisors{};
vk::StructureChain<vk::PipelineVertexInputStateCreateInfo, vk::PipelineVertexInputDivisorStateCreateInfoEXT> vertexState{
vk::PipelineVertexInputStateCreateInfo{
.pVertexBindingDescriptions = vertexBindings.data(),
.vertexBindingDescriptionCount = maxwell3d::VertexBufferCount,
}, vk::PipelineVertexInputDivisorStateCreateInfoEXT{
.pVertexBindingDivisors = vertexBindingDivisors.data(),
.vertexBindingDivisorCount = maxwell3d::VertexBufferCount,
}
};
public:
void SetVertexBufferStride(u32 index, u32 stride) {
vertexBindings[index].stride = stride;
}
void SetVertexBufferIovaHigh(u32 index, u32 high) {
vertexBindingIovas[index].high = high;
}
void SetVertexBufferIovaLow(u32 index, u32 low) {
vertexBindingIovas[index].low = low;
}
void SetVertexBufferDivisor(u32 index, u32 divisor) {
if (!gpu.quirks.supportsVertexAttributeDivisor)
Logger::Warn("Cannot set vertex attribute divisor without host GPU support");
vertexBindingDivisors[index].divisor = divisor;
}
}; };
} }

View File

@ -25,6 +25,7 @@ namespace skyline {
auto extensionVersion{extension.specVersion}; auto extensionVersion{extension.specVersion};
switch (util::Hash(extensionName)) { switch (util::Hash(extensionName)) {
EXT_SET("VK_EXT_provoking_vertex", supportsLastProvokingVertex); EXT_SET("VK_EXT_provoking_vertex", supportsLastProvokingVertex);
EXT_SET("VK_EXT_vertex_attribute_divisor", supportsVertexAttributeDivisor);
} }
#undef EXT_SET #undef EXT_SET
@ -43,6 +44,6 @@ namespace skyline {
} }
std::string QuirkManager::Summary() { std::string QuirkManager::Summary() {
return fmt::format("\n* Supports Last Provoking Vertex: {}\n* Supports Logical Operations: {}", supportsLastProvokingVertex, supportsLogicOp); return fmt::format("\n* Supports Last Provoking Vertex: {}\n* Supports Logical Operations: {}\n* Supports Vertex Attribute Divisor: {}", supportsLastProvokingVertex, supportsLogicOp, supportsVertexAttributeDivisor);
} }
} }

View File

@ -14,6 +14,7 @@ namespace skyline {
public: public:
bool supportsLastProvokingVertex{}; //!< If the device supports setting the last vertex as the provoking vertex (with VK_EXT_provoking_vertex) 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 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)
QuirkManager() = default; QuirkManager() = default;

View File

@ -200,6 +200,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
}; };
static_assert(sizeof(Scissor) == (0x4 * sizeof(u32))); static_assert(sizeof(Scissor) == (0x4 * sizeof(u32)));
constexpr static size_t VertexBufferCount{16}; //!< The maximum amount of vertex buffers that can be bound at once
union VertexAttribute { union VertexAttribute {
u32 raw; u32 raw;

View File

@ -324,6 +324,24 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
context.SetBlendLogicOpType(type); context.SetBlendLogicOpType(type);
}) })
#define VERTEX_BUFFER_CALLBACKS(z, index, data) \
MAXWELL3D_ARRAY_STRUCT_CASE(vertexBuffers, index, config, { \
context.SetVertexBufferStride(index, config.stride); \
}) \
MAXWELL3D_ARRAY_STRUCT_STRUCT_CASE(vertexBuffers, index, iova, high, { \
context.SetVertexBufferIovaHigh(index, high); \
}) \
MAXWELL3D_ARRAY_STRUCT_STRUCT_CASE(vertexBuffers, index, iova, low, { \
context.SetVertexBufferIovaLow(index, low); \
}) \
MAXWELL3D_ARRAY_STRUCT_CASE(vertexBuffers, index, divisor, { \
context.SetVertexBufferDivisor(index, divisor); \
})
BOOST_PP_REPEAT(16, VERTEX_BUFFER_CALLBACKS, 0)
static_assert(type::VertexBufferCount == 16 && type::VertexBufferCount < BOOST_PP_LIMIT_REPEAT);
#undef VERTEX_BUFFER_CALLBACKS
#define SET_INDEPENDENT_COLOR_BLEND_CALLBACKS(z, index, data) \ #define SET_INDEPENDENT_COLOR_BLEND_CALLBACKS(z, index, data) \
MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, colorOp, { \ MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, colorOp, { \
context.SetColorBlendOp(index, colorOp); \ context.SetColorBlendOp(index, colorOp); \

View File

@ -229,6 +229,20 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
}; };
Register<0x671, ColorLogicOp> colorLogicOp; Register<0x671, ColorLogicOp> colorLogicOp;
struct VertexBuffer {
union {
u32 raw;
struct {
u32 stride : 12;
u32 enable : 1;
};
} config;
type::Address iova;
u32 divisor;
};
static_assert(sizeof(VertexBuffer) == sizeof(u32) * 4);
Register<0x700, std::array<VertexBuffer, type::VertexBufferCount>> vertexBuffers;
struct IndependentBlend { struct IndependentBlend {
u32 seperateAlpha; u32 seperateAlpha;
type::BlendOp colorOp; type::BlendOp colorOp;