mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-26 20:54:17 +01:00
Implement Maxwell3D Vertex Attributes
Translates all Maxwell3D vertex attributes to Vulkan with the exception of `isConstant` which causes the vertex attribute to return a constant value `(0,0,0,X)` which was trivial in OpenGL with `glDisableVertexAttribArray` and `glVertexAttrib4(..., 0, 0, 0, 1)` but we don't have access to this in Vulkan and might need to depend on undefined behavior or manually emulate it in a shader. This'll be revisited in the future after checking host GPU behavior.
This commit is contained in:
parent
4b9f99bb27
commit
138f884159
@ -55,6 +55,10 @@ namespace skyline::gpu::interconnect {
|
||||
vertexState.unlink<vk::PipelineVertexInputDivisorStateCreateInfoEXT>();
|
||||
}
|
||||
|
||||
u32 attributeIndex{};
|
||||
for (auto &vertexAttribute : vertexAttributes)
|
||||
vertexAttribute.location = attributeIndex++;
|
||||
|
||||
if (!gpu.quirks.supportsLastProvokingVertex)
|
||||
rasterizerState.unlink<vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT>();
|
||||
}
|
||||
@ -772,10 +776,13 @@ namespace skyline::gpu::interconnect {
|
||||
std::array<VertexBuffer, maxwell3d::VertexBufferCount> vertexBuffers{};
|
||||
std::array<vk::VertexInputBindingDescription, maxwell3d::VertexBufferCount> vertexBindings{};
|
||||
std::array<vk::VertexInputBindingDivisorDescriptionEXT, maxwell3d::VertexBufferCount> vertexBindingDivisors{};
|
||||
std::array<vk::VertexInputAttributeDescription, maxwell3d::VertexAttributeCount> vertexAttributes{};
|
||||
vk::StructureChain<vk::PipelineVertexInputStateCreateInfo, vk::PipelineVertexInputDivisorStateCreateInfoEXT> vertexState{
|
||||
vk::PipelineVertexInputStateCreateInfo{
|
||||
.pVertexBindingDescriptions = vertexBindings.data(),
|
||||
.vertexBindingDescriptionCount = maxwell3d::VertexBufferCount,
|
||||
.pVertexAttributeDescriptions = vertexAttributes.data(),
|
||||
.vertexAttributeDescriptionCount = maxwell3d::VertexAttributeCount,
|
||||
}, vk::PipelineVertexInputDivisorStateCreateInfoEXT{
|
||||
.pVertexBindingDivisors = vertexBindingDivisors.data(),
|
||||
.vertexBindingDivisorCount = maxwell3d::VertexBufferCount,
|
||||
@ -814,5 +821,124 @@ namespace skyline::gpu::interconnect {
|
||||
Logger::Warn("Cannot set vertex attribute divisor to zero without host GPU support");
|
||||
vertexBindingDivisors[index].divisor = divisor;
|
||||
}
|
||||
|
||||
vk::Format ConvertVertexBufferFormat(maxwell3d::VertexAttribute::ElementType type, maxwell3d::VertexAttribute::ElementSize size) {
|
||||
using Size = maxwell3d::VertexAttribute::ElementSize;
|
||||
using Type = maxwell3d::VertexAttribute::ElementType;
|
||||
|
||||
if (size == Size::e0 || type == Type::None)
|
||||
return vk::Format::eUndefined;
|
||||
|
||||
switch(size | type) {
|
||||
// @fmt:off
|
||||
|
||||
/* 8-bit components */
|
||||
|
||||
case Size::e1x8 | Type::Unorm: return vk::Format::eR8Unorm;
|
||||
case Size::e1x8 | Type::Snorm: return vk::Format::eR8Snorm;
|
||||
case Size::e1x8 | Type::Uint: return vk::Format::eR8Uint;
|
||||
case Size::e1x8 | Type::Sint: return vk::Format::eR8Sint;
|
||||
case Size::e1x8 | Type::Uscaled: return vk::Format::eR8Uscaled;
|
||||
case Size::e1x8 | Type::Sscaled: return vk::Format::eR8Sscaled;
|
||||
|
||||
case Size::e2x8 | Type::Unorm: return vk::Format::eR8G8Unorm;
|
||||
case Size::e2x8 | Type::Snorm: return vk::Format::eR8G8Snorm;
|
||||
case Size::e2x8 | Type::Uint: return vk::Format::eR8G8Uint;
|
||||
case Size::e2x8 | Type::Sint: return vk::Format::eR8G8Sint;
|
||||
case Size::e2x8 | Type::Uscaled: return vk::Format::eR8G8Uscaled;
|
||||
case Size::e2x8 | Type::Sscaled: return vk::Format::eR8G8Sscaled;
|
||||
|
||||
case Size::e3x8 | Type::Unorm: return vk::Format::eR8G8B8Unorm;
|
||||
case Size::e3x8 | Type::Snorm: return vk::Format::eR8G8B8Snorm;
|
||||
case Size::e3x8 | Type::Uint: return vk::Format::eR8G8B8Uint;
|
||||
case Size::e3x8 | Type::Sint: return vk::Format::eR8G8B8Sint;
|
||||
case Size::e3x8 | Type::Uscaled: return vk::Format::eR8G8B8Uscaled;
|
||||
case Size::e3x8 | Type::Sscaled: return vk::Format::eR8G8B8Sscaled;
|
||||
|
||||
case Size::e4x8 | Type::Unorm: return vk::Format::eR8G8B8A8Unorm;
|
||||
case Size::e4x8 | Type::Snorm: return vk::Format::eR8G8B8A8Snorm;
|
||||
case Size::e4x8 | Type::Uint: return vk::Format::eR8G8B8A8Uint;
|
||||
case Size::e4x8 | Type::Sint: return vk::Format::eR8G8B8A8Sint;
|
||||
case Size::e4x8 | Type::Uscaled: return vk::Format::eR8G8B8A8Uscaled;
|
||||
case Size::e4x8 | Type::Sscaled: return vk::Format::eR8G8B8A8Sscaled;
|
||||
|
||||
/* 16-bit components */
|
||||
|
||||
case Size::e1x16 | Type::Unorm: return vk::Format::eR16Unorm;
|
||||
case Size::e1x16 | Type::Snorm: return vk::Format::eR16Snorm;
|
||||
case Size::e1x16 | Type::Uint: return vk::Format::eR16Uint;
|
||||
case Size::e1x16 | Type::Sint: return vk::Format::eR16Sint;
|
||||
case Size::e1x16 | Type::Uscaled: return vk::Format::eR16Uscaled;
|
||||
case Size::e1x16 | Type::Sscaled: return vk::Format::eR16Sscaled;
|
||||
case Size::e1x16 | Type::Float: return vk::Format::eR16Sfloat;
|
||||
|
||||
case Size::e2x16 | Type::Unorm: return vk::Format::eR16G16Unorm;
|
||||
case Size::e2x16 | Type::Snorm: return vk::Format::eR16G16Snorm;
|
||||
case Size::e2x16 | Type::Uint: return vk::Format::eR16G16Uint;
|
||||
case Size::e2x16 | Type::Sint: return vk::Format::eR16G16Sint;
|
||||
case Size::e2x16 | Type::Uscaled: return vk::Format::eR16G16Uscaled;
|
||||
case Size::e2x16 | Type::Sscaled: return vk::Format::eR16G16Sscaled;
|
||||
case Size::e2x16 | Type::Float: return vk::Format::eR16G16Sfloat;
|
||||
|
||||
case Size::e3x16 | Type::Unorm: return vk::Format::eR16G16B16Unorm;
|
||||
case Size::e3x16 | Type::Snorm: return vk::Format::eR16G16B16Snorm;
|
||||
case Size::e3x16 | Type::Uint: return vk::Format::eR16G16B16Uint;
|
||||
case Size::e3x16 | Type::Sint: return vk::Format::eR16G16B16Sint;
|
||||
case Size::e3x16 | Type::Uscaled: return vk::Format::eR16G16B16Uscaled;
|
||||
case Size::e3x16 | Type::Sscaled: return vk::Format::eR16G16B16Sscaled;
|
||||
case Size::e3x16 | Type::Float: return vk::Format::eR16G16B16Sfloat;
|
||||
|
||||
case Size::e4x16 | Type::Unorm: return vk::Format::eR16G16B16A16Unorm;
|
||||
case Size::e4x16 | Type::Snorm: return vk::Format::eR16G16B16A16Snorm;
|
||||
case Size::e4x16 | Type::Uint: return vk::Format::eR16G16B16A16Uint;
|
||||
case Size::e4x16 | Type::Sint: return vk::Format::eR16G16B16A16Sint;
|
||||
case Size::e4x16 | Type::Uscaled: return vk::Format::eR16G16B16A16Uscaled;
|
||||
case Size::e4x16 | Type::Sscaled: return vk::Format::eR16G16B16A16Sscaled;
|
||||
case Size::e4x16 | Type::Float: return vk::Format::eR16G16B16A16Sfloat;
|
||||
|
||||
/* 32-bit components */
|
||||
|
||||
case Size::e1x32 | Type::Uint: return vk::Format::eR32Uint;
|
||||
case Size::e1x32 | Type::Sint: return vk::Format::eR32Sint;
|
||||
case Size::e1x32 | Type::Float: return vk::Format::eR32Sfloat;
|
||||
|
||||
case Size::e2x32 | Type::Uint: return vk::Format::eR32G32Uint;
|
||||
case Size::e2x32 | Type::Sint: return vk::Format::eR32G32Sint;
|
||||
case Size::e2x32 | Type::Float: return vk::Format::eR32G32Sfloat;
|
||||
|
||||
case Size::e3x32 | Type::Uint: return vk::Format::eR32G32B32Uint;
|
||||
case Size::e3x32 | Type::Sint: return vk::Format::eR32G32B32Sint;
|
||||
case Size::e3x32 | Type::Float: return vk::Format::eR32G32B32Sfloat;
|
||||
|
||||
case Size::e4x32 | Type::Uint: return vk::Format::eR32G32B32A32Uint;
|
||||
case Size::e4x32 | Type::Sint: return vk::Format::eR32G32B32A32Sint;
|
||||
case Size::e4x32 | Type::Float: return vk::Format::eR32G32B32A32Sfloat;
|
||||
|
||||
/* 10-bit RGB, 2-bit A */
|
||||
|
||||
case Size::e10_10_10_2 | Type::Unorm: return vk::Format::eA2R10G10B10UnormPack32;
|
||||
case Size::e10_10_10_2 | Type::Snorm: return vk::Format::eA2R10G10B10SnormPack32;
|
||||
case Size::e10_10_10_2 | Type::Uint: return vk::Format::eA2R10G10B10UintPack32;
|
||||
case Size::e10_10_10_2 | Type::Sint: return vk::Format::eA2R10G10B10SintPack32;
|
||||
case Size::e10_10_10_2 | Type::Uscaled: return vk::Format::eA2R10G10B10UscaledPack32;
|
||||
case Size::e10_10_10_2 | Type::Sscaled: return vk::Format::eA2R10G10B10SscaledPack32;
|
||||
|
||||
/* Unknown */
|
||||
|
||||
case 0x12F: return vk::Format::eUndefined; // Issued by Maxwell3D::InitializeRegisters()
|
||||
|
||||
// @fmt:on
|
||||
|
||||
default:
|
||||
throw exception("Unimplemented Vertex Buffer Format: {} | {}", maxwell3d::VertexAttribute::ToString(size), maxwell3d::VertexAttribute::ToString(type));
|
||||
}
|
||||
}
|
||||
|
||||
void SetVertexAttributeState(u32 index, maxwell3d::VertexAttribute attribute) {
|
||||
auto& vkAttributes{vertexAttributes[index]};
|
||||
vkAttributes.binding = attribute.bufferId;
|
||||
vkAttributes.format = ConvertVertexBufferFormat(attribute.type, attribute.elementSize);
|
||||
vkAttributes.offset = attribute.offset;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -201,51 +201,85 @@ 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
|
||||
constexpr static size_t VertexAttributeCount{32}; //!< The amount of vertex attributes that can be set
|
||||
|
||||
union VertexAttribute {
|
||||
u32 raw;
|
||||
|
||||
enum class Size : u8 {
|
||||
Size_1x32 = 0x12,
|
||||
Size_2x32 = 0x04,
|
||||
Size_3x32 = 0x02,
|
||||
Size_4x32 = 0x01,
|
||||
Size_1x16 = 0x1B,
|
||||
Size_2x16 = 0x0F,
|
||||
Size_3x16 = 0x05,
|
||||
Size_4x16 = 0x03,
|
||||
Size_1x8 = 0x1D,
|
||||
Size_2x8 = 0x18,
|
||||
Size_3x8 = 0x13,
|
||||
Size_4x8 = 0x0A,
|
||||
Size_10_10_10_2 = 0x30,
|
||||
Size_11_11_10 = 0x31,
|
||||
enum class ElementSize : u16 {
|
||||
e0 = 0x0,
|
||||
e1x8 = 0x1D,
|
||||
e2x8 = 0x18,
|
||||
e3x8 = 0x13,
|
||||
e4x8 = 0x0A,
|
||||
e1x16 = 0x1B,
|
||||
e2x16 = 0x0F,
|
||||
e3x16 = 0x05,
|
||||
e4x16 = 0x03,
|
||||
e1x32 = 0x12,
|
||||
e2x32 = 0x04,
|
||||
e3x32 = 0x02,
|
||||
e4x32 = 0x01,
|
||||
e10_10_10_2 = 0x30,
|
||||
e11_11_10 = 0x31,
|
||||
};
|
||||
|
||||
enum class Type : u8 {
|
||||
ENUM_STRING(ElementSize, {
|
||||
ENUM_CASE_PAIR(e1x8, "1x8");
|
||||
ENUM_CASE_PAIR(e2x8, "2x8");
|
||||
ENUM_CASE_PAIR(e3x8, "3x8");
|
||||
ENUM_CASE_PAIR(e4x8, "4x8");
|
||||
ENUM_CASE_PAIR(e1x16, "1x16");
|
||||
ENUM_CASE_PAIR(e2x16, "2x16");
|
||||
ENUM_CASE_PAIR(e3x16, "3x16");
|
||||
ENUM_CASE_PAIR(e4x16, "4x16");
|
||||
ENUM_CASE_PAIR(e1x32, "1x32");
|
||||
ENUM_CASE_PAIR(e2x32, "2x32");
|
||||
ENUM_CASE_PAIR(e3x32, "3x32");
|
||||
ENUM_CASE_PAIR(e4x32, "4x32");
|
||||
ENUM_CASE_PAIR(e10_10_10_2, "10_10_10_2");
|
||||
ENUM_CASE_PAIR(e11_11_10, "11_11_10");
|
||||
})
|
||||
|
||||
enum class ElementType : u16 {
|
||||
None = 0,
|
||||
SNorm = 1,
|
||||
UNorm = 2,
|
||||
SInt = 3,
|
||||
UInt = 4,
|
||||
UScaled = 5,
|
||||
SScaled = 6,
|
||||
Snorm = 1,
|
||||
Unorm = 2,
|
||||
Sint = 3,
|
||||
Uint = 4,
|
||||
Uscaled = 5,
|
||||
Sscaled = 6,
|
||||
Float = 7,
|
||||
};
|
||||
|
||||
ENUM_STRING(ElementType, {
|
||||
ENUM_CASE(None);
|
||||
ENUM_CASE(Snorm);
|
||||
ENUM_CASE(Unorm);
|
||||
ENUM_CASE(Sint);
|
||||
ENUM_CASE(Uint);
|
||||
ENUM_CASE(Uscaled);
|
||||
ENUM_CASE(Sscaled);
|
||||
ENUM_CASE(Float);
|
||||
})
|
||||
|
||||
struct {
|
||||
u8 bufferId : 5;
|
||||
u8 _pad0_ : 1;
|
||||
bool fixed : 1;
|
||||
bool isConstant : 1;
|
||||
u16 offset : 14;
|
||||
Size size : 6;
|
||||
Type type : 3;
|
||||
ElementSize elementSize : 6;
|
||||
ElementType type : 3;
|
||||
u8 _pad1_ : 1;
|
||||
bool bgra : 1;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(VertexAttribute) == sizeof(u32));
|
||||
|
||||
constexpr u16 operator|(VertexAttribute::ElementSize elementSize, VertexAttribute::ElementType type) {
|
||||
return static_cast<u16>(static_cast<u16>(elementSize) | (static_cast<u16>(type) << 6));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A descriptor that controls how the RenderTarget array (at 0x200) will be interpreted
|
||||
*/
|
||||
|
@ -351,6 +351,15 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
|
||||
static_assert(type::VertexBufferCount == 16 && type::VertexBufferCount < BOOST_PP_LIMIT_REPEAT);
|
||||
#undef VERTEX_BUFFER_CALLBACKS
|
||||
|
||||
#define VERTEX_ATTRIBUTES_CALLBACKS(z, index, data) \
|
||||
MAXWELL3D_ARRAY_CASE(vertexAttributeState, index, { \
|
||||
context.SetVertexAttributeState(index, vertexAttributeState); \
|
||||
})
|
||||
|
||||
BOOST_PP_REPEAT(32, VERTEX_ATTRIBUTES_CALLBACKS, 0)
|
||||
static_assert(type::VertexAttributeCount == 32 && type::VertexAttributeCount < 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); \
|
||||
|
@ -106,7 +106,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
|
||||
|
||||
Register<0x3E4, u32> commonColorWriteMask; //!< If enabled, the color write masks for all RTs must be set to that of the first RT
|
||||
Register<0x3EB, u32> rtSeparateFragData;
|
||||
Register<0x458, std::array<type::VertexAttribute, 0x20>> vertexAttributeState;
|
||||
Register<0x458, std::array<type::VertexAttribute, type::VertexAttributeCount>> vertexAttributeState;
|
||||
Register<0x487, type::RenderTargetControl> renderTargetControl;
|
||||
Register<0x4B9, u32> independentBlendEnable;
|
||||
Register<0x4BB, u32> alphaTestEnable;
|
||||
|
Loading…
Reference in New Issue
Block a user