diff --git a/app/src/main/cpp/skyline/gpu/shaders/helper_shaders.cpp b/app/src/main/cpp/skyline/gpu/shaders/helper_shaders.cpp index 980831d9..d3eca8b9 100644 --- a/app/src/main/cpp/skyline/gpu/shaders/helper_shaders.cpp +++ b/app/src/main/cpp/skyline/gpu/shaders/helper_shaders.cpp @@ -40,10 +40,11 @@ namespace skyline::gpu { } {} cache::GraphicsPipelineCache::CompiledPipeline SimpleSingleRtShader::GetPipeline(GPU &gpu, - TextureView *colorAttachment, TextureView *depthStencilAttachment, - bool depthWrite, bool stencilWrite, u32 stencilValue, - vk::ColorComponentFlags colorWriteMask, + const PipelineState &state, span layoutBindings, span pushConstantRanges) { + if (auto it{pipelineCache.find(state)}; it != pipelineCache.end()) + return it->second; + constexpr static vk::PipelineInputAssemblyStateCreateInfo inputAssemblyState{ .topology = vk::PrimitiveTopology::eTriangleList, .primitiveRestartEnable = false @@ -75,28 +76,49 @@ namespace skyline::gpu { .alphaToOneEnable = false }; - vk::PipelineDepthStencilStateCreateInfo depthStencilState{ - .depthTestEnable = depthWrite, - .depthWriteEnable = depthWrite, - .depthCompareOp = vk::CompareOp::eAlways, - .depthBoundsTestEnable = false, - .stencilTestEnable = stencilWrite, + constexpr static std::array dynamicStates{ + vk::DynamicState::eViewport, + vk::DynamicState::eScissor, }; - if (stencilWrite) { + constexpr static vk::PipelineDynamicStateCreateInfo dynamicState{ + .dynamicStateCount = 2, + .pDynamicStates = dynamicStates.data() + }; + + // Dynamic state will be used instead of these + constexpr static std::array emptyScissor{}; + constexpr static std::array emptyViewport{}; + + constexpr static vk::PipelineViewportStateCreateInfo viewportState{ + .viewportCount = 1, + .pViewports = emptyViewport.data(), + .scissorCount = 1, + .pScissors = emptyScissor.data() + }; + + vk::PipelineDepthStencilStateCreateInfo depthStencilState{ + .depthTestEnable = state.depthWrite, + .depthWriteEnable = state.depthWrite, + .depthCompareOp = vk::CompareOp::eAlways, + .depthBoundsTestEnable = false, + .stencilTestEnable = state.stencilWrite, + }; + + if (state.stencilWrite) { depthStencilState.front = depthStencilState.back = { .depthFailOp = vk::StencilOp::eReplace, .passOp = vk::StencilOp::eReplace, .compareOp = vk::CompareOp::eAlways, .compareMask = 0xFF, .writeMask = 0xFF, - .reference = stencilValue + .reference = state.stencilValue }; } vk::PipelineColorBlendAttachmentState attachmentState{ .blendEnable = false, - .colorWriteMask = colorWriteMask + .colorWriteMask = static_cast(state.colorWriteMask) }; vk::PipelineColorBlendStateCreateInfo blendState{ @@ -114,30 +136,8 @@ namespace skyline::gpu { vertexState.unlink(); - auto attachmentDimensions{colorAttachment ? colorAttachment->texture->dimensions : depthStencilAttachment->texture->dimensions}; - - vk::Viewport viewport{ - .height = static_cast(attachmentDimensions.height), - .width = static_cast(attachmentDimensions.width), - .x = 0.0f, - .y = 0.0f, - .minDepth = 0.0f, - .maxDepth = 1.0f - }; - - vk::Rect2D scissor{ - .extent = attachmentDimensions - }; - - vk::PipelineViewportStateCreateInfo viewportState{ - .pViewports = &viewport, - .viewportCount = 1, - .pScissors = &scissor, - .scissorCount = 1 - }; - - std::array colorFormats{colorAttachment ? colorAttachment->format->vkFormat : vk::Format::eUndefined}; - return gpu.graphicsPipelineCache.GetCompiledPipeline(cache::GraphicsPipelineCache::PipelineState{ + std::array colorFormats{state.colorFormat}; + return pipelineCache.emplace(state, gpu.graphicsPipelineCache.GetCompiledPipeline(cache::GraphicsPipelineCache::PipelineState{ .shaderStages = shaderStages, .vertexState = vertexState, .inputAssemblyState = inputAssemblyState, @@ -147,10 +147,10 @@ namespace skyline::gpu { .multisampleState = multisampleState, .depthStencilState = depthStencilState, .colorBlendState = blendState, - .dynamicState = {}, + .dynamicState = dynamicState, .colorFormats = colorFormats, - .depthStencilFormat = depthStencilAttachment ? depthStencilAttachment->format->vkFormat : vk::Format::eUndefined, - }, layoutBindings, pushConstantRanges, true); + .depthStencilFormat = state.depthFormat, + }, layoutBindings, pushConstantRanges, true)).first->second; } namespace glsl { @@ -233,13 +233,16 @@ namespace skyline::gpu { blit::FragmentPushConstantLayout fragmentPushConstants; DescriptorAllocator::ActiveDescriptorSet descriptorSet; cache::GraphicsPipelineCache::CompiledPipeline pipeline; + vk::Extent2D imageDimensions; DrawState(GPU &gpu, blit::VertexPushConstantLayout vertexPushConstants, blit::FragmentPushConstantLayout fragmentPushConstants, - cache::GraphicsPipelineCache::CompiledPipeline pipeline) + cache::GraphicsPipelineCache::CompiledPipeline pipeline, + vk::Extent2D imageDimensions) : vertexPushConstants{vertexPushConstants}, fragmentPushConstants{fragmentPushConstants}, descriptorSet{gpu.descriptor.AllocateSet(pipeline.descriptorSetLayout)}, - pipeline{pipeline} {} + pipeline{pipeline}, + imageDimensions{imageDimensions} {} }; auto drawState{std::make_shared( @@ -252,11 +255,13 @@ namespace skyline::gpu { .dstSrcScaleFactor = {dstSrcScaleFactorX * (srcRect.width / srcImageDimensions.width), dstSrcScaleFactorY * (srcRect.height / srcImageDimensions.height)}, .srcHeightRecip = 1.0f / srcImageDimensions.height }, - GetPipeline(gpu, dstImageView, - nullptr, false, false, 0, - vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, - {blit::SamplerLayoutBinding}, blit::PushConstantRanges)) - }; + GetPipeline(gpu, + {dstImageView->format->vkFormat, + vk::Format::eUndefined, false, false, 0, + VkColorComponentFlags{vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA}}, + {blit::SamplerLayoutBinding}, blit::PushConstantRanges), + dstImageDimensions + )}; vk::DescriptorImageInfo imageInfo{ .imageLayout = vk::ImageLayout::eGeneral, @@ -276,7 +281,23 @@ namespace skyline::gpu { recordCb([drawState = std::move(drawState)](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &gpu, vk::RenderPass, u32) { cycle->AttachObject(drawState); - commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, drawState->pipeline.pipeline); + + vk::Viewport viewport{ + .height = static_cast(drawState->imageDimensions.height), + .width = static_cast(drawState->imageDimensions.width), + .x = 0.0f, + .y = 0.0f, + .minDepth = 0.0f, + .maxDepth = 1.0f + }; + + vk::Rect2D scissor{ + .extent = drawState->imageDimensions + }; + + commandBuffer.setScissor(0, {scissor}); + commandBuffer.setViewport(0, {viewport}); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *drawState->pipeline.pipeline.get()); commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, drawState->pipeline.pipelineLayout, 0, *drawState->descriptorSet, nullptr); commandBuffer.pushConstants(drawState->pipeline.pipelineLayout, vk::ShaderStageFlagBits::eVertex, 0, vk::ArrayProxy{drawState->vertexPushConstants}); @@ -311,12 +332,15 @@ namespace skyline::gpu { struct DrawState { clear::FragmentPushConstantLayout fragmentPushConstants; cache::GraphicsPipelineCache::CompiledPipeline pipeline; + vk::Extent2D imageDimensions; DrawState(GPU &gpu, clear::FragmentPushConstantLayout fragmentPushConstants, - cache::GraphicsPipelineCache::CompiledPipeline pipeline) + cache::GraphicsPipelineCache::CompiledPipeline pipeline, + vk::Extent2D imageDimensions) : fragmentPushConstants{fragmentPushConstants}, - pipeline{pipeline} {} + pipeline{pipeline}, + imageDimensions{imageDimensions} {} }; bool writeColor{mask & vk::ImageAspectFlagBits::eColor}; @@ -330,12 +354,35 @@ namespace skyline::gpu { .clearDepth = (mask & vk::ImageAspectFlagBits::eDepth) != vk::ImageAspectFlags{}, .depth = value.depthStencil.depth }, - GetPipeline(gpu, writeColor ? dstImageView : nullptr, (writeDepth || writeStencil) ? dstImageView : nullptr, writeDepth, writeStencil, value.depthStencil.stencil, components, {}, clear::PushConstantRanges)) - }; + GetPipeline(gpu, + {writeColor ? dstImageView->format->vkFormat : vk::Format::eUndefined, + (writeDepth || writeStencil) ? dstImageView->format->vkFormat : vk::Format::eUndefined, + writeDepth, writeStencil, + value.depthStencil.stencil, + VkColorComponentFlags{components}}, + {}, clear::PushConstantRanges), + dstImageView->texture->dimensions + )}; recordCb([drawState = std::move(drawState)](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &gpu, vk::RenderPass, u32) { cycle->AttachObject(drawState); - commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, drawState->pipeline.pipeline); + + vk::Viewport viewport{ + .height = static_cast(drawState->imageDimensions.height), + .width = static_cast(drawState->imageDimensions.width), + .x = 0.0f, + .y = 0.0f, + .minDepth = 0.0f, + .maxDepth = 1.0f + }; + + vk::Rect2D scissor{ + .extent = drawState->imageDimensions + }; + + commandBuffer.setScissor(0, {scissor}); + commandBuffer.setViewport(0, {viewport}); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *drawState->pipeline.pipeline.get()); commandBuffer.pushConstants(drawState->pipeline.pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, vk::ArrayProxy{drawState->fragmentPushConstants}); commandBuffer.draw(6, 1, 0, 0); diff --git a/app/src/main/cpp/skyline/gpu/shaders/helper_shaders.h b/app/src/main/cpp/skyline/gpu/shaders/helper_shaders.h index 5c8330e4..b7a26593 100644 --- a/app/src/main/cpp/skyline/gpu/shaders/helper_shaders.h +++ b/app/src/main/cpp/skyline/gpu/shaders/helper_shaders.h @@ -20,6 +20,21 @@ namespace skyline::gpu { */ class SimpleSingleRtShader { protected: + /** + * @brief Holds all per-pipeline state for a helper shader + */ + struct PipelineState { + vk::Format colorFormat; + vk::Format depthFormat; + bool depthWrite; + bool stencilWrite; + u32 stencilValue; + VkColorComponentFlags colorWriteMask; + + bool operator<=>(const PipelineState &) const = default; + }; + + std::unordered_map> pipelineCache; vk::raii::ShaderModule vertexShaderModule; vk::raii::ShaderModule fragmentShaderModule; @@ -31,9 +46,7 @@ namespace skyline::gpu { * @brief Returns a potentially cached pipeline built according to the supplied input state */ cache::GraphicsPipelineCache::CompiledPipeline GetPipeline(GPU &gpu, - TextureView *colorAttachment, TextureView *depthStenilAttachment, - bool depthWrite, bool stencilWrite, u32 stencilValue, - vk::ColorComponentFlags colorWriteMask, + const PipelineState &state, span layoutBindings, span pushConstantRanges); };