diff --git a/app/src/main/cpp/skyline/gpu.cpp b/app/src/main/cpp/skyline/gpu.cpp index 9ea60fed..922767f4 100644 --- a/app/src/main/cpp/skyline/gpu.cpp +++ b/app/src/main/cpp/skyline/gpu.cpp @@ -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}; diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index ddcd1b2c..34e6e250 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -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 varyings; + }; + std::array 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(mapping.data(), buffer.size), executor.tag, [this](std::shared_ptr buffer, ContextLock &&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()[varIdx] = value; + + InvalidateTransformFeedbackVaryings(); + } + /* Draws */ public: template @@ -2900,6 +3040,34 @@ namespace skyline::gpu::interconnect { if (vertexAttribute.enabled) vertexAttributesDescriptions.push_back(vertexAttribute.description); + struct BoundTransformFeedbackBuffers { + std::array handles{}; + std::array offsets{}; + std::array sizes{}; + }; + + std::shared_ptr boundTransformFeedbackBuffers{}; + + if (transformFeedbackEnabled) { + boundTransformFeedbackBuffers = std::allocate_shared>(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) { + *handle = buffer->GetBacking(); + *offset = view.offset; + }); + } + } + } + } + + FillTransformFeedbackVaryingState(); + // Color Render Target + Blending Setup boost::container::static_vector 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 &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 &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); } diff --git a/app/src/main/cpp/skyline/gpu/memory_manager.cpp b/app/src/main/cpp/skyline/gpu/memory_manager.cpp index e4bff55c..0e23762d 100644 --- a/app/src/main/cpp/skyline/gpu/memory_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/memory_manager.cpp @@ -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, diff --git a/app/src/main/cpp/skyline/gpu/trait_manager.cpp b/app/src/main/cpp/skyline/gpu/trait_manager.cpp index dd5db21b..60a8b75d 100644 --- a/app/src/main/cpp/skyline/gpu/trait_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/trait_manager.cpp @@ -6,7 +6,7 @@ namespace skyline::gpu { TraitManager::TraitManager(const DeviceFeatures2 &deviceFeatures2, DeviceFeatures2 &enabledFeatures2, const std::vector &deviceExtensions, std::vector> &enabledExtensions, const DeviceProperties2 &deviceProperties2, const vk::raii::PhysicalDevice &physicalDevice) : quirks(deviceProperties2.get().properties, deviceProperties2.get()) { - 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(); } + 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()}; + if (hasTransformFeedbackFeat && hasGeometryStreamsStreamsFeat && transformFeedbackProperties.transformFeedbackDraw) + supportsTransformFeedback = true; + } else { + enabledFeatures2.unlink(); + } + #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() ); } diff --git a/app/src/main/cpp/skyline/gpu/trait_manager.h b/app/src/main/cpp/skyline/gpu/trait_manager.h index 87bdd2fb..7f3fd682 100644 --- a/app/src/main/cpp/skyline/gpu/trait_manager.h +++ b/app/src/main/cpp/skyline/gpu/trait_manager.h @@ -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 &deviceExtensions, std::vector> &enabledExtensions, const DeviceProperties2 &deviceProperties2, const vk::raii::PhysicalDevice& physicalDevice); diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h index 382604d5..11cb451e 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h @@ -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) } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index d52ec61b..e5e858f2 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -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; } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index c238d3a3..e0673299 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -118,6 +118,11 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0xC8, TessellationMode> tessellationMode; Register<0xDF, u32> rasterizerEnable; + + Register<0xE0, std::array> transformFeedbackBuffers; + Register<0x1C0, std::array> transformFeedbackBufferStates; + Register<0x1D1, u32> transformFeedbackEnable; + Register<0x200, std::array> renderTargets; Register<0x280, std::array> viewportTransforms; Register<0x300, std::array> viewports; @@ -378,6 +383,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x900, std::array> 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> transformFeedbackVaryings; }; static_assert(sizeof(Registers) == (EngineMethodsEnd * sizeof(u32))); #pragma pack(pop)