Implement transform feedback with VK_EXT_transform_feedback

Tested to work in Xenoblade Chronicles DE, the code handles both hades varying input and buffer setup.
This commit is contained in:
Billy Laws 2022-07-31 14:58:24 +01:00
parent 06053d3caf
commit dccc86ea97
8 changed files with 277 additions and 8 deletions

View File

@ -233,7 +233,8 @@ namespace skyline::gpu {
vk::PhysicalDeviceShaderDrawParametersFeatures,
vk::PhysicalDeviceProvokingVertexFeaturesEXT,
vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT,
vk::PhysicalDeviceImagelessFramebufferFeatures>()};
vk::PhysicalDeviceImagelessFramebufferFeatures,
vk::PhysicalDeviceTransformFeedbackFeaturesEXT>()};
decltype(deviceFeatures2) enabledFeatures2{}; // We only want to enable features we required due to potential overhead from unused features
#define FEAT_REQ(structName, feature) \
@ -268,6 +269,7 @@ namespace skyline::gpu {
vk::PhysicalDeviceProperties2,
vk::PhysicalDeviceDriverProperties,
vk::PhysicalDeviceFloatControlsProperties,
vk::PhysicalDeviceTransformFeedbackPropertiesEXT,
vk::PhysicalDeviceSubgroupProperties>()};
traits = TraitManager{deviceFeatures2, enabledFeatures2, deviceExtensions, enabledExtensions, deviceProperties2, physicalDevice};

View File

@ -2817,6 +2817,146 @@ namespace skyline::gpu::interconnect {
.rasterizationSamples = vk::SampleCountFlagBits::e1,
};
/* Transform Feedback */
private:
bool transformFeedbackEnabled{};
struct TransformFeedbackBuffer {
IOVA iova;
u32 size;
u32 offset;
BufferView view;
u32 stride;
u32 varyingCount;
std::array<u8, maxwell3d::TransformFeedbackVaryingCount> varyings;
};
std::array<TransformFeedbackBuffer, maxwell3d::TransformFeedbackBufferCount> transformFeedbackBuffers{};
bool transformFeedbackVaryingsDirty;
struct TransformFeedbackBufferResult {
BufferView view;
bool wasCached;
};
TransformFeedbackBufferResult GetTransformFeedbackBuffer(size_t idx) {
auto &buffer{transformFeedbackBuffers[idx]};
if (!buffer.iova || !buffer.size)
return {nullptr, false};
else if (buffer.view)
return {buffer.view, true};
auto mappings{channelCtx.asCtx->gmmu.TranslateRange(buffer.offset + buffer.iova, buffer.size)};
if (mappings.size() != 1)
Logger::Warn("Multiple buffer mappings ({}) are not supported", mappings.size());
auto mapping{mappings.front()};
buffer.view = executor.AcquireBufferManager().FindOrCreate(span<u8>(mapping.data(), buffer.size), executor.tag, [this](std::shared_ptr<Buffer> buffer, ContextLock<Buffer> &&lock) {
executor.AttachLockedBuffer(buffer, std::move(lock));
});
return {buffer.view, false};
}
void FillTransformFeedbackVaryingState() {
if (!transformFeedbackVaryingsDirty)
return;
runtimeInfo.xfb_varyings.clear();
if (!transformFeedbackEnabled)
return;
// Will be indexed by a u8 so allocate just enough space
runtimeInfo.xfb_varyings.resize(256);
for (u32 i{}; i < maxwell3d::TransformFeedbackBufferCount; i++) {
const auto &buffer{transformFeedbackBuffers[i]};
for (u32 k{}; k < buffer.varyingCount; k++) {
// TODO: We could merge multiple component accesses from the same attribute into one varying
u8 attributeIndex{buffer.varyings[k]};
runtimeInfo.xfb_varyings[attributeIndex] = {
.buffer = i,
.offset = k * 4,
.stride = buffer.stride,
.components = 1,
};
}
}
transformFeedbackVaryingsDirty = false;
}
void InvalidateTransformFeedbackVaryings() {
transformFeedbackVaryingsDirty = true;
pipelineStages[maxwell3d::PipelineStage::Vertex].needsRecompile = true;
pipelineStages[maxwell3d::PipelineStage::Geometry].needsRecompile = true;
}
public:
void SetTransformFeedbackEnabled(bool enable) {
transformFeedbackEnabled = enable;
if (enable && !gpu.traits.supportsTransformFeedback)
Logger::Warn("Transform feedback used without host GPU support!");
InvalidateTransformFeedbackVaryings();
}
void SetTransformFeedbackBufferEnabled(size_t idx, bool enabled) {
if (!enabled)
transformFeedbackBuffers[idx].iova = {};
}
void SetTransformFeedbackBufferIovaHigh(size_t idx, u32 high) {
auto &buffer{transformFeedbackBuffers[idx]};
buffer.iova.high = high;
buffer.view = {};
};
void SetTransformFeedbackBufferIovaLow(size_t idx, u32 low) {
auto &buffer{transformFeedbackBuffers[idx]};
buffer.iova.low = low;
buffer.view = {};
}
void SetTransformFeedbackBufferSize(size_t idx, u32 size) {
auto &buffer{transformFeedbackBuffers[idx]};
buffer.size = size;
buffer.view = {};
}
void SetTransformFeedbackBufferOffset(size_t idx, u32 offset) {
auto &buffer{transformFeedbackBuffers[idx]};
buffer.offset = offset;
buffer.view = {};
}
void SetTransformFeedbackBufferStride(size_t idx, u32 stride) {
auto &buffer{transformFeedbackBuffers[idx]};
buffer.stride = stride;
InvalidateTransformFeedbackVaryings();
}
void SetTransformFeedbackBufferVaryingCount(size_t idx, u32 varyingCount) {
auto &buffer{transformFeedbackBuffers[idx]};
buffer.varyingCount = varyingCount;
InvalidateTransformFeedbackVaryings();
}
void SetTransformFeedbackBufferVarying(size_t bufIdx, size_t varIdx, u32 value) {
auto &buffer{transformFeedbackBuffers[bufIdx]};
span(buffer.varyings).cast<u32>()[varIdx] = value;
InvalidateTransformFeedbackVaryings();
}
/* Draws */
public:
template<bool IsIndexed>
@ -2900,6 +3040,34 @@ namespace skyline::gpu::interconnect {
if (vertexAttribute.enabled)
vertexAttributesDescriptions.push_back(vertexAttribute.description);
struct BoundTransformFeedbackBuffers {
std::array<vk::Buffer, maxwell3d::TransformFeedbackBufferCount> handles{};
std::array<vk::DeviceSize, maxwell3d::TransformFeedbackBufferCount> offsets{};
std::array<vk::DeviceSize, maxwell3d::TransformFeedbackBufferCount> sizes{};
};
std::shared_ptr<BoundTransformFeedbackBuffers> boundTransformFeedbackBuffers{};
if (transformFeedbackEnabled) {
boundTransformFeedbackBuffers = std::allocate_shared<BoundTransformFeedbackBuffers, LinearAllocator<BoundVertexBuffers>>(executor.allocator);
for (size_t i{}; i < maxwell3d::TransformFeedbackBufferCount; i++) {
if (auto result{GetTransformFeedbackBuffer(i)}; result.view) {
auto &view{result.view};
executor.AttachBuffer(view);
view->buffer->MarkGpuDirty();
if (!result.wasCached) {
boundTransformFeedbackBuffers->sizes[i] = view->view->size;
view.RegisterUsage(executor.allocator, executor.cycle, [handle = boundTransformFeedbackBuffers->handles.data() + i, offset = boundTransformFeedbackBuffers->offsets.data() + i](const Buffer::BufferViewStorage &view, const std::shared_ptr<Buffer> &buffer) {
*handle = buffer->GetBacking();
*offset = view.offset;
});
}
}
}
}
FillTransformFeedbackVaryingState();
// Color Render Target + Blending Setup
boost::container::static_vector<TextureView *, maxwell3d::RenderTargetCount> activeColorRenderTargets;
for (u32 index{}; index < maxwell3d::RenderTargetCount; index++) {
@ -2979,7 +3147,7 @@ namespace skyline::gpu::interconnect {
}
// Submit Draw
executor.AddSubpass([=, drawStorage = std::move(drawStorage), pipelineLayout = compiledPipeline.pipelineLayout, pipeline = compiledPipeline.pipeline](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &, vk::RenderPass renderPass, u32 subpassIndex) mutable {
executor.AddSubpass([=, drawStorage = std::move(drawStorage), pipelineLayout = compiledPipeline.pipelineLayout, pipeline = compiledPipeline.pipeline, transformFeedbackEnabled = transformFeedbackEnabled](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &, vk::RenderPass renderPass, u32 subpassIndex) mutable {
auto &vertexBufferHandles{boundVertexBuffers->handles};
for (u32 bindingIndex{}; bindingIndex != vertexBufferHandles.size(); bindingIndex++) {
// We need to bind all non-null vertex buffers while skipping any null ones
@ -3004,12 +3172,23 @@ namespace skyline::gpu::interconnect {
commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
if (transformFeedbackEnabled) {
for (u32 i{}; i < maxwell3d::TransformFeedbackBufferCount; i++)
if (boundTransformFeedbackBuffers->handles[i])
commandBuffer.bindTransformFeedbackBuffersEXT(i, span(boundTransformFeedbackBuffers->handles).subspan(i, 1), span(boundTransformFeedbackBuffers->offsets).subspan(i, 1), span(boundTransformFeedbackBuffers->sizes).subspan(i, 1));
commandBuffer.beginTransformFeedbackEXT(0, {}, {});
}
if (IsIndexed || boundIndexBuffer) {
commandBuffer.bindIndexBuffer(boundIndexBuffer->handle, boundIndexBuffer->offset, boundIndexBuffer->type);
commandBuffer.drawIndexed(count, instanceCount, first, vertexOffset, 0);
} else {
commandBuffer.draw(count, instanceCount, first, 0);
}
if (transformFeedbackEnabled)
commandBuffer.endTransformFeedbackEXT(0, {}, {});
}, renderArea, {}, activeColorRenderTargets, depthRenderTargetView, !gpu.traits.quirks.relaxedRenderPassCompatibility);
}

View File

@ -98,7 +98,7 @@ namespace skyline::gpu::memory {
Buffer MemoryManager::AllocateBuffer(vk::DeviceSize size) {
vk::BufferCreateInfo bufferCreateInfo{
.size = size,
.usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eUniformTexelBuffer | vk::BufferUsageFlagBits::eStorageTexelBuffer | vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndirectBuffer,
.usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eUniformTexelBuffer | vk::BufferUsageFlagBits::eStorageTexelBuffer | vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndirectBuffer | vk::BufferUsageFlagBits::eTransformFeedbackBufferEXT,
.sharingMode = vk::SharingMode::eExclusive,
.queueFamilyIndexCount = 1,
.pQueueFamilyIndices = &gpu.vkQueueFamilyIndex,

View File

@ -6,7 +6,7 @@
namespace skyline::gpu {
TraitManager::TraitManager(const DeviceFeatures2 &deviceFeatures2, DeviceFeatures2 &enabledFeatures2, const std::vector<vk::ExtensionProperties> &deviceExtensions, std::vector<std::array<char, VK_MAX_EXTENSION_NAME_SIZE>> &enabledExtensions, const DeviceProperties2 &deviceProperties2, const vk::raii::PhysicalDevice &physicalDevice) : quirks(deviceProperties2.get<vk::PhysicalDeviceProperties2>().properties, deviceProperties2.get<vk::PhysicalDeviceDriverProperties>()) {
bool hasCustomBorderColorExt{}, hasShaderAtomicInt64Ext{}, hasShaderFloat16Int8Ext{}, hasShaderDemoteToHelperExt{}, hasVertexAttributeDivisorExt{}, hasProvokingVertexExt{}, hasPrimitiveTopologyListRestartExt{}, hasImagelessFramebuffersExt{};
bool hasCustomBorderColorExt{}, hasShaderAtomicInt64Ext{}, hasShaderFloat16Int8Ext{}, hasShaderDemoteToHelperExt{}, hasVertexAttributeDivisorExt{}, hasProvokingVertexExt{}, hasPrimitiveTopologyListRestartExt{}, hasImagelessFramebuffersExt{}, hasTransformFeedbackExt{};
bool supportsUniformBufferStandardLayout{}; // We require VK_KHR_uniform_buffer_standard_layout but assume it is implicitly supported even when not present
for (auto &extension : deviceExtensions) {
@ -56,6 +56,7 @@ namespace skyline::gpu {
EXT_SET("VK_KHR_shader_float_controls", supportsFloatControls);
EXT_SET("VK_KHR_uniform_buffer_standard_layout", supportsUniformBufferStandardLayout);
EXT_SET("VK_EXT_primitive_topology_list_restart", hasPrimitiveTopologyListRestartExt);
EXT_SET("VK_EXT_transform_feedback", hasTransformFeedbackExt);
}
#undef EXT_SET
@ -138,6 +139,20 @@ namespace skyline::gpu {
enabledFeatures2.unlink<vk::PhysicalDeviceImagelessFramebufferFeatures>();
}
FEAT_SET(vk::PhysicalDeviceFeatures2, features.geometryShader, supportsGeometryShaders)
if (hasTransformFeedbackExt) {
bool hasTransformFeedbackFeat{}, hasGeometryStreamsStreamsFeat{};
FEAT_SET(vk::PhysicalDeviceTransformFeedbackFeaturesEXT, transformFeedback, hasTransformFeedbackFeat)
FEAT_SET(vk::PhysicalDeviceTransformFeedbackFeaturesEXT, geometryStreams, hasGeometryStreamsStreamsFeat)
auto transformFeedbackProperties{deviceProperties2.get<vk::PhysicalDeviceTransformFeedbackPropertiesEXT>()};
if (hasTransformFeedbackFeat && hasGeometryStreamsStreamsFeat && transformFeedbackProperties.transformFeedbackDraw)
supportsTransformFeedback = true;
} else {
enabledFeatures2.unlink<vk::PhysicalDeviceTransformFeedbackFeaturesEXT>();
}
#undef FEAT_SET
if (supportsFloatControls)
@ -166,8 +181,8 @@ namespace skyline::gpu {
std::string TraitManager::Summary() {
return fmt::format(
"\n* Supports U8 Indices: {}\n* Supports Sampler Mirror Clamp To Edge: {}\n* Supports Sampler Reduction Mode: {}\n* Supports Custom Border Color (Without Format): {}\n* Supports Anisotropic Filtering: {}\n* Supports Last Provoking Vertex: {}\n* Supports Logical Operations: {}\n* Supports Vertex Attribute Divisor: {}\n* Supports Vertex Attribute Zero Divisor: {}\n* Supports Push Descriptors: {}\n* Supports Imageless Framebuffers: {}\n* Supports Global Priority: {}\n* Supports Multiple Viewports: {}\n* Supports Shader Viewport Index: {}\n* Supports SPIR-V 1.4: {}\n* Supports Shader Invocation Demotion: {}\n* Supports 16-bit FP: {}\n* Supports 8-bit Integers: {}\n* Supports 16-bit Integers: {}\n* Supports 64-bit Integers: {}\n* Supports Atomic 64-bit Integers: {}\n* Supports Floating Point Behavior Control: {}\n* Supports Image Read Without Format: {}\n* Supports List Primitive Topology Restart: {}\n* Supports Patch List Primitive Topology Restart: {}\n* Supports Subgroup Vote: {}\n* Subgroup Size: {}\n* BCn Support: {}",
supportsUint8Indices, supportsSamplerMirrorClampToEdge, supportsSamplerReductionMode, supportsCustomBorderColor, supportsAnisotropicFiltering, supportsLastProvokingVertex, supportsLogicOp, supportsVertexAttributeDivisor, supportsVertexAttributeZeroDivisor, supportsPushDescriptors, supportsImagelessFramebuffers, supportsGlobalPriority, supportsMultipleViewports, supportsShaderViewportIndexLayer, supportsSpirv14, supportsShaderDemoteToHelper, supportsFloat16, supportsInt8, supportsInt16, supportsInt64, supportsAtomicInt64, supportsFloatControls, supportsImageReadWithoutFormat, supportsTopologyListRestart, supportsTopologyPatchListRestart, supportsSubgroupVote, subgroupSize, bcnSupport.to_string()
"\n* Supports U8 Indices: {}\n* Supports Sampler Mirror Clamp To Edge: {}\n* Supports Sampler Reduction Mode: {}\n* Supports Custom Border Color (Without Format): {}\n* Supports Anisotropic Filtering: {}\n* Supports Last Provoking Vertex: {}\n* Supports Logical Operations: {}\n* Supports Vertex Attribute Divisor: {}\n* Supports Vertex Attribute Zero Divisor: {}\n* Supports Push Descriptors: {}\n* Supports Imageless Framebuffers: {}\n* Supports Global Priority: {}\n* Supports Multiple Viewports: {}\n* Supports Shader Viewport Index: {}\n* Supports SPIR-V 1.4: {}\n* Supports Shader Invocation Demotion: {}\n* Supports 16-bit FP: {}\n* Supports 8-bit Integers: {}\n* Supports 16-bit Integers: {}\n* Supports 64-bit Integers: {}\n* Supports Atomic 64-bit Integers: {}\n* Supports Floating Point Behavior Control: {}\n* Supports Image Read Without Format: {}\n* Supports List Primitive Topology Restart: {}\n* Supports Patch List Primitive Topology Restart: {}\n* Supports Transform Feedback: {}\n* Supports Geometry Shaders: {}\n * Supports Subgroup Vote: {}\n* Subgroup Size: {}\n* BCn Support: {}",
supportsUint8Indices, supportsSamplerMirrorClampToEdge, supportsSamplerReductionMode, supportsCustomBorderColor, supportsAnisotropicFiltering, supportsLastProvokingVertex, supportsLogicOp, supportsVertexAttributeDivisor, supportsVertexAttributeZeroDivisor, supportsPushDescriptors, supportsImagelessFramebuffers, supportsGlobalPriority, supportsMultipleViewports, supportsShaderViewportIndexLayer, supportsSpirv14, supportsShaderDemoteToHelper, supportsFloat16, supportsInt8, supportsInt16, supportsInt64, supportsAtomicInt64, supportsFloatControls, supportsImageReadWithoutFormat, supportsTopologyListRestart, supportsTopologyPatchListRestart, supportsTransformFeedback, supportsGeometryShaders, supportsSubgroupVote, subgroupSize, bcnSupport.to_string()
);
}

View File

@ -35,9 +35,11 @@ namespace skyline::gpu {
bool supportsAtomicInt64{}; //!< If atomic operations on 64-bit integers are supported in shaders
bool supportsFloatControls{}; //!< If extensive control over FP behavior is exposed (with VK_KHR_shader_float_controls)
vk::PhysicalDeviceFloatControlsProperties floatControls{}; //!< Specifics of FP behavior control (All members will be zero'd out when unavailable)
bool supportsTransformFeedback{}; //!< If the 'VK_EXT_transform_feedback' extension is supported with neccessary features for emulation
bool supportsImageReadWithoutFormat{}; //!< If a storage image can be read without a format
bool supportsTopologyListRestart{}; //!< If the device supports using primitive restart for topology lists (with VK_EXT_primitive_topology_list_restart)
bool supportsTopologyPatchListRestart{}; //!< If the device supports using primitive restart for topology patch lists (with VK_EXT_primitive_topology_list_restart)
bool supportsGeometryShaders; //!< If the device supports the 'geometryShader' Vulkan feature
bool supportsSubgroupVote{}; //!< If subgroup votes are supported in shaders with SPV_KHR_subgroup_vote
u32 subgroupSize{}; //!< Size of a subgroup on the host GPU
@ -74,6 +76,7 @@ namespace skyline::gpu {
vk::PhysicalDeviceProperties2,
vk::PhysicalDeviceDriverProperties,
vk::PhysicalDeviceFloatControlsProperties,
vk::PhysicalDeviceTransformFeedbackPropertiesEXT,
vk::PhysicalDeviceSubgroupProperties>;
using DeviceFeatures2 = vk::StructureChain<
@ -87,7 +90,8 @@ namespace skyline::gpu {
vk::PhysicalDeviceShaderDrawParametersFeatures,
vk::PhysicalDeviceProvokingVertexFeaturesEXT,
vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT,
vk::PhysicalDeviceImagelessFramebufferFeatures>;
vk::PhysicalDeviceImagelessFramebufferFeatures,
vk::PhysicalDeviceTransformFeedbackFeaturesEXT>;
TraitManager(const DeviceFeatures2 &deviceFeatures2, DeviceFeatures2 &enabledFeatures2, const std::vector<vk::ExtensionProperties> &deviceExtensions, std::vector<std::array<char, VK_MAX_EXTENSION_NAME_SIZE>> &enabledExtensions, const DeviceProperties2 &deviceProperties2, const vk::raii::PhysicalDevice& physicalDevice);

View File

@ -782,5 +782,26 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
ZeroToOne = 1
};
constexpr static size_t TransformFeedbackBufferCount{4}; //!< Number of supported transform feecback buffers in the 3D engine
struct TransformFeedbackBuffer {
u32 enable;
Address iova;
u32 size;
u32 offset;
u32 _pad_[3];
};
static_assert(sizeof(TransformFeedbackBuffer) == (sizeof(u32) * 8));
struct TransformFeedbackBufferState {
u32 bufferIndex;
u32 varyingCount;
u32 stride;
u32 _pad_;
};
static_assert(sizeof(TransformFeedbackBufferState) == (sizeof(u32) * 4));
constexpr static size_t TransformFeedbackVaryingCount{0x80};
#pragma pack(pop)
}

View File

@ -232,6 +232,37 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
context.SetTessellationMode(tessellationMode.primitive, tessellationMode.spacing, tessellationMode.winding);
})
#define TRANSFORM_FEEDBACK_CALLBACKS(z, index, data) \
ENGINE_ARRAY_STRUCT_CASE(transformFeedbackBuffers, index, enable, { \
context.SetTransformFeedbackBufferEnabled(index, enable); \
}) \
ENGINE_ARRAY_STRUCT_STRUCT_CASE(transformFeedbackBuffers, index, iova, high, { \
context.SetTransformFeedbackBufferIovaHigh(index, high); \
}) \
ENGINE_ARRAY_STRUCT_STRUCT_CASE(transformFeedbackBuffers, index, iova, low, { \
context.SetTransformFeedbackBufferIovaLow(index, low); \
}) \
ENGINE_ARRAY_STRUCT_CASE(transformFeedbackBuffers, index, size, { \
context.SetTransformFeedbackBufferSize(index, size); \
}) \
ENGINE_ARRAY_STRUCT_CASE(transformFeedbackBuffers, index, offset, { \
context.SetTransformFeedbackBufferOffset(index, offset); \
}) \
ENGINE_ARRAY_STRUCT_CASE(transformFeedbackBufferStates, index, varyingCount, { \
context.SetTransformFeedbackBufferVaryingCount(index, varyingCount); \
}) \
ENGINE_ARRAY_STRUCT_CASE(transformFeedbackBufferStates, index, stride, { \
context.SetTransformFeedbackBufferStride(index, stride); \
})
BOOST_PP_REPEAT(4, TRANSFORM_FEEDBACK_CALLBACKS, 0)
static_assert(type::TransformFeedbackBufferCount == 4 && type::TransformFeedbackBufferCount < BOOST_PP_LIMIT_REPEAT);
#undef TRANSFORM_FEEDBACK_CALLBACKS
ENGINE_CASE(transformFeedbackEnable, {
context.SetTransformFeedbackEnabled(transformFeedbackEnable);
})
ENGINE_STRUCT_CASE(depthBiasEnable, point, {
context.SetDepthBiasPointEnabled(point);
})
@ -617,11 +648,21 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
ENGINE_STRUCT_CASE(texturePool, maximumIndex, {
context.SetTexturePoolMaximumIndex(maximumIndex);
})
ENGINE_CASE(depthMode, {
context.SetDepthMode(depthMode);
})
#define TRANSFORM_FEEDBACK_VARYINGS_CALLBACK(z, index, data) \
ENGINE_ARRAY_CASE(transformFeedbackVaryings, index, { \
context.SetTransformFeedbackBufferVarying(index / (type::TransformFeedbackVaryingCount / sizeof(u32)), \
index % (type::TransformFeedbackVaryingCount / sizeof(u32)), \
transformFeedbackVaryings); \
})
BOOST_PP_REPEAT(128, TRANSFORM_FEEDBACK_VARYINGS_CALLBACK, 0)
static_assert((type::TransformFeedbackVaryingCount / sizeof(u32)) * type::TransformFeedbackBufferCount < BOOST_PP_LIMIT_REPEAT);
#undef TRANSFORM_FEEDBACK_VARYINGS_CALLBACK
default:
break;
}

View File

@ -118,6 +118,11 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
Register<0xC8, TessellationMode> tessellationMode;
Register<0xDF, u32> rasterizerEnable;
Register<0xE0, std::array<type::TransformFeedbackBuffer, type::TransformFeedbackBufferCount>> transformFeedbackBuffers;
Register<0x1C0, std::array<type::TransformFeedbackBufferState, type::TransformFeedbackBufferCount>> transformFeedbackBufferStates;
Register<0x1D1, u32> transformFeedbackEnable;
Register<0x200, std::array<type::ColorRenderTarget, type::RenderTargetCount>> renderTargets;
Register<0x280, std::array<type::ViewportTransform, type::ViewportCount>> viewportTransforms;
Register<0x300, std::array<type::Viewport, type::ViewportCount>> viewports;
@ -378,6 +383,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
Register<0x900, std::array<type::Bind, type::PipelineStageCount>> bind; //!< Binds constant buffers to pipeline stages
Register<0x982, u32> bindlessTextureConstantBufferIndex; //!< The index of the constant buffer containing bindless texture descriptors
Register<0xA00, std::array<u32, (type::TransformFeedbackVaryingCount / sizeof(u32)) * type::TransformFeedbackBufferCount>> transformFeedbackVaryings;
};
static_assert(sizeof(Registers) == (EngineMethodsEnd * sizeof(u32)));
#pragma pack(pop)