mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 12:21:51 +01:00
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:
parent
d163e4ffa6
commit
ff5515d4d1
@ -43,6 +43,18 @@ namespace skyline::gpu::interconnect {
|
||||
public:
|
||||
GraphicsContext(GPU &gpu, soc::gm20b::ChannelContext &channelCtx, gpu::interconnect::CommandExecutor &executor) : gpu(gpu), channelCtx(channelCtx), executor(executor) {
|
||||
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)
|
||||
rasterizerState.unlink<vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT>();
|
||||
}
|
||||
@ -751,5 +763,39 @@ namespace skyline::gpu::interconnect {
|
||||
void SetColorBlendConstant(u32 index, float 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace skyline {
|
||||
auto extensionVersion{extension.specVersion};
|
||||
switch (util::Hash(extensionName)) {
|
||||
EXT_SET("VK_EXT_provoking_vertex", supportsLastProvokingVertex);
|
||||
EXT_SET("VK_EXT_vertex_attribute_divisor", supportsVertexAttributeDivisor);
|
||||
}
|
||||
|
||||
#undef EXT_SET
|
||||
@ -43,6 +44,6 @@ namespace skyline {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace skyline {
|
||||
public:
|
||||
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)
|
||||
|
||||
QuirkManager() = default;
|
||||
|
||||
|
@ -200,6 +200,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
|
||||
};
|
||||
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 {
|
||||
u32 raw;
|
||||
|
||||
|
@ -324,6 +324,24 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
|
||||
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) \
|
||||
MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, colorOp, { \
|
||||
context.SetColorBlendOp(index, colorOp); \
|
||||
|
@ -229,6 +229,20 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
|
||||
};
|
||||
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 {
|
||||
u32 seperateAlpha;
|
||||
type::BlendOp colorOp;
|
||||
|
Loading…
Reference in New Issue
Block a user