Transition vertex input state to pipeline cache key

Also adds dirty tracking and removes it from direct state while we're at it. Since we no longer use Vulkan structs directly there's no benefit to it.
This commit is contained in:
Billy Laws 2022-09-06 18:16:25 +01:00
parent ffe24aa075
commit 3f9161fb74
3 changed files with 39 additions and 118 deletions

View File

@ -213,63 +213,23 @@ namespace skyline::gpu::interconnect::maxwell3d {
}
/* Vertex Input State */
// TODO: check if better individually
void VertexInputState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const {
ranges::for_each(vertexStreamRegisters, [&](const auto &regs) { manager.Bind(handle, regs.format, regs.frequency); });
ranges::for_each(vertexStreams, [&](const auto &regs) { manager.Bind(handle, regs.format, regs.frequency); });
auto bindFull{[&](const auto &regs) { manager.Bind(handle, regs); }};
ranges::for_each(vertexStreamInstanceRegisters, bindFull);
ranges::for_each(vertexAttributesRegisters, bindFull);
ranges::for_each(vertexStreamInstance, bindFull);
ranges::for_each(vertexAttributes, bindFull);
}
vk::StructureChain<vk::PipelineVertexInputStateCreateInfo, vk::PipelineVertexInputDivisorStateCreateInfoEXT> VertexInputState::Build(InterconnectContext &ctx, const EngineRegisters &engine) {
activeBindingDivisorDescs.clear();
activeAttributeDescs.clear();
VertexInputState::VertexInputState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine) : engine{manager, dirtyHandle, engine} {}
for (size_t i{}; i < engine::VertexStreamCount; i++) {
if (bindingDescs[i].inputRate == vk::VertexInputRate::eInstance) {
if (!ctx.gpu.traits.supportsVertexAttributeDivisor) [[unlikely]]
Logger::Warn("Vertex attribute divisor used on guest without host support");
else if (!ctx.gpu.traits.supportsVertexAttributeZeroDivisor && bindingDivisorDescs[i].divisor == 0) [[unlikely]]
Logger::Warn("Vertex attribute zero divisor used on guest without host support");
else
activeBindingDivisorDescs.push_back(bindingDivisorDescs[i]);
}
}
void VertexInputState::Flush(Key &key) {
for (u32 i{}; i < engine::VertexStreamCount; i++)
key.SetVertexBinding(i, engine->vertexStreams[i], engine->vertexStreamInstance[i]);
// TODO: check shader inputs
for (size_t i{}; i < engine::VertexAttributeCount; i++)
if (engine.vertexAttributesRegisters[i].source == engine::VertexAttribute::Source::Active)
activeAttributeDescs.push_back(attributeDescs[i]);
vk::StructureChain<vk::PipelineVertexInputStateCreateInfo, vk::PipelineVertexInputDivisorStateCreateInfoEXT> chain{
vk::PipelineVertexInputStateCreateInfo{
.vertexBindingDescriptionCount = static_cast<u32>(bindingDescs.size()),
.pVertexBindingDescriptions = bindingDescs.data(),
.vertexAttributeDescriptionCount = static_cast<u32>(activeAttributeDescs.size()),
.pVertexAttributeDescriptions = activeAttributeDescs.data(),
},
vk::PipelineVertexInputDivisorStateCreateInfoEXT{
.vertexBindingDivisorCount = static_cast<u32>(activeBindingDivisorDescs.size()),
.pVertexBindingDivisors = activeBindingDivisorDescs.data(),
},
};
if (activeBindingDivisorDescs.empty())
chain.unlink<vk::PipelineVertexInputDivisorStateCreateInfoEXT>();
return chain;
}
void VertexInputState::SetStride(u32 index, u32 stride) {
bindingDescs[index].stride = stride;
}
void VertexInputState::SetInputRate(u32 index, engine::VertexStreamInstance instance) {
bindingDescs[index].inputRate = instance.isInstanced ? vk::VertexInputRate::eInstance : vk::VertexInputRate::eVertex;
}
void VertexInputState::SetDivisor(u32 index, u32 divisor) {
bindingDivisorDescs[index].divisor = divisor;
for (u32 i{}; i < engine::VertexAttributeCount; i++)
key.vertexAttributes[i] = engine->vertexAttributes[i];
}
static vk::Format ConvertVertexInputAttributeFormat(engine::VertexAttribute::ComponentBitWidths componentBitWidths, engine::VertexAttribute::NumericalType numericalType) {
@ -355,20 +315,6 @@ namespace skyline::gpu::interconnect::maxwell3d {
}
}
void VertexInputState::SetAttribute(u32 index, engine::VertexAttribute attribute) {
auto &vkAttribute{attributeDescs[index]};
if (attribute.source == engine::VertexAttribute::Source::Active) {
vkAttribute.binding = attribute.stream;
vkAttribute.format = ConvertVertexInputAttributeFormat(attribute.componentBitWidths, attribute.numericalType);
vkAttribute.offset = attribute.offset;
// UpdateRuntimeInformation(runtimeInfo.generic_input_types[index], ConvertShaderGenericInputType(attribute.numericalType), maxwell3d::PipelineStage::Vertex);
} else {
// UpdateRuntimeInformation(runtimeInfo.generic_input_types[index], Shader::AttributeType::Disabled, maxwell3d::PipelineStage::Vertex);
}
}
/* Input Assembly State */
void InputAssemblyState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const {
manager.Bind(handle, primitiveRestartEnable);
@ -830,13 +776,12 @@ namespace skyline::gpu::interconnect::maxwell3d {
: engine{manager, dirtyHandle, engine},
colorRenderTargets{util::MergeInto<dirty::ManualDirtyState<ColorRenderTargetState>, engine::ColorTargetCount>(manager, engine.colorRenderTargetsRegisters, util::IncrementingT<size_t>{})},
depthRenderTarget{manager, engine.depthRenderTargetRegisters},
vertexInput{manager, engine.vertexInputRegisters},
rasterization{manager, engine.rasterizationRegisters},
depthStencil{manager, engine.depthStencilRegisters},
colorBlend{manager, engine.colorBlendRegisters} {}
void PipelineState::Flush(InterconnectContext &ctx, StateUpdateBuilder &builder) {
Key key;
boost::container::static_vector<TextureView *, engine::ColorTargetCount> colorAttachments;
for (auto &colorRenderTarget : colorRenderTargets)
if (auto view{colorRenderTarget.UpdateGet(ctx, key).view}; view)
@ -844,7 +789,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
TextureView *depthAttachment{depthRenderTarget.UpdateGet(ctx, key).view.get()};
auto vertexInputState{directState.vertexInput.Build(ctx, engine->vertexInputRegisters)};
vertexInput.Update(key);
const auto &inputAssemblyState{directState.inputAssembly.Build()};
const auto &tessellationState{directState.tessellation.Build()};
const auto &rasterizationState{rasterization.UpdateGet().rasterizationState};

View File

@ -14,7 +14,17 @@ namespace skyline::gpu::interconnect::maxwell3d {
u8 ztFormat : 5; // ZtFormat - 0xA as u8
};
struct VertexBinding {
u16 stride : 12;
bool instanced : 1;
bool enable : 1;
u8 _pad_ : 2;
u32 divisor;
};
static_assert(sizeof(VertexBinding) == 0x8);
std::array<u8, engine::ColorTargetCount> ctFormats; //!< ColorTarget::Format as u8
std::array<VertexBinding, engine::VertexStreamCount> vertexBindings;
public:
std::array<engine::VertexAttribute, engine::VertexAttributeCount> vertexAttributes;
@ -26,6 +36,13 @@ namespace skyline::gpu::interconnect::maxwell3d {
void SetZtFormat(engine::ZtFormat format) {
ztFormat = static_cast<u8>(format) - static_cast<u8>(engine::ZtFormat::ZF32);
}
void SetVertexBinding(u32 index, engine::VertexStream stream, engine::VertexStreamInstance instance) {
vertexBindings[index].stride = stream.format.stride;
vertexBindings[index].instanced = instance.isInstanced;
vertexBindings[index].enable = stream.format.enable;
vertexBindings[index].divisor = stream.frequency;
}
};
class ColorRenderTargetState : dirty::ManualDirty {
@ -73,39 +90,23 @@ namespace skyline::gpu::interconnect::maxwell3d {
void Flush(InterconnectContext &ctx, Key &key);
};
struct VertexInputState {
private:
std::array<vk::VertexInputBindingDescription, engine::VertexStreamCount> bindingDescs{
util::MergeInto<vk::VertexInputBindingDescription, engine::VertexStreamCount>(util::IncrementingT<u32>{})
};
std::array<vk::VertexInputBindingDivisorDescriptionEXT, engine::VertexStreamCount> bindingDivisorDescs{
util::MergeInto<vk::VertexInputBindingDivisorDescriptionEXT, engine::VertexStreamCount>(util::IncrementingT<u32>{})
};
std::array<vk::VertexInputAttributeDescription, engine::VertexAttributeCount> attributeDescs{
util::MergeInto<vk::VertexInputAttributeDescription, engine::VertexAttributeCount>(util::IncrementingT<u32>{})
};
boost::container::static_vector<vk::VertexInputBindingDivisorDescriptionEXT, engine::VertexStreamCount> activeBindingDivisorDescs;
boost::container::static_vector<vk::VertexInputAttributeDescription, engine::VertexAttributeCount> activeAttributeDescs;
class VertexInputState : dirty::ManualDirty {
public:
struct EngineRegisters {
const std::array<engine::VertexStream, engine::VertexStreamCount> &vertexStreamRegisters;
const std::array<engine::VertexStreamInstance, engine::VertexStreamCount> &vertexStreamInstanceRegisters;
const std::array<engine::VertexAttribute, engine::VertexAttributeCount> &vertexAttributesRegisters;
const std::array<engine::VertexStream, engine::VertexStreamCount> &vertexStreams;
const std::array<engine::VertexStreamInstance, engine::VertexStreamCount> &vertexStreamInstance;
const std::array<engine::VertexAttribute, engine::VertexAttributeCount> &vertexAttributes;
void DirtyBind(DirtyManager &manager, dirty::Handle handle) const;
};
vk::StructureChain<vk::PipelineVertexInputStateCreateInfo, vk::PipelineVertexInputDivisorStateCreateInfoEXT> Build(InterconnectContext &ctx, const EngineRegisters &engine);
private:
dirty::BoundSubresource<EngineRegisters> engine;
void SetStride(u32 index, u32 stride);
public:
VertexInputState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine);
void SetInputRate(u32 index, engine::VertexStreamInstance instance);
void SetDivisor(u32 index, u32 divisor);
void SetAttribute(u32 index, engine::VertexAttribute attribute);
void Flush(Key &key);
};
struct InputAssemblyState {
@ -158,7 +159,6 @@ namespace skyline::gpu::interconnect::maxwell3d {
* @brief Holds pipeline state that is directly written by the engine code, without using dirty tracking
*/
struct DirectPipelineState {
VertexInputState vertexInput;
InputAssemblyState inputAssembly;
TessellationState tessellation;
};
@ -269,6 +269,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
std::array<dirty::ManualDirtyState<ColorRenderTargetState>, engine::ColorTargetCount> colorRenderTargets;
dirty::ManualDirtyState<DepthRenderTargetState> depthRenderTarget;
dirty::ManualDirtyState<VertexInputState> vertexInput;
dirty::ManualDirtyState<RasterizationState> rasterization;
dirty::ManualDirtyState<DepthStencilState> depthStencil;
dirty::ManualDirtyState<ColorBlendState> colorBlend;

View File

@ -153,31 +153,6 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
dirtyManager.MarkDirty(method);
switch (method) {
#define VERTEX_STREAM_CALLBACKS(z, idx, data) \
ENGINE_ARRAY_STRUCT_CASE(vertexStreams, idx, format, { \
interconnect.directState.vertexInput.SetStride(idx, format.stride); \
}) \
ENGINE_ARRAY_STRUCT_CASE(vertexStreams, idx, frequency, { \
interconnect.directState.vertexInput.SetDivisor(idx, frequency); \
}) \
ENGINE_ARRAY_CASE(vertexStreamInstance, idx, { \
interconnect.directState.vertexInput.SetInputRate(idx, vertexStreamInstance); \
})
BOOST_PP_REPEAT(16, VERTEX_STREAM_CALLBACKS, 0)
static_assert(type::VertexStreamCount == 16 && type::VertexStreamCount < BOOST_PP_LIMIT_REPEAT);
#undef VERTEX_STREAM_CALLBACKS
#define VERTEX_ATTRIBUTE_CALLBACKS(z, idx, data) \
ENGINE_ARRAY_CASE(vertexAttributes, idx, { \
interconnect.directState.vertexInput.SetAttribute(idx, vertexAttributes); \
})
BOOST_PP_REPEAT(16, VERTEX_ATTRIBUTE_CALLBACKS, 0)
static_assert(type::VertexAttributeCount == 32 && type::VertexAttributeCount < BOOST_PP_LIMIT_REPEAT);
#undef VERTEX_ATTRIBUTE_CALLBACKS
ENGINE_CASE(primitiveRestartEnable, {
interconnect.directState.inputAssembly.SetPrimitiveRestart(primitiveRestartEnable != 0);