mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-23 11:59:15 +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:
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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); \
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user