/* * Created on: Oct 3, 2019 Copyright 2019 flyinghead This file is part of Flycast. Flycast is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Flycast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Flycast. If not, see . */ #include "pipeline.h" #include "hw/pvr/Renderer_if.h" #include "rend/osd.h" #include "quad.h" void PipelineManager::CreateModVolPipeline(ModVolMode mode) { // Vertex input state vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo; // Input assembly state vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo; if (mode == ModVolMode::Final) { pipelineVertexInputStateCreateInfo = GetMainVertexInputStateCreateInfo(false); pipelineInputAssemblyStateCreateInfo = vk::PipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleStrip); } else { static const vk::VertexInputBindingDescription vertexBindingDescriptions[] = { { 0, sizeof(float) * 3 }, }; static const vk::VertexInputAttributeDescription vertexInputAttributeDescriptions[] = { vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, 0), // pos }; pipelineVertexInputStateCreateInfo = vk::PipelineVertexInputStateCreateInfo( vk::PipelineVertexInputStateCreateFlags(), ARRAY_SIZE(vertexBindingDescriptions), vertexBindingDescriptions, ARRAY_SIZE(vertexInputAttributeDescriptions), vertexInputAttributeDescriptions); pipelineInputAssemblyStateCreateInfo = vk::PipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleList); } // Viewport and scissor states vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr); // Rasterization and multisample states vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo ( vk::PipelineRasterizationStateCreateFlags(), // flags false, // depthClampEnable false, // rasterizerDiscardEnable vk::PolygonMode::eFill, // polygonMode vk::CullModeFlagBits::eNone, // cullMode vk::FrontFace::eCounterClockwise, // frontFace false, // depthBiasEnable 0.0f, // depthBiasConstantFactor 0.0f, // depthBiasClamp 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil vk::StencilOpState stencilOpState; switch (mode) { case ModVolMode::Xor: stencilOpState = vk::StencilOpState(vk::StencilOp::eKeep, vk::StencilOp::eInvert, vk::StencilOp::eKeep, vk::CompareOp::eAlways, 0, 2, 2); break; case ModVolMode::Or: stencilOpState = vk::StencilOpState(vk::StencilOp::eKeep, vk::StencilOp::eReplace, vk::StencilOp::eKeep, vk::CompareOp::eAlways, 2, 2, 2); break; case ModVolMode::Inclusion: stencilOpState = vk::StencilOpState(vk::StencilOp::eZero, vk::StencilOp::eReplace, vk::StencilOp::eZero, vk::CompareOp::eLessOrEqual, 3, 3, 1); break; case ModVolMode::Exclusion: stencilOpState = vk::StencilOpState(vk::StencilOp::eZero, vk::StencilOp::eKeep, vk::StencilOp::eZero, vk::CompareOp::eEqual, 3, 3, 1); break; case ModVolMode::Final: stencilOpState = vk::StencilOpState(vk::StencilOp::eZero, vk::StencilOp::eZero, vk::StencilOp::eZero, vk::CompareOp::eEqual, 0x81, 3, 0x81); break; } vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo ( vk::PipelineDepthStencilStateCreateFlags(), // flags mode == ModVolMode::Xor || mode == ModVolMode::Or, // depthTestEnable false, // depthWriteEnable vk::CompareOp::eGreater, // depthCompareOp false, // depthBoundTestEnable true, // stencilTestEnable stencilOpState, // front stencilOpState // back ); // Color flags and blending vk::ColorComponentFlags colorComponentFlags( mode != ModVolMode::Final ? (vk::ColorComponentFlagBits)0 : vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA); vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState( mode == ModVolMode::Final, // blendEnable vk::BlendFactor::eSrcAlpha, // srcColorBlendFactor vk::BlendFactor::eOneMinusSrcAlpha, // dstColorBlendFactor vk::BlendOp::eAdd, // colorBlendOp vk::BlendFactor::eSrcAlpha, // srcAlphaBlendFactor vk::BlendFactor::eOneMinusSrcAlpha, // dstAlphaBlendFactor vk::BlendOp::eAdd, // alphaBlendOp colorComponentFlags // colorWriteMask ); vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo ( vk::PipelineColorBlendStateCreateFlags(), // flags false, // logicOpEnable vk::LogicOp::eNoOp, // logicOp 1, // attachmentCount &pipelineColorBlendAttachmentState, // pAttachments { { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants ); vk::DynamicState dynamicStates[2] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor }; vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), 2, dynamicStates); vk::ShaderModule vertex_module = shaderManager->GetModVolVertexShader(); vk::ShaderModule fragment_module = shaderManager->GetModVolShader(); vk::PipelineShaderStageCreateInfo stages[] = { { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertex_module, "main" }, { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, fragment_module, "main" }, }; vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo ( vk::PipelineCreateFlags(), // flags 2, // stageCount stages, // pStages &pipelineVertexInputStateCreateInfo, // pVertexInputState &pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState nullptr, // pTessellationState &pipelineViewportStateCreateInfo, // pViewportState &pipelineRasterizationStateCreateInfo, // pRasterizationState &pipelineMultisampleStateCreateInfo, // pMultisampleState &pipelineDepthStencilStateCreateInfo, // pDepthStencilState &pipelineColorBlendStateCreateInfo, // pColorBlendState &pipelineDynamicStateCreateInfo, // pDynamicState *pipelineLayout, // layout renderPass // renderPass ); if (modVolPipelines.empty()) modVolPipelines.resize((size_t)ModVolMode::Final + 1); modVolPipelines[(size_t)mode] = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo); } void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const PolyParam& pp) { vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetMainVertexInputStateCreateInfo(); // Input assembly state vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), sortTriangles && !settings.rend.PerStripSorting ? vk::PrimitiveTopology::eTriangleList : vk::PrimitiveTopology::eTriangleStrip); // Viewport and scissor states vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr); // Rasterization and multisample states vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo ( vk::PipelineRasterizationStateCreateFlags(), // flags false, // depthClampEnable false, // rasterizerDiscardEnable vk::PolygonMode::eFill, // polygonMode pp.isp.CullMode == 3 ? vk::CullModeFlagBits::eBack : pp.isp.CullMode == 2 ? vk::CullModeFlagBits::eFront : vk::CullModeFlagBits::eNone, // cullMode vk::FrontFace::eCounterClockwise, // frontFace false, // depthBiasEnable 0.0f, // depthBiasConstantFactor 0.0f, // depthBiasClamp 0.0f, // depthBiasSlopeFactor 1.0f // lineWidth ); vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil vk::CompareOp depthOp; if (listType == ListType_Punch_Through || sortTriangles) depthOp = vk::CompareOp::eGreaterOrEqual; else depthOp = depthOps[pp.isp.DepthMode]; bool depthWriteEnable; if (sortTriangles && !settings.rend.PerStripSorting) depthWriteEnable = false; else { // Z Write Disable seems to be ignored for punch-through. // Fixes Worms World Party, Bust-a-Move 4 and Re-Volt if (listType == ListType_Punch_Through) depthWriteEnable = true; else depthWriteEnable = !pp.isp.ZWriteDis; } bool shadowed = (listType == ListType_Opaque || listType == ListType_Punch_Through) && pp.pcw.Shadow != 0; vk::StencilOpState stencilOpState; if (shadowed) stencilOpState = vk::StencilOpState(vk::StencilOp::eKeep, vk::StencilOp::eReplace, vk::StencilOp::eKeep, vk::CompareOp::eAlways, 0, 0x80, 0x80); else stencilOpState = vk::StencilOpState(vk::StencilOp::eKeep, vk::StencilOp::eKeep, vk::StencilOp::eKeep, vk::CompareOp::eAlways); vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo ( vk::PipelineDepthStencilStateCreateFlags(), // flags true, // depthTestEnable depthWriteEnable, // depthWriteEnable depthOp, // depthCompareOp false, // depthBoundTestEnable shadowed, // stencilTestEnable stencilOpState, // front stencilOpState // back ); // Color flags and blending vk::ColorComponentFlags colorComponentFlags(vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA); vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState; // Apparently punch-through polys support blending, or at least some combinations if (listType == ListType_Translucent || listType == ListType_Punch_Through) { u32 src = pp.tsp.SrcInstr; u32 dst = pp.tsp.DstInstr; pipelineColorBlendAttachmentState = { true, // blendEnable getBlendFactor(src, true), // srcColorBlendFactor getBlendFactor(dst, false), // dstColorBlendFactor vk::BlendOp::eAdd, // colorBlendOp getBlendFactor(src, true), // srcAlphaBlendFactor getBlendFactor(dst, false), // dstAlphaBlendFactor vk::BlendOp::eAdd, // alphaBlendOp colorComponentFlags // colorWriteMask }; } else { pipelineColorBlendAttachmentState = { false, // blendEnable vk::BlendFactor::eZero, // srcColorBlendFactor vk::BlendFactor::eZero, // dstColorBlendFactor vk::BlendOp::eAdd, // colorBlendOp vk::BlendFactor::eZero, // srcAlphaBlendFactor vk::BlendFactor::eZero, // dstAlphaBlendFactor vk::BlendOp::eAdd, // alphaBlendOp colorComponentFlags // colorWriteMask }; } vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo ( vk::PipelineColorBlendStateCreateFlags(), // flags false, // logicOpEnable vk::LogicOp::eNoOp, // logicOp 1, // attachmentCount &pipelineColorBlendAttachmentState, // pAttachments { { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants ); vk::DynamicState dynamicStates[2] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor }; vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), 2, dynamicStates); vk::ShaderModule vertex_module = shaderManager->GetVertexShader(VertexShaderParams{ pp.pcw.Gouraud == 1 }); FragmentShaderParams params = {}; params.alphaTest = listType == ListType_Punch_Through; params.bumpmap = pp.tcw.PixelFmt == PixelBumpMap; params.clamping = pp.tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff); params.insideClipTest = (pp.tileclip >> 28) == 3; params.fog = settings.rend.Fog ? pp.tsp.FogCtrl : 2; params.gouraud = pp.pcw.Gouraud; params.ignoreTexAlpha = pp.tsp.IgnoreTexA; params.offset = pp.pcw.Offset; params.shaderInstr = pp.tsp.ShadInstr; params.texture = pp.pcw.Texture; params.trilinear = pp.pcw.Texture && pp.tsp.FilterMode > 1 && listType != ListType_Punch_Through; params.useAlpha = pp.tsp.UseAlpha; vk::ShaderModule fragment_module = shaderManager->GetFragmentShader(params); vk::PipelineShaderStageCreateInfo stages[] = { { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertex_module, "main" }, { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, fragment_module, "main" }, }; vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo ( vk::PipelineCreateFlags(), // flags 2, // stageCount stages, // pStages &pipelineVertexInputStateCreateInfo, // pVertexInputState &pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState nullptr, // pTessellationState &pipelineViewportStateCreateInfo, // pViewportState &pipelineRasterizationStateCreateInfo, // pRasterizationState &pipelineMultisampleStateCreateInfo, // pMultisampleState &pipelineDepthStencilStateCreateInfo, // pDepthStencilState &pipelineColorBlendStateCreateInfo, // pColorBlendState &pipelineDynamicStateCreateInfo, // pDynamicState *pipelineLayout, // layout renderPass // renderPass ); pipelines[hash(listType, sortTriangles, &pp)] = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo); } void QuadPipeline::CreatePipeline() { vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetQuadInputStateCreateInfo(true); // Input assembly state vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleStrip); // Viewport and scissor states vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr); // Rasterization and multisample states vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo; pipelineRasterizationStateCreateInfo.lineWidth = 1.0; vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo; // Color flags and blending vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState( true, // blendEnable vk::BlendFactor::eConstantAlpha, // srcColorBlendFactor vk::BlendFactor::eOneMinusConstantAlpha, // dstColorBlendFactor vk::BlendOp::eAdd, // colorBlendOp vk::BlendFactor::eConstantAlpha, // srcAlphaBlendFactor vk::BlendFactor::eOneMinusConstantAlpha, // dstAlphaBlendFactor vk::BlendOp::eAdd, // alphaBlendOp vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA ); vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo ( vk::PipelineColorBlendStateCreateFlags(), // flags false, // logicOpEnable vk::LogicOp::eNoOp, // logicOp 1, // attachmentCount &pipelineColorBlendAttachmentState, // pAttachments { { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants ); vk::DynamicState dynamicStates[] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor, vk::DynamicState::eBlendConstants }; vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), ARRAY_SIZE(dynamicStates), dynamicStates); vk::PipelineShaderStageCreateInfo stages[] = { { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, shaderManager->GetQuadVertexShader(), "main" }, { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, shaderManager->GetQuadFragmentShader(), "main" }, }; vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo ( vk::PipelineCreateFlags(), // flags 2, // stageCount stages, // pStages &pipelineVertexInputStateCreateInfo, // pVertexInputState &pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState nullptr, // pTessellationState &pipelineViewportStateCreateInfo, // pViewportState &pipelineRasterizationStateCreateInfo, // pRasterizationState &pipelineMultisampleStateCreateInfo, // pMultisampleState &pipelineDepthStencilStateCreateInfo, // pDepthStencilState &pipelineColorBlendStateCreateInfo, // pColorBlendState &pipelineDynamicStateCreateInfo, // pDynamicState *pipelineLayout, // layout renderPass // renderPass ); pipeline = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo); } void OSDPipeline::CreatePipeline() { // Vertex input state static const vk::VertexInputBindingDescription vertexBindingDescriptions[] = { { 0, sizeof(OSDVertex) }, }; static const vk::VertexInputAttributeDescription vertexInputAttributeDescriptions[] = { vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32Sfloat, offsetof(OSDVertex, x)), // pos vk::VertexInputAttributeDescription(1, 0, vk::Format::eR8G8B8A8Uint, offsetof(OSDVertex, r)), // color vk::VertexInputAttributeDescription(2, 0, vk::Format::eR32G32Sfloat, offsetof(OSDVertex, u)), // tex coord }; vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo( vk::PipelineVertexInputStateCreateFlags(), ARRAY_SIZE(vertexBindingDescriptions), vertexBindingDescriptions, ARRAY_SIZE(vertexInputAttributeDescriptions), vertexInputAttributeDescriptions); // Input assembly state vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleStrip); // Viewport and scissor states vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr); // Rasterization and multisample states vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo; pipelineRasterizationStateCreateInfo.lineWidth = 1.0; vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; // Depth and stencil vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo; // Color flags and blending vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState( true, // blendEnable vk::BlendFactor::eSrcAlpha, // srcColorBlendFactor vk::BlendFactor::eOneMinusSrcAlpha, // dstColorBlendFactor vk::BlendOp::eAdd, // colorBlendOp vk::BlendFactor::eSrcAlpha, // srcAlphaBlendFactor vk::BlendFactor::eOneMinusSrcAlpha, // dstAlphaBlendFactor vk::BlendOp::eAdd, // alphaBlendOp vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA ); vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo ( vk::PipelineColorBlendStateCreateFlags(), // flags false, // logicOpEnable vk::LogicOp::eNoOp, // logicOp 1, // attachmentCount &pipelineColorBlendAttachmentState, // pAttachments { { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants ); vk::DynamicState dynamicStates[] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor }; vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), ARRAY_SIZE(dynamicStates), dynamicStates); vk::PipelineShaderStageCreateInfo stages[] = { { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, shaderManager->GetOSDVertexShader(), "main" }, { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, shaderManager->GetOSDFragmentShader(), "main" }, }; vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo ( vk::PipelineCreateFlags(), // flags 2, // stageCount stages, // pStages &vertexInputStateCreateInfo, // pVertexInputState &pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState nullptr, // pTessellationState &pipelineViewportStateCreateInfo, // pViewportState &pipelineRasterizationStateCreateInfo, // pRasterizationState &pipelineMultisampleStateCreateInfo, // pMultisampleState &pipelineDepthStencilStateCreateInfo, // pDepthStencilState &pipelineColorBlendStateCreateInfo, // pColorBlendState &pipelineDynamicStateCreateInfo, // pDynamicState *pipelineLayout, // layout renderPass // renderPass ); pipeline = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo); }