mirror of
https://github.com/libretro/parallel-dc.git
synced 2026-11-10 11:21:28 -10:00
The start waits, on the pipeline thread, for every fixed pipeline the first frame needs, so no frame makes one or waits for one. A device without VK_EXT_extended_dynamic_state or _state3 has the general pipeline of every fixed state a draw can reach made then too: Prepare() runs Key() over the drawer's draws and every value of the fields it reads. Where they are too many for the start (neither extension), those of earlier runs are made, until the blend is folded. HDR output's post effects are made with it, not in the frame they first turn on. The quads' pipelines are dropped before the drawers' render passes go: the pipeline thread could make one with a render pass already destroyed. tools/vulkan/vk_draw_path.sh runs every renderer on every test disc cold, without each dynamic state and with HDR output, and fails on a pipeline made in retro_run (CI). VKH_HIDE_EXT takes a list. The Direct3D tests give each test disc its own directory: their tracks share names, and every disc ran the last one made.
894 lines
41 KiB
C++
894 lines
41 KiB
C++
#define PVR_REGS_FOR_RENDERER // see hw/pvr/pvr_regs.h
|
|
/*
|
|
Created on: Nov 6, 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "oit_pipeline.h"
|
|
#include "../quad.h"
|
|
#include <algorithm>
|
|
|
|
static vk::CullModeFlags CullMode(u32 cull)
|
|
{
|
|
return cull == 2 ? vk::CullModeFlagBits::eBack : cull == 1 ? vk::CullModeFlagBits::eFront : vk::CullModeFlagBits::eNone;
|
|
}
|
|
|
|
// a key's stencil state: none, or the shadow bit set or cleared
|
|
static vk::StencilOpState StencilState(u32 stencil)
|
|
{
|
|
if (stencil == 1)
|
|
return vk::StencilOpState(vk::StencilOp::eKeep, vk::StencilOp::eReplace, vk::StencilOp::eKeep, vk::CompareOp::eAlways, 0, 0x80, 0x80);
|
|
if (stencil == 2)
|
|
return vk::StencilOpState(vk::StencilOp::eKeep, vk::StencilOp::eReplace, vk::StencilOp::eKeep, vk::CompareOp::eAlways, 0, 0x80, 0);
|
|
return vk::StencilOpState(vk::StencilOp::eKeep, vk::StencilOp::eKeep, vk::StencilOp::eKeep, vk::CompareOp::eNever);
|
|
}
|
|
|
|
u64 OITPipelineManager::Key(u32 listType, bool autosort, const PolyParam& pp, Pass pass) const
|
|
{
|
|
// the shader
|
|
OITShaderManager::FragmentShaderParams params = {};
|
|
params.alphaTest = listType == ListType_Punch_Through;
|
|
params.bumpmap = pp.tcw.PixelFmt == PixelBumpMap;
|
|
/* By the polygon alone. The clamping limits were looked at too, to leave
|
|
* the clamp out of the shader while they clamp nothing - but a pipeline
|
|
* is made once and kept under a key that has only the polygon's bit in
|
|
* it, and the limits change: a polygon first drawn while they clamped
|
|
* nothing was never clamped after. (Upstream: Red Dog.) */
|
|
params.clamping = pp.tsp.ColorClamp;
|
|
params.insideClipTest = (pp.tileclip >> 28) == 3;
|
|
params.fog = pp.tsp.FogCtrl;
|
|
params.ignoreTexAlpha = pp.tsp.IgnoreTexA || pp.tcw.PixelFmt == Pixel565;
|
|
params.offset = pp.pcw.Offset;
|
|
params.shaderInstr = pp.tsp.ShadInstr;
|
|
params.texture = pp.pcw.Texture;
|
|
params.useAlpha = pp.tsp.UseAlpha;
|
|
params.twoVolume = pp.tsp1.full != (u32)-1 || pp.tcw1.full != (u32)-1;
|
|
params.palette = BaseTextureCacheData::IsGpuHandledPaletted(pp.tsp, pp.tcw);
|
|
u64 key = (u32)params.key() | ((u64)pp.pcw.Gouraud << KEY_GOURAUD) | ((u64)pass << KEY_PASS);
|
|
/* SSAA: shaded at each sample, but for what is drawn at a single
|
|
* rate; and a translucent fragment put in the lists once a pixel,
|
|
* with the samples it covers, so the lists are no longer for it */
|
|
if (renderPasses->GetSamples() > 1)
|
|
key |= (u64)(pass != Pass::OIT && !SsaaSingleRate(pp) ? 1 : 2) << KEY_RATE;
|
|
key |= (u64)(pass == Pass::Depth ? (listType == ListType_Translucent ? 2 : 0) : 1) << KEY_SUBPASS;
|
|
|
|
// the fixed functions
|
|
key |= (u64)(pp.isp.CullMode == 3 ? 2 : pp.isp.CullMode == 2 ? 1 : 0) << KEY_CULL;
|
|
vk::CompareOp depthOp;
|
|
if (pass == Pass::Color && !pp.isp.ZWriteDis && listType != ListType_Translucent)
|
|
depthOp = vk::CompareOp::eEqual;
|
|
else if (listType == ListType_Punch_Through || autosort)
|
|
depthOp = vk::CompareOp::eGreaterOrEqual;
|
|
else
|
|
depthOp = depthOps[pp.isp.DepthMode];
|
|
bool depthWriteEnable;
|
|
/* Depth is written in the depth pass. In the colour pass the depth buffer
|
|
* is read-only - it is an input to the shaders there - and depth writes
|
|
* are not allowed. For opaque and punch-through polygons there is nothing
|
|
* to write anyway: they are drawn where their depth is the one the depth
|
|
* pass left, so a write would put the same value back.
|
|
*
|
|
* Translucent polygons that are not sorted are the exception. They are
|
|
* drawn in the colour pass only, in order, each tested against the depth
|
|
* the ones before it wrote, so they still write. So does everything on
|
|
* Intel, which is the driver bug workaround this condition came with. */
|
|
const bool colourPassWrites = pass == Pass::Color
|
|
&& (GetContext()->GetVendorID() == VENDOR_INTEL
|
|
|| (!autosort && listType == ListType_Translucent));
|
|
if (pass != Pass::Depth && !colourPassWrites)
|
|
depthWriteEnable = false;
|
|
// Z Write Disable seems to be ignored for punch-through.
|
|
// Fixes Worms World Party, Bust-a-Move 4 and Re-Volt
|
|
else if (listType == ListType_Punch_Through)
|
|
depthWriteEnable = true;
|
|
else
|
|
depthWriteEnable = !pp.isp.ZWriteDis;
|
|
const bool shadowed = pass == Pass::Depth && (listType == ListType_Opaque || listType == ListType_Punch_Through);
|
|
key |= ((u64)depthWriteEnable << KEY_ZWRITE) | ((u64)depthOp << KEY_DEPTH_OP)
|
|
| ((u64)(shadowed ? (pp.pcw.Shadow != 0 ? 1 : 2) : 0) << KEY_STENCIL);
|
|
// Apparently punch-through polys support blending, or at least some combinations
|
|
if (listType == ListType_Punch_Through || pass == Pass::Color)
|
|
key |= (1ull << KEY_BLEND) | (1ull << KEY_COLOR_WRITE) | ((u64)pp.tsp.SrcInstr << KEY_SRC) | ((u64)pp.tsp.DstInstr << KEY_DST);
|
|
|
|
return key;
|
|
}
|
|
|
|
OITPsoChoice OITPipelineManager::Choose(u64 key)
|
|
{
|
|
if (key == lastKey)
|
|
return lastChoice;
|
|
VkPsoWorker& worker = VkPsoWorker::Instance();
|
|
PsoSlot *slot = pipelines.Find(key);
|
|
if (slot == nullptr && worker.Running() && !PsoTestGeneral)
|
|
{
|
|
// its own pipeline, asked for now; drawn with the general one until it is made
|
|
slot = pipelines.Insert(key);
|
|
if (slot != nullptr)
|
|
{
|
|
worker.Request(slot);
|
|
GetContext()->PsoKeys().Record(who, key);
|
|
}
|
|
}
|
|
if (PsoReady(slot))
|
|
{
|
|
lastKey = key;
|
|
lastChoice = { slot->pipeline, key, false };
|
|
return lastChoice;
|
|
}
|
|
const u64 generalKey = GeneralKey(key);
|
|
PsoSlot *slotGeneral = general.Find(generalKey);
|
|
if (slotGeneral == nullptr)
|
|
{
|
|
/* A device that cannot set this polygon's depth, stencil or blend
|
|
* states with the draw, and a general pipeline for them not made
|
|
* when the renderer started: made now, the draw waiting for it */
|
|
slotGeneral = general.Insert(generalKey);
|
|
if (slotGeneral != nullptr)
|
|
VkPsoWorker::BuildSync(slotGeneral, GetContext()->GetPipelineCache());
|
|
}
|
|
if (slotGeneral == nullptr)
|
|
return { VK_NULL_HANDLE, key, false };
|
|
if (PsoReady(slotGeneral))
|
|
return { slotGeneral->pipeline, key, true };
|
|
// (one handed to the worker at the start, not made yet: taken, made or waited for)
|
|
const VkPipeline general = VkPsoWorker::Need(slotGeneral);
|
|
return { general, key, general != VK_NULL_HANDLE };
|
|
}
|
|
|
|
void OITPipelineManager::SetDynamicState(vk::CommandBuffer cmdBuffer, u64 key) const
|
|
{
|
|
const pso_ext::Functions& f = GetContext()->DynamicState();
|
|
const VkCommandBuffer cmd = (VkCommandBuffer)cmdBuffer;
|
|
if (f.depthStencil)
|
|
{
|
|
f.CmdSetCullMode(cmd, (VkCullModeFlags)CullMode((key >> KEY_CULL) & 3));
|
|
f.CmdSetPrimitiveTopology(cmd, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
|
f.CmdSetDepthTestEnable(cmd, VK_TRUE);
|
|
f.CmdSetDepthWriteEnable(cmd, (VkBool32)((key >> KEY_ZWRITE) & 1));
|
|
f.CmdSetDepthCompareOp(cmd, (VkCompareOp)((key >> KEY_DEPTH_OP) & 7));
|
|
const u32 stencil = (key >> KEY_STENCIL) & 3;
|
|
const vk::StencilOpState state = StencilState(stencil);
|
|
f.CmdSetStencilTestEnable(cmd, stencil != 0);
|
|
f.CmdSetStencilOp(cmd, VK_STENCIL_FACE_FRONT_AND_BACK, (VkStencilOp)state.failOp, (VkStencilOp)state.passOp,
|
|
(VkStencilOp)state.depthFailOp, (VkCompareOp)state.compareOp);
|
|
cmdBuffer.setStencilCompareMask(vk::StencilFaceFlagBits::eVkStencilFrontAndBack, state.compareMask);
|
|
cmdBuffer.setStencilWriteMask(vk::StencilFaceFlagBits::eVkStencilFrontAndBack, state.writeMask);
|
|
cmdBuffer.setStencilReference(vk::StencilFaceFlagBits::eVkStencilFrontAndBack, state.reference);
|
|
}
|
|
if (f.blend)
|
|
{
|
|
const VkBool32 enable = (VkBool32)((key >> KEY_BLEND) & 1);
|
|
f.CmdSetColorBlendEnable(cmd, 0, 1, &enable);
|
|
pso_ext::ColorBlendEquation equation = {};
|
|
equation.colorBlendOp = VK_BLEND_OP_ADD;
|
|
equation.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
if (enable)
|
|
{
|
|
equation.srcColorBlendFactor = equation.srcAlphaBlendFactor = (VkBlendFactor)getBlendFactor((key >> KEY_SRC) & 7, true);
|
|
equation.dstColorBlendFactor = equation.dstAlphaBlendFactor = (VkBlendFactor)getBlendFactor((key >> KEY_DST) & 7, false);
|
|
}
|
|
f.CmdSetColorBlendEquation(cmd, 0, 1, &equation);
|
|
const VkColorComponentFlags writeMask = ((key >> KEY_COLOR_WRITE) & 1)
|
|
? VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT : 0;
|
|
f.CmdSetColorWriteMask(cmd, 0, 1, &writeMask);
|
|
}
|
|
}
|
|
|
|
void OITPipelineManager::Reset()
|
|
{
|
|
// (nothing of it is to be made any more; what is being made, finished)
|
|
NewGeneration();
|
|
VkPsoWorker::Instance().EndBatch(this);
|
|
VkPsoWorker::Instance().WaitIdle();
|
|
if (GetContext() != nullptr && GetContext()->GetDevice())
|
|
{
|
|
vk::Device device = GetContext()->GetDevice();
|
|
pipelines.Clear(device);
|
|
general.Clear(device);
|
|
for (PsoSlot& slot : fixedSlots)
|
|
{
|
|
if (slot.pipeline != VK_NULL_HANDLE)
|
|
device.destroyPipeline(vk::Pipeline(slot.pipeline));
|
|
slot.pipeline = VK_NULL_HANDLE;
|
|
slot.owner = nullptr;
|
|
}
|
|
}
|
|
lastKey = ~0ull;
|
|
prepared = false;
|
|
}
|
|
|
|
void OITPipelineManager::Prepare()
|
|
{
|
|
VkPsoWorker& worker = VkPsoWorker::Instance();
|
|
const u32 samples = renderPasses->GetSamples();
|
|
/* (taken here: the render passes are made when first asked for, which
|
|
* is not something two threads may do at once) */
|
|
renderPass = renderPasses->GetRenderPass(true, true);
|
|
std::vector<PsoSlot *> now;
|
|
auto addGeneral = [&](u64 key) {
|
|
const u64 generalKey = GeneralKey(key);
|
|
if (general.Find(generalKey) == nullptr)
|
|
{
|
|
PsoSlot *slot = general.Insert(generalKey);
|
|
if (slot != nullptr)
|
|
now.push_back(slot);
|
|
}
|
|
};
|
|
auto fits = [&](u64 key) {
|
|
const u32 rate = (key >> KEY_RATE) & 3;
|
|
return ((key >> KEY_KIND) & 15) == KIND_POLY && (samples > 1 ? rate == 1 || rate == 2 : rate == 0);
|
|
};
|
|
/* The fixed ones first: every frame draws with them */
|
|
const pso_ext::Functions& dynamic = GetContext()->DynamicState();
|
|
cullSetter = dynamic.depthStencil ? dynamic.CmdSetCullMode : nullptr;
|
|
cullKept = cullSetter != nullptr ? 0 : 3;
|
|
for (u32 i = 0; i < FIXED_COUNT; i++)
|
|
{
|
|
// (with the cull mode dynamic, the modifier volumes' none ones draw them all)
|
|
if (i < FIXED_FINAL && cullSetter != nullptr && i % 3 != 0)
|
|
continue;
|
|
if (i == FIXED_FINAL_PER_SAMPLE && samples <= 1)
|
|
continue;
|
|
if (i == FIXED_FINAL_SUMS && !sums)
|
|
continue;
|
|
PsoSlot& slot = fixedSlots[i];
|
|
slot.key = ((u64)KIND_FIXED << KEY_KIND) | i;
|
|
slot.owner = this;
|
|
slot.pipeline = VK_NULL_HANDLE;
|
|
now.push_back(&slot);
|
|
}
|
|
/* The general pipelines: of each module and subpass, and of each fixed
|
|
* state the device must have made with them. The depth pass draws the
|
|
* opaque polygons in subpass 0, the translucent ones in 2; the colour
|
|
* pass and the lists are in 1. */
|
|
for (u64 gouraud = 0; gouraud < 2; gouraud++)
|
|
for (u64 pass = 0; pass < 3; pass++)
|
|
for (u64 subpass = 0; subpass < 3; subpass++)
|
|
{
|
|
if ((pass == (u64)Pass::Depth) != (subpass != 1))
|
|
continue;
|
|
for (u64 rate = samples > 1 ? 1 : 0; rate <= (samples > 1 ? 2u : 0u); rate++)
|
|
{
|
|
if (pass == (u64)Pass::OIT && rate == 1)
|
|
continue;
|
|
addGeneral((gouraud << KEY_GOURAUD) | (rate << KEY_RATE) | (pass << KEY_PASS) | (subpass << KEY_SUBPASS));
|
|
}
|
|
}
|
|
if (!dynamic.depthStencil || !dynamic.blend)
|
|
{
|
|
std::vector<u64> reach;
|
|
/* A device that has a general pipeline for each fixed state: one for
|
|
* every state a draw can reach, worked out by Key() itself from the
|
|
* draws the drawer makes (each list in each pass it is drawn in) and
|
|
* every value of the fields it reads */
|
|
static const struct { u32 list; bool autosort; Pass pass; } draws[] = {
|
|
{ ListType_Opaque, false, Pass::Depth }, { ListType_Punch_Through, false, Pass::Depth },
|
|
{ ListType_Opaque, false, Pass::Color }, { ListType_Punch_Through, false, Pass::Color },
|
|
{ ListType_Translucent, true, Pass::OIT }, { ListType_Translucent, false, Pass::Color },
|
|
{ ListType_Translucent, false, Pass::Depth }, { ListType_Translucent, true, Pass::Depth },
|
|
};
|
|
const u64 kept = DEPTH_STENCIL_BITS | BLEND_BITS | (3ull << KEY_PASS) | (3ull << KEY_SUBPASS);
|
|
for (const auto& d : draws)
|
|
for (u32 bits = 0; bits < (1u << 13); bits++)
|
|
{
|
|
PolyParam pp = {};
|
|
pp.isp.CullMode = bits & 3;
|
|
pp.isp.DepthMode = (bits >> 2) & 7;
|
|
pp.isp.ZWriteDis = (bits >> 5) & 1;
|
|
pp.pcw.Shadow = (bits >> 6) & 1;
|
|
pp.tsp.SrcInstr = (bits >> 7) & 7;
|
|
pp.tsp.DstInstr = (bits >> 10) & 7;
|
|
pp.tsp1.full = (u32)-1;
|
|
pp.tcw1.full = (u32)-1;
|
|
const u64 fixed = Key(d.list, d.autosort, pp, d.pass) & kept;
|
|
for (u64 gouraud = 0; gouraud < 2; gouraud++)
|
|
for (u64 rate = samples > 1 ? 1 : 0; rate <= (samples > 1 ? 2u : 0u); rate++)
|
|
if (d.pass != Pass::OIT || rate != 1)
|
|
reach.push_back(GeneralKey(fixed | (gouraud << KEY_GOURAUD) | (rate << KEY_RATE)));
|
|
}
|
|
/* All made at the start, before the first frame. Where they are too
|
|
* many (a device with neither extension, the per-pixel renderer's
|
|
* passes: thousands, until the blend is folded as Direct3D 12's
|
|
* is), those of earlier runs are, and one not seen before is made
|
|
* when first drawn (VkPsoWorker::SyncBuilt() counts them) */
|
|
std::sort(reach.begin(), reach.end());
|
|
reach.erase(std::unique(reach.begin(), reach.end()), reach.end());
|
|
if (reach.size() <= PSO_GENERAL_AT_START)
|
|
for (u64 key : reach)
|
|
addGeneral(key);
|
|
else
|
|
{
|
|
WARN_LOG(RENDERER, "Vulkan: %u general pipelines a draw can reach, too many to make at the start",
|
|
(u32)reach.size());
|
|
GetContext()->PsoKeys().ForEach(who, [&](u64 key) { if (fits(key)) addGeneral(key); });
|
|
}
|
|
}
|
|
NOTICE_LOG(RENDERER, "Vulkan: %u general pipelines made at the start", general.Used());
|
|
worker.BuildSoon(now.data(), (u32)now.size(), GetContext()->GetPipelineCache());
|
|
/* The polygons' own pipelines made in earlier runs: asked for now, made
|
|
* while nothing more pressing is */
|
|
if (worker.Running())
|
|
GetContext()->PsoKeys().ForEach(who, [&](u64 key) {
|
|
if (fits(key) && pipelines.Find(key) == nullptr)
|
|
{
|
|
PsoSlot *slot = pipelines.Insert(key);
|
|
if (slot != nullptr)
|
|
worker.Prefetch(slot);
|
|
}
|
|
});
|
|
prepared = true;
|
|
}
|
|
|
|
VkPipeline OITPipelineManager::BuildPipeline(u64 key, vk::PipelineCache cache)
|
|
{
|
|
switch ((key >> KEY_KIND) & 15)
|
|
{
|
|
case KIND_POLY:
|
|
return BuildPoly(key, false, cache);
|
|
case KIND_GENERAL:
|
|
return BuildPoly(key, true, cache);
|
|
case KIND_FIXED:
|
|
{
|
|
const u32 i = (u32)(key & 0xff);
|
|
// (the modifier volumes': Xor, Or, Inclusion, Exclusion, by cull mode none, front, back)
|
|
if (i < FIXED_TRMODVOL)
|
|
return CreateModVolPipeline((ModVolMode)(i / 3), i % 3, cache);
|
|
if (i < FIXED_FINAL)
|
|
return CreateTrModVolPipeline((ModVolMode)((i - FIXED_TRMODVOL) / 3), (i - FIXED_TRMODVOL) % 3, cache);
|
|
if (i == FIXED_FINAL || i == FIXED_FINAL_PER_SAMPLE || i == FIXED_FINAL_SUMS)
|
|
return CreateFinalPipeline(i == FIXED_FINAL_PER_SAMPLE, i == FIXED_FINAL_SUMS, cache);
|
|
if (i == FIXED_CLEAR)
|
|
return CreateClearPipeline(cache);
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
default:
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
}
|
|
|
|
/* A polygon's pipeline, all of it from @key; @general: the one that draws
|
|
* for the keys that differ from it only in what the draw sets (pso.h) */
|
|
VkPipeline OITPipelineManager::BuildPoly(u64 key, bool general, vk::PipelineCache cache)
|
|
{
|
|
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetMainVertexInputStateCreateInfo();
|
|
|
|
// 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
|
|
(
|
|
vk::PipelineRasterizationStateCreateFlags(), // flags
|
|
false, // depthClampEnable
|
|
false, // rasterizerDiscardEnable
|
|
vk::PolygonMode::eFill, // polygonMode
|
|
CullMode((key >> KEY_CULL) & 3), // cullMode
|
|
vk::FrontFace::eCounterClockwise, // frontFace
|
|
false, // depthBiasEnable
|
|
0.0f, // depthBiasConstantFactor
|
|
0.0f, // depthBiasClamp
|
|
0.0f, // depthBiasSlopeFactor
|
|
1.0f // lineWidth
|
|
);
|
|
const u32 rate = (key >> KEY_RATE) & 3;
|
|
vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = SsaaMultisample(renderPasses->GetSamples(), rate == 1);
|
|
|
|
// Depth and stencil
|
|
const u32 stencil = (key >> KEY_STENCIL) & 3;
|
|
const vk::StencilOpState stencilOpState = StencilState(stencil);
|
|
vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo
|
|
(
|
|
vk::PipelineDepthStencilStateCreateFlags(), // flags
|
|
true, // depthTestEnable
|
|
(key >> KEY_ZWRITE) & 1, // depthWriteEnable
|
|
(vk::CompareOp)((key >> KEY_DEPTH_OP) & 7), // depthCompareOp
|
|
false, // depthBoundTestEnable
|
|
stencil != 0, // stencilTestEnable
|
|
stencilOpState, // front
|
|
stencilOpState // back
|
|
);
|
|
|
|
// Color flags and blending
|
|
vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState;
|
|
if ((key >> KEY_BLEND) & 1)
|
|
{
|
|
vk::ColorComponentFlags colorComponentFlags(vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA);
|
|
u32 src = (key >> KEY_SRC) & 7;
|
|
u32 dst = (key >> KEY_DST) & 7;
|
|
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
|
|
vk::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
|
|
);
|
|
|
|
// the general pipeline's states that are set with each draw (SetDynamicState())
|
|
vk::DynamicState dynamicStates[18] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor };
|
|
u32 dynamicCount = 2;
|
|
if (general)
|
|
{
|
|
const pso_ext::Functions& dynamic = GetContext()->DynamicState();
|
|
if (dynamic.depthStencil)
|
|
{
|
|
const int states[] = { pso_ext::DYNAMIC_STATE_CULL_MODE, pso_ext::DYNAMIC_STATE_PRIMITIVE_TOPOLOGY,
|
|
pso_ext::DYNAMIC_STATE_DEPTH_TEST_ENABLE, pso_ext::DYNAMIC_STATE_DEPTH_WRITE_ENABLE,
|
|
pso_ext::DYNAMIC_STATE_DEPTH_COMPARE_OP, pso_ext::DYNAMIC_STATE_STENCIL_TEST_ENABLE,
|
|
pso_ext::DYNAMIC_STATE_STENCIL_OP, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
|
|
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE };
|
|
for (int state : states)
|
|
dynamicStates[dynamicCount++] = (vk::DynamicState)state;
|
|
}
|
|
if (dynamic.blend)
|
|
{
|
|
const int states[] = { pso_ext::DYNAMIC_STATE_COLOR_BLEND_ENABLE, pso_ext::DYNAMIC_STATE_COLOR_BLEND_EQUATION,
|
|
pso_ext::DYNAMIC_STATE_COLOR_WRITE_MASK };
|
|
for (int state : states)
|
|
dynamicStates[dynamicCount++] = (vk::DynamicState)state;
|
|
}
|
|
}
|
|
vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), dynamicCount, dynamicStates);
|
|
|
|
const bool gouraud = (key >> KEY_GOURAUD) & 1;
|
|
vk::ShaderModule vertex_module = shaderManager->GetVertexShader(OITShaderManager::VertexShaderParams{ gouraud });
|
|
OITShaderManager::FragmentShaderParams params = {};
|
|
params.gouraud = gouraud;
|
|
params.pass = (Pass)((key >> KEY_PASS) & 3);
|
|
params.sampleRate = (int)rate;
|
|
vk::ShaderModule fragment_module = shaderManager->GetFragmentShader(params);
|
|
const PsoSpecialization specialization(general ? -1 : (s32)(key & ((1u << OIT_SC_BITS) - 1)), renderPasses->GetSamples());
|
|
|
|
vk::PipelineShaderStageCreateInfo stages[] = {
|
|
{ vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertex_module, "main" },
|
|
{ vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, fragment_module, "main", &specialization.info },
|
|
};
|
|
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
|
|
(u32)((key >> KEY_SUBPASS) & 3) // subpass
|
|
);
|
|
|
|
return PsoCreate(GetContext()->GetDevice(), cache, graphicsPipelineCreateInfo);
|
|
}
|
|
|
|
VkPipeline OITPipelineManager::CreateFinalPipeline(bool perSample, bool sums, vk::PipelineCache cache)
|
|
{
|
|
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetQuadInputStateCreateInfo(false);
|
|
|
|
// 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
|
|
(
|
|
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
|
|
);
|
|
// (SSAA: the last subpass is of single samples; the one before, which puts each sample together, of all of them)
|
|
vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = SsaaMultisample(perSample ? renderPasses->GetSamples() : 1, perSample);
|
|
|
|
// Depth and stencil
|
|
vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo;
|
|
|
|
// Color flags and blending
|
|
vk::ColorComponentFlags colorComponentFlags(vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA);
|
|
vk::PipelineColorBlendAttachmentState 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->GetFinalVertexShader();
|
|
vk::ShaderModule fragment_module = shaderManager->GetFinalShader(perSample, sums);
|
|
const PsoSpecialization specialization(0, renderPasses->GetSamples());
|
|
|
|
vk::PipelineShaderStageCreateInfo stages[] = {
|
|
{ vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertex_module, "main" },
|
|
{ vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, fragment_module, "main", &specialization.info },
|
|
};
|
|
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
|
|
perSample ? 2 : GetFinalSubpass() // subpass
|
|
);
|
|
|
|
return PsoCreate(GetContext()->GetDevice(), cache, graphicsPipelineCreateInfo);
|
|
|
|
}
|
|
|
|
VkPipeline OITPipelineManager::CreateClearPipeline(vk::PipelineCache cache)
|
|
{
|
|
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetQuadInputStateCreateInfo(false);
|
|
|
|
// 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
|
|
(
|
|
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::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo;
|
|
|
|
// Color flags and blending
|
|
vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState;
|
|
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->GetFinalVertexShader();
|
|
vk::ShaderModule fragment_module = shaderManager->GetClearShader();
|
|
|
|
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
|
|
GetFinalSubpass() // subpass
|
|
);
|
|
|
|
return PsoCreate(GetContext()->GetDevice(), cache, graphicsPipelineCreateInfo);
|
|
}
|
|
|
|
VkPipeline OITPipelineManager::CreateModVolPipeline(ModVolMode mode, u32 cull, vk::PipelineCache cache)
|
|
{
|
|
verify(mode != ModVolMode::Final);
|
|
|
|
static const vk::VertexInputBindingDescription vertexBindingDescriptions[] =
|
|
{
|
|
{ 0, sizeof(float) * 3 },
|
|
};
|
|
static const vk::VertexInputAttributeDescription vertexInputAttributeDescriptions[] =
|
|
{
|
|
vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, 0), // pos
|
|
};
|
|
// Vertex input state
|
|
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo(
|
|
vk::PipelineVertexInputStateCreateFlags(),
|
|
ARRAY_SIZE(vertexBindingDescriptions),
|
|
vertexBindingDescriptions,
|
|
ARRAY_SIZE(vertexInputAttributeDescriptions),
|
|
vertexInputAttributeDescriptions);
|
|
// Input assembly state
|
|
vk::PipelineInputAssemblyStateCreateInfo 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
|
|
CullMode(cull), // cullMode
|
|
vk::FrontFace::eCounterClockwise, // frontFace
|
|
false, // depthBiasEnable
|
|
0.0f, // depthBiasConstantFactor
|
|
0.0f, // depthBiasClamp
|
|
0.0f, // depthBiasSlopeFactor
|
|
1.0f // lineWidth
|
|
);
|
|
vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = SsaaMultisample(renderPasses->GetSamples(), false);
|
|
|
|
// 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;
|
|
default:
|
|
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::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState;
|
|
|
|
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
|
|
);
|
|
|
|
// (the cull mode set with the draws, where it can be: PsoCull)
|
|
vk::DynamicState dynamicStates[3] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor,
|
|
(vk::DynamicState)pso_ext::DYNAMIC_STATE_CULL_MODE };
|
|
vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(),
|
|
cullSetter != nullptr ? 3 : 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
|
|
0 // subpass
|
|
);
|
|
|
|
return PsoCreate(GetContext()->GetDevice(), cache, graphicsPipelineCreateInfo);
|
|
}
|
|
|
|
VkPipeline OITPipelineManager::CreateTrModVolPipeline(ModVolMode mode, u32 cull, vk::PipelineCache cache)
|
|
{
|
|
verify(mode != ModVolMode::Final);
|
|
|
|
static const vk::VertexInputBindingDescription vertexBindingDescriptions[] =
|
|
{
|
|
{ 0, sizeof(float) * 3 },
|
|
};
|
|
static const vk::VertexInputAttributeDescription vertexInputAttributeDescriptions[] =
|
|
{
|
|
vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, 0), // pos
|
|
};
|
|
// Vertex input state
|
|
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo(
|
|
vk::PipelineVertexInputStateCreateFlags(),
|
|
ARRAY_SIZE(vertexBindingDescriptions),
|
|
vertexBindingDescriptions,
|
|
ARRAY_SIZE(vertexInputAttributeDescriptions),
|
|
vertexInputAttributeDescriptions);
|
|
// Input assembly state
|
|
vk::PipelineInputAssemblyStateCreateInfo 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
|
|
CullMode(cull), // cullMode
|
|
vk::FrontFace::eCounterClockwise, // frontFace
|
|
false, // depthBiasEnable
|
|
0.0f, // depthBiasConstantFactor
|
|
0.0f, // depthBiasClamp
|
|
0.0f, // depthBiasSlopeFactor
|
|
1.0f // lineWidth
|
|
);
|
|
vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = SsaaMultisample(renderPasses->GetSamples(), false);
|
|
|
|
// Depth and stencil
|
|
vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo;
|
|
|
|
// Color flags and blending
|
|
vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState;
|
|
|
|
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
|
|
);
|
|
|
|
// (the cull mode set with the draws, where it can be: PsoCull)
|
|
vk::DynamicState dynamicStates[3] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor,
|
|
(vk::DynamicState)pso_ext::DYNAMIC_STATE_CULL_MODE };
|
|
vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(),
|
|
cullSetter != nullptr ? 3 : 2, dynamicStates);
|
|
|
|
vk::ShaderModule vertex_module = shaderManager->GetModVolVertexShader();
|
|
vk::ShaderModule fragment_module = shaderManager->GetTrModVolShader(mode);
|
|
|
|
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
|
|
2 // subpass
|
|
);
|
|
|
|
return PsoCreate(GetContext()->GetDevice(), cache, graphicsPipelineCreateInfo);
|
|
}
|