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 5e3cf842..13ecbae8 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -48,10 +48,6 @@ namespace skyline::gpu::interconnect { public: GraphicsContext(GPU &gpu, soc::gm20b::ChannelContext &channelCtx, gpu::interconnect::CommandExecutor &executor) : gpu(gpu), channelCtx(channelCtx), executor(executor), pipelineCache(gpu.vkDevice, vk::PipelineCacheCreateInfo{}) { scissors.fill(DefaultScissor); - if (!gpu.quirks.supportsMultipleViewports) { - viewportState.viewportCount = 1; - viewportState.scissorCount = 1; - } u32 bindingIndex{}; for (auto &vertexBuffer : vertexBuffers) { @@ -59,8 +55,6 @@ namespace skyline::gpu::interconnect { vertexBuffer.bindingDivisorDescription.binding = bindingIndex; bindingIndex++; } - if (!gpu.quirks.supportsVertexAttributeDivisor) - vertexState.unlink(); u32 attributeIndex{}; for (auto &vertexAttribute : vertexAttributes) @@ -371,12 +365,6 @@ namespace skyline::gpu::interconnect { .extent.height = std::numeric_limits::max(), .extent.width = std::numeric_limits::max(), }; //!< A scissor which displays the entire viewport, utilized when the viewport scissor is disabled - vk::PipelineViewportStateCreateInfo viewportState{ - .pViewports = viewports.data(), - .viewportCount = maxwell3d::ViewportCount, - .pScissors = scissors.data(), - .scissorCount = maxwell3d::ViewportCount, - }; public: /** @@ -696,7 +684,7 @@ namespace skyline::gpu::interconnect { bool needsRecompile{}; //!< If the shader needs to be recompiled as runtime information has changed ShaderCompiler::VaryingState previousStageStores{}; u32 bindingBase{}, bindingLast{}; //!< The base and last binding for descriptors bound to this stage - std::optional vkModule; + std::shared_ptr vkModule; std::array constantBuffers{}; @@ -725,9 +713,6 @@ namespace skyline::gpu::interconnect { ShaderSet shaders; PipelineStages pipelineStages; - std::array shaderStagesInfo{}; //!< Storage backing for the pipeline shader stage information for all shaders aside from 'VertexA' which uses the same stage as 'VertexB' - std::optional descriptorSetLayout{}; //!< The descriptor set layout for the pipeline (Only valid when `activeShaderStagesInfoCount` is non-zero) - ShaderCompiler::RuntimeInfo runtimeInfo{}; constexpr static size_t MaxShaderBytecodeSize{1 * 1024 * 1024}; //!< The largest shader binary that we support (1 MiB) @@ -746,8 +731,9 @@ namespace skyline::gpu::interconnect { * @note The `descriptorSetWrite` will have a null `dstSet` which needs to be assigned prior to usage */ struct ShaderProgramState { - span shaders; - vk::DescriptorSetLayout descriptorSetLayout; + boost::container::static_vector, maxwell3d::PipelineStageCount> shaderModules; //!< Shader modules for every pipeline stage + boost::container::static_vector shaderStages; //!< Shader modules for every pipeline stage + vk::raii::DescriptorSetLayout descriptorSetLayout; //!< The descriptor set layout for the pipeline (Only valid when `activeShaderStagesInfoCount` is non-zero) span descriptorSetWrites; //!< The writes to the descriptor set that need to be done prior to executing a pipeline }; @@ -861,7 +847,8 @@ namespace skyline::gpu::interconnect { runtimeInfo.previous_stage_stores.mask.set(); // First stage should always have all bits set ShaderCompiler::Backend::Bindings bindings{}; - size_t count{}; + boost::container::static_vector, maxwell3d::PipelineStageCount> shaderModules; + boost::container::static_vector shaderStages; for (auto &pipelineStage : pipelineStages) { if (!pipelineStage.enabled) continue; @@ -874,7 +861,7 @@ namespace skyline::gpu::interconnect { if (pipelineStage.needsRecompile || bindings.unified != pipelineStage.bindingBase || pipelineStage.previousStageStores.mask != runtimeInfo.previous_stage_stores.mask) { pipelineStage.previousStageStores = runtimeInfo.previous_stage_stores; pipelineStage.bindingBase = bindings.unified; - pipelineStage.vkModule = gpu.shader.CompileShader(runtimeInfo, program, bindings); + pipelineStage.vkModule = std::make_shared(gpu.shader.CompileShader(runtimeInfo, program, bindings)); pipelineStage.bindingLast = bindings.unified; } @@ -951,21 +938,21 @@ namespace skyline::gpu::interconnect { } } - shaderStagesInfo[count++] = vk::PipelineShaderStageCreateInfo{ + shaderModules.emplace_back(pipelineStage.vkModule); + shaderStages.emplace_back(vk::PipelineShaderStageCreateInfo{ .stage = pipelineStage.vkStage, .module = **pipelineStage.vkModule, .pName = "main", - }; + }); } - descriptorSetLayout.emplace(gpu.vkDevice, vk::DescriptorSetLayoutCreateInfo{ - .pBindings = layoutBindings.data(), - .bindingCount = static_cast(layoutBindings.size()), - }); - return { - span(shaderStagesInfo.data(), count), - **descriptorSetLayout, + std::move(shaderModules), + std::move(shaderStages), + vk::raii::DescriptorSetLayout(gpu.vkDevice, vk::DescriptorSetLayoutCreateInfo{ + .pBindings = layoutBindings.data(), + .bindingCount = static_cast(layoutBindings.size()), + }), descriptorSetWrites, }; } @@ -1384,24 +1371,12 @@ namespace skyline::gpu::interconnect { std::shared_ptr view; }; std::array vertexBuffers{}; - boost::container::static_vector vertexBindingDescriptions{}; - boost::container::static_vector vertexBindingDivisorsDescriptions{}; struct VertexAttribute { bool enabled{}; vk::VertexInputAttributeDescription description; }; std::array vertexAttributes{}; - boost::container::static_vector vertexAttributesDescriptions{}; - - vk::StructureChain vertexState{ - vk::PipelineVertexInputStateCreateInfo{ - .pVertexBindingDescriptions = vertexBindingDescriptions.data(), - .pVertexAttributeDescriptions = vertexAttributesDescriptions.data(), - }, vk::PipelineVertexInputDivisorStateCreateInfoEXT{ - .pVertexBindingDivisors = vertexBindingDivisorsDescriptions.data(), - } - }; public: void SetVertexBufferStride(u32 index, u32 stride) { @@ -2078,86 +2053,21 @@ namespace skyline::gpu::interconnect { /* Draws */ private: - vk::GraphicsPipelineCreateInfo pipelineState{ - .pVertexInputState = &vertexState.get(), - .pInputAssemblyState = &inputAssemblyState, - .pViewportState = &viewportState, - .pRasterizationState = &rasterizerState.get(), - .pMultisampleState = &multisampleState, - .pDepthStencilState = &depthState, - .pColorBlendState = &blendState, - .pDynamicState = nullptr, - }; vk::raii::PipelineCache pipelineCache; public: template void Draw(u32 count, u32 first, i32 vertexOffset = 0) { - // Color Render Target Setup - boost::container::static_vector, maxwell3d::RenderTargetCount> colorRenderTargetLocks; - boost::container::static_vector activeColorRenderTargets; - - for (u32 index{}; index < maxwell3d::RenderTargetCount; index++) { - auto renderTarget{GetColorRenderTarget(index)}; - if (renderTarget) { - colorRenderTargetLocks.emplace_back(*renderTarget); - activeColorRenderTargets.push_back(renderTarget); - } - } - - blendState.attachmentCount = static_cast(activeColorRenderTargets.size()); - - // Depth/Stencil Render Target Setup - auto depthRenderTargetView{GetDepthRenderTarget()}; - std::optional> depthTargetLock; - if (depthRenderTargetView) - depthTargetLock.emplace(*depthRenderTargetView); - - // Vertex Buffer Setup - std::array vertexBufferHandles{}; - std::array vertexBufferOffsets{}; - - vertexBindingDescriptions.clear(); - vertexBindingDivisorsDescriptions.clear(); - - for (u32 index{}; index < maxwell3d::VertexBufferCount; index++) { - auto vertexBufferView{GetVertexBuffer(index)}; - if (vertexBufferView) { - auto &vertexBuffer{vertexBuffers[index]}; - vertexBindingDescriptions.push_back(vertexBuffer.bindingDescription); - vertexBindingDivisorsDescriptions.push_back(vertexBuffer.bindingDivisorDescription); - - std::scoped_lock vertexBufferLock(*vertexBufferView); - executor.AttachBuffer(vertexBufferView); - vertexBufferHandles[index] = vertexBufferView->buffer->GetBacking(); - vertexBufferOffsets[index] = vertexBufferView->offset; - } - } - - vertexState.get().vertexBindingDescriptionCount = static_cast(vertexBindingDescriptions.size()); - vertexState.get().vertexBindingDivisorCount = static_cast(vertexBindingDivisorsDescriptions.size()); - - // Vertex Attribute Setup - vertexAttributesDescriptions.clear(); - - for (auto &vertexAttribute : vertexAttributes) - if (vertexAttribute.enabled) - vertexAttributesDescriptions.push_back(vertexAttribute.description); - - vertexState.get().vertexAttributeDescriptionCount = static_cast(vertexAttributesDescriptions.size()); - // Shader + Binding Setup auto programState{CompileShaderProgramState()}; - pipelineState.pStages = programState.shaders.data(); - pipelineState.stageCount = static_cast(programState.shaders.size()); - auto descriptorSet{gpu.descriptor.AllocateSet(programState.descriptorSetLayout)}; + auto descriptorSet{gpu.descriptor.AllocateSet(*programState.descriptorSetLayout)}; for (auto &descriptorSetWrite : programState.descriptorSetWrites) descriptorSetWrite.dstSet = descriptorSet; gpu.vkDevice.updateDescriptorSets(programState.descriptorSetWrites, nullptr); vk::raii::PipelineLayout pipelineLayout(gpu.vkDevice, vk::PipelineLayoutCreateInfo{ - .pSetLayouts = &programState.descriptorSetLayout, + .pSetLayouts = &*programState.descriptorSetLayout, .setLayoutCount = 1, }); @@ -2174,6 +2084,52 @@ namespace skyline::gpu::interconnect { indexBufferType = indexBuffer.type; } + // Vertex Buffer Setup + std::array vertexBufferHandles{}; + std::array vertexBufferOffsets{}; + + boost::container::static_vector vertexBindingDescriptions{}; + boost::container::static_vector vertexBindingDivisorsDescriptions{}; + + for (u32 index{}; index < maxwell3d::VertexBufferCount; index++) { + auto vertexBufferView{GetVertexBuffer(index)}; + if (vertexBufferView) { + auto &vertexBuffer{vertexBuffers[index]}; + vertexBindingDescriptions.push_back(vertexBuffer.bindingDescription); + vertexBindingDivisorsDescriptions.push_back(vertexBuffer.bindingDivisorDescription); + + std::scoped_lock vertexBufferLock(*vertexBufferView); + vertexBufferHandles[index] = vertexBufferView->buffer->GetBacking(); + vertexBufferOffsets[index] = vertexBufferView->offset; + executor.AttachBuffer(vertexBufferView); + } + } + + // Vertex Attribute Setup + boost::container::static_vector vertexAttributesDescriptions{}; + for (auto &vertexAttribute : vertexAttributes) + if (vertexAttribute.enabled) + vertexAttributesDescriptions.push_back(vertexAttribute.description); + + // Color Render Target + Blending Setup + boost::container::static_vector activeColorRenderTargets; + for (u32 index{}; index < maxwell3d::RenderTargetCount; index++) { + auto renderTarget{GetColorRenderTarget(index)}; + if (renderTarget) { + std::scoped_lock lock(*renderTarget); + activeColorRenderTargets.push_back(renderTarget); + executor.AttachTexture(renderTarget); + } + } + + boost::container::static_vector blendAttachmentStates(blendState.pAttachments, blendState.pAttachments + activeColorRenderTargets.size()); + + // Depth/Stencil Render Target Setup + auto depthRenderTargetView{GetDepthRenderTarget()}; + std::optional> depthTargetLock; + if (depthRenderTargetView) + depthTargetLock.emplace(*depthRenderTargetView); + // Draw Persistent Storage struct Storage : FenceCycleDependency { vk::raii::PipelineLayout pipelineLayout; @@ -2186,11 +2142,47 @@ namespace skyline::gpu::interconnect { auto storage{std::make_shared(std::move(pipelineLayout), std::move(descriptorSet))}; // Submit Draw - executor.AddSubpass([=, &vkDevice = gpu.vkDevice, pipelineCreateInfo = pipelineState, storage = std::move(storage), vertexBufferHandles = std::move(vertexBufferHandles), vertexBufferOffsets = std::move(vertexBufferOffsets), pipelineCache = *pipelineCache](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &, vk::RenderPass renderPass, u32 subpassIndex) mutable { - pipelineCreateInfo.layout = *storage->pipelineLayout; + executor.AddSubpass([=, &vkDevice = gpu.vkDevice, shaderModules = programState.shaderModules, shaderStages = programState.shaderStages, inputAssemblyState = inputAssemblyState, multiViewport = gpu.quirks.supportsMultipleViewports, viewports = viewports, scissors = scissors, rasterizerState = rasterizerState, multisampleState = multisampleState, depthState = depthState, blendState = blendState, storage = std::move(storage), supportsVertexAttributeDivisor = gpu.quirks.supportsVertexAttributeDivisor, vertexBufferHandles = std::move(vertexBufferHandles), vertexBufferOffsets = std::move(vertexBufferOffsets), pipelineCache = *pipelineCache](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &, vk::RenderPass renderPass, u32 subpassIndex) mutable { + vk::StructureChain vertexState{ + vk::PipelineVertexInputStateCreateInfo{ + .pVertexBindingDescriptions = vertexBindingDescriptions.data(), + .vertexBindingDescriptionCount = static_cast(vertexBindingDescriptions.size()), + .pVertexAttributeDescriptions = vertexAttributesDescriptions.data(), + .vertexAttributeDescriptionCount = static_cast(vertexAttributesDescriptions.size()), + }, vk::PipelineVertexInputDivisorStateCreateInfoEXT{ + .pVertexBindingDivisors = vertexBindingDivisorsDescriptions.data(), + .vertexBindingDivisorCount = static_cast(vertexBindingDivisorsDescriptions.size()), + } + }; - pipelineCreateInfo.renderPass = renderPass; - pipelineCreateInfo.subpass = subpassIndex; + if (!supportsVertexAttributeDivisor) + vertexState.unlink(); + + vk::PipelineViewportStateCreateInfo viewportState{ + .pViewports = viewports.data(), + .viewportCount = static_cast(multiViewport ? maxwell3d::ViewportCount : 1), + .pScissors = scissors.data(), + .scissorCount = static_cast(multiViewport ? maxwell3d::ViewportCount : 1), + }; + + blendState.pAttachments = blendAttachmentStates.data(); + blendState.attachmentCount = static_cast(blendAttachmentStates.size()); + + vk::GraphicsPipelineCreateInfo pipelineCreateInfo{ + .pStages = shaderStages.data(), + .stageCount = static_cast(shaderStages.size()), + .pVertexInputState = &vertexState.get(), + .pInputAssemblyState = &inputAssemblyState, + .pViewportState = &viewportState, + .pRasterizationState = &rasterizerState.get(), + .pMultisampleState = &multisampleState, + .pDepthStencilState = &depthState, + .pColorBlendState = &blendState, + .pDynamicState = nullptr, + .layout = *storage->pipelineLayout, + .renderPass = renderPass, + .subpass = subpassIndex, + }; auto pipeline{(*vkDevice).createGraphicsPipeline(pipelineCache, pipelineCreateInfo, nullptr, *vkDevice.getDispatcher())}; if (pipeline.result != vk::Result::eSuccess)