Keep track of transform feedback varyings pipeline state

This commit is contained in:
Billy Laws 2022-10-09 13:48:05 +01:00
parent 7ad2d94345
commit c86ad638c4
5 changed files with 106 additions and 9 deletions

View File

@ -300,6 +300,37 @@ namespace skyline::gpu::interconnect::maxwell3d {
.blendEnable = state.blendEnable .blendEnable = state.blendEnable
}; };
} }
void PackedPipelineState::SetTransformFeedbackVaryings(const engine::StreamOutControl &control, const std::array<u8, engine::StreamOutLayoutSelectAttributeCount> &layoutSelect, size_t buffer) {
for (size_t i{}; i < control.componentCount; i++) {
// TODO: We could merge multiple component accesses from the same attribute into one varying as yuzu does
u8 attributeIndex{layoutSelect[i]};
if (control.strideBytes > std::numeric_limits<u16>::max())
throw exception("Stride too large: {}", control.strideBytes);
transformFeedbackVaryings[attributeIndex] = {
.buffer = static_cast<u8>(buffer),
.offsetWords = static_cast<u8>(i),
.stride = static_cast<u16>(control.strideBytes)
};
}
}
std::vector<Shader::TransformFeedbackVarying> PackedPipelineState::GetTransformFeedbackVaryings() const {
std::vector<Shader::TransformFeedbackVarying> convertedVaryings;
convertedVaryings.reserve(0x100);
for (const auto &varying : transformFeedbackVaryings)
convertedVaryings.push_back(
{
.buffer = varying.buffer,
.stride = varying.stride,
.offset = varying.offsetWords * 4U,
.components = 1,
});
return convertedVaryings;
}
} }
#pragma clang diagnostic pop #pragma clang diagnostic pop

View File

@ -3,8 +3,9 @@
#pragma once #pragma once
#include "common.h"
#include <tuple> #include <tuple>
#include <shader_compiler/runtime_info.h>
#include "common.h"
namespace skyline::gpu::interconnect::maxwell3d { namespace skyline::gpu::interconnect::maxwell3d {
#pragma clang diagnostic push #pragma clang diagnostic push
@ -53,6 +54,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
u8 bindlessTextureConstantBufferSlotSelect : 5; u8 bindlessTextureConstantBufferSlotSelect : 5;
bool apiMandatedEarlyZ : 1; bool apiMandatedEarlyZ : 1;
bool openGlNdc : 1; bool openGlNdc : 1;
bool transformFeedbackEnable : 1;
}; };
u32 patchSize; u32 patchSize;
@ -89,6 +91,13 @@ namespace skyline::gpu::interconnect::maxwell3d {
std::array<AttachmentBlendState, engine::ColorTargetCount> attachmentBlendStates; std::array<AttachmentBlendState, engine::ColorTargetCount> attachmentBlendStates;
struct TransformFeedbackVarying {
u16 stride;
u8 offsetWords;
u8 buffer;
};
std::array<TransformFeedbackVarying, 0x100> transformFeedbackVaryings{};
void SetColorRenderTargetFormat(size_t index, engine::ColorTarget::Format format); void SetColorRenderTargetFormat(size_t index, engine::ColorTarget::Format format);
void SetDepthRenderTargetFormat(engine::ZtFormat format); void SetDepthRenderTargetFormat(engine::ZtFormat format);
@ -121,8 +130,26 @@ namespace skyline::gpu::interconnect::maxwell3d {
vk::PipelineColorBlendAttachmentState GetAttachmentBlendState(u32 index) const; vk::PipelineColorBlendAttachmentState GetAttachmentBlendState(u32 index) const;
void SetTransformFeedbackVaryings(const engine::StreamOutControl &control, const std::array<u8, engine::StreamOutLayoutSelectAttributeCount> &layoutSelect, size_t buffer);
std::vector<Shader::TransformFeedbackVarying> GetTransformFeedbackVaryings() const;
bool operator==(const PackedPipelineState &other) const { bool operator==(const PackedPipelineState &other) const {
// Only hash transform feedback state if it's enabled
if (other.transformFeedbackEnable && transformFeedbackEnable)
return std::memcmp(this, &other, sizeof(PackedPipelineState)) == 0; return std::memcmp(this, &other, sizeof(PackedPipelineState)) == 0;
else
return std::memcmp(this, &other, offsetof(PackedPipelineState, transformFeedbackVaryings)) == 0;
}
};
struct PackedPipelineStateHash {
size_t operator()(const PackedPipelineState &state) const noexcept {
// Only hash transform feedback state if it's enabled
if (state.transformFeedbackEnable)
return XXH64(&state, sizeof(PackedPipelineState), 0);
return XXH64(&state, offsetof(PackedPipelineState, transformFeedbackVaryings), 0);
} }
}; };

View File

@ -107,15 +107,14 @@ namespace skyline::gpu::interconnect::maxwell3d {
if (packedState.topology == engine::DrawTopology::Points) if (packedState.topology == engine::DrawTopology::Points)
info.fixed_state_point_size = packedState.pointSize; info.fixed_state_point_size = packedState.pointSize;
//if (key.state.xfb_enabled) if (packedState.transformFeedbackEnable)
//info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); info.xfb_varyings = packedState.GetTransformFeedbackVaryings();
//}
info.convert_depth_mode = packedState.openGlNdc; info.convert_depth_mode = packedState.openGlNdc;
} }
ranges::transform(packedState.vertexAttributes, info.generic_input_types.begin(), &ConvertShaderAttributeType); ranges::transform(packedState.vertexAttributes, info.generic_input_types.begin(), &ConvertShaderAttributeType);
break; break;
case Shader::Stage::TessellationEval: case Shader::Stage::TessellationEval:
// Double check this!
info.tess_clockwise = packedState.outputPrimitives != engine::TessellationParameters::OutputPrimitives::TrianglesCCW; info.tess_clockwise = packedState.outputPrimitives != engine::TessellationParameters::OutputPrimitives::TrianglesCCW;
info.tess_primitive = ConvertShaderTessPrimitive(packedState.domainType); info.tess_primitive = ConvertShaderTessPrimitive(packedState.domainType);
info.tess_spacing = ConvertShaderTessSpacing(packedState.spacing); info.tess_spacing = ConvertShaderTessSpacing(packedState.spacing);
@ -124,9 +123,9 @@ namespace skyline::gpu::interconnect::maxwell3d {
if (program.output_topology == Shader::OutputTopology::PointList) if (program.output_topology == Shader::OutputTopology::PointList)
info.fixed_state_point_size = packedState.pointSize; info.fixed_state_point_size = packedState.pointSize;
// if (key.state.xfb_enabled != 0) { if (packedState.transformFeedbackEnable)
// info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); info.xfb_varyings = packedState.GetTransformFeedbackVaryings();
// }
info.convert_depth_mode = packedState.openGlNdc; info.convert_depth_mode = packedState.openGlNdc;
break; break;
case Shader::Stage::Fragment: case Shader::Stage::Fragment:

View File

@ -458,6 +458,22 @@ namespace skyline::gpu::interconnect::maxwell3d {
} }
} }
/* Transform Feedback State */
void TransformFeedbackState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const {
manager.Bind(handle, streamOutputEnable, streamOutControls, streamOutLayoutSelect);
}
TransformFeedbackState::TransformFeedbackState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine) : engine{manager, dirtyHandle, engine} {}
void TransformFeedbackState::Flush(PackedPipelineState &packedState) {
packedState.transformFeedbackEnable = engine->streamOutputEnable;
packedState.transformFeedbackVaryings = {};
if (engine->streamOutputEnable)
for (size_t i{}; i < engine::StreamOutBufferCount; i++)
packedState.SetTransformFeedbackVaryings(engine->streamOutControls[i], engine->streamOutLayoutSelect[i], i);
}
/* Global Shader Config State */ /* Global Shader Config State */
void GlobalShaderConfigState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const { void GlobalShaderConfigState::EngineRegisters::DirtyBind(DirtyManager &manager, dirty::Handle handle) const {
manager.Bind(handle, postVtgShaderAttributeSkipMask, bindlessTexture, apiMandatedEarlyZ); manager.Bind(handle, postVtgShaderAttributeSkipMask, bindlessTexture, apiMandatedEarlyZ);
@ -485,6 +501,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
bindFunc(depthStencilRegisters); bindFunc(depthStencilRegisters);
bindFunc(colorBlendRegisters); bindFunc(colorBlendRegisters);
bindFunc(globalShaderConfigRegisters); bindFunc(globalShaderConfigRegisters);
bindFunc(transformFeedbackRegisters);
manager.Bind(handle, ctSelect); manager.Bind(handle, ctSelect);
} }
@ -498,6 +515,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
rasterization{manager, engine.rasterizationRegisters}, rasterization{manager, engine.rasterizationRegisters},
depthStencil{manager, engine.depthStencilRegisters}, depthStencil{manager, engine.depthStencilRegisters},
colorBlend{manager, engine.colorBlendRegisters}, colorBlend{manager, engine.colorBlendRegisters},
transformFeedback{manager, engine.transformFeedbackRegisters},
directState{engine.inputAssemblyRegisters}, directState{engine.inputAssemblyRegisters},
globalShaderConfig{engine.globalShaderConfigRegisters}, globalShaderConfig{engine.globalShaderConfigRegisters},
ctSelect{engine.ctSelect} {} ctSelect{engine.ctSelect} {}
@ -531,6 +549,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
rasterization.Update(packedState); rasterization.Update(packedState);
depthStencil.Update(packedState); depthStencil.Update(packedState);
colorBlend.Update(packedState); colorBlend.Update(packedState);
transformFeedback.Update(packedState);
globalShaderConfig.Update(packedState); globalShaderConfig.Update(packedState);
if (pipeline) { if (pipeline) {

View File

@ -249,6 +249,25 @@ namespace skyline::gpu::interconnect::maxwell3d {
void Flush(PackedPipelineState &packedState); void Flush(PackedPipelineState &packedState);
}; };
class TransformFeedbackState : dirty::ManualDirty {
public:
struct EngineRegisters {
const u32 &streamOutputEnable;
const std::array<engine::StreamOutControl, engine::StreamOutBufferCount> &streamOutControls;
const std::array<std::array<u8, engine::StreamOutLayoutSelectAttributeCount>, engine::StreamOutBufferCount> &streamOutLayoutSelect;
void DirtyBind(DirtyManager &manager, dirty::Handle handle) const;
};
private:
dirty::BoundSubresource<EngineRegisters> engine;
public:
TransformFeedbackState(dirty::Handle dirtyHandle, DirtyManager &manager, const EngineRegisters &engine);
void Flush(PackedPipelineState &packedState);
};
class GlobalShaderConfigState { class GlobalShaderConfigState {
public: public:
struct EngineRegisters { struct EngineRegisters {
@ -283,6 +302,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
RasterizationState::EngineRegisters rasterizationRegisters; RasterizationState::EngineRegisters rasterizationRegisters;
DepthStencilState::EngineRegisters depthStencilRegisters; DepthStencilState::EngineRegisters depthStencilRegisters;
ColorBlendState::EngineRegisters colorBlendRegisters; ColorBlendState::EngineRegisters colorBlendRegisters;
TransformFeedbackState::EngineRegisters transformFeedbackRegisters;
GlobalShaderConfigState::EngineRegisters globalShaderConfigRegisters; GlobalShaderConfigState::EngineRegisters globalShaderConfigRegisters;
const engine::CtSelect &ctSelect; const engine::CtSelect &ctSelect;
@ -304,6 +324,7 @@ namespace skyline::gpu::interconnect::maxwell3d {
dirty::ManualDirtyState<RasterizationState> rasterization; dirty::ManualDirtyState<RasterizationState> rasterization;
dirty::ManualDirtyState<DepthStencilState> depthStencil; dirty::ManualDirtyState<DepthStencilState> depthStencil;
dirty::ManualDirtyState<ColorBlendState> colorBlend; dirty::ManualDirtyState<ColorBlendState> colorBlend;
dirty::ManualDirtyState<TransformFeedbackState> transformFeedback;
GlobalShaderConfigState globalShaderConfig; GlobalShaderConfigState globalShaderConfig;
const engine::CtSelect &ctSelect; const engine::CtSelect &ctSelect;