mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-03-04 12:17:16 +00:00
VulkanRenderManager: Add deferred pipeline creation (to get it off the CPU thread)
This commit is contained in:
parent
be152acf7b
commit
62f4875e24
@ -841,9 +841,11 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) {
|
||||
case VKRRenderCommand::REMOVED:
|
||||
INFO_LOG(G3D, " (Removed)");
|
||||
break;
|
||||
|
||||
case VKRRenderCommand::BIND_PIPELINE:
|
||||
INFO_LOG(G3D, " BindPipeline(%x)", (int)(intptr_t)cmd.pipeline.pipeline);
|
||||
case VKRRenderCommand::BIND_GRAPHICS_PIPELINE:
|
||||
INFO_LOG(G3D, " BindGraphicsPipeline(%x)", (int)(intptr_t)cmd.graphics_pipeline.pipeline);
|
||||
break;
|
||||
case VKRRenderCommand::BIND_COMPUTE_PIPELINE:
|
||||
INFO_LOG(G3D, " BindComputePipeline(%x)", (int)(intptr_t)cmd.compute_pipeline.pipeline);
|
||||
break;
|
||||
case VKRRenderCommand::BLEND:
|
||||
INFO_LOG(G3D, " BlendColor(%08x)", cmd.blendColor.color);
|
||||
@ -1236,6 +1238,9 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
|
||||
VKRFramebuffer *fb = step.render.framebuffer;
|
||||
|
||||
VkPipeline lastGraphicsPipeline = VK_NULL_HANDLE;
|
||||
VkPipeline lastComputePipeline = VK_NULL_HANDLE;
|
||||
|
||||
auto &commands = step.commands;
|
||||
|
||||
// We can do a little bit of state tracking here to eliminate some calls into the driver.
|
||||
@ -1251,16 +1256,54 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
case VKRRenderCommand::REMOVED:
|
||||
break;
|
||||
|
||||
// Still here to support binding of non-async pipelines.
|
||||
case VKRRenderCommand::BIND_PIPELINE:
|
||||
if (c.pipeline.pipeline != lastPipeline) {
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.pipeline.pipeline);
|
||||
lastPipeline = c.pipeline.pipeline;
|
||||
{
|
||||
VkPipeline pipeline = c.pipeline.pipeline;
|
||||
if (pipeline != lastGraphicsPipeline) {
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
lastGraphicsPipeline = pipeline;
|
||||
// Reset dynamic state so it gets refreshed with the new pipeline.
|
||||
lastStencilWriteMask = -1;
|
||||
lastStencilCompareMask = -1;
|
||||
lastStencilReference = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VKRRenderCommand::BIND_GRAPHICS_PIPELINE:
|
||||
{
|
||||
VKRGraphicsPipeline *pipeline = c.graphics_pipeline.pipeline;
|
||||
if (!pipeline->pipeline) {
|
||||
// Late! Compile it.
|
||||
if (!pipeline->Create(vulkan_))
|
||||
break;
|
||||
}
|
||||
if (pipeline->pipeline != lastGraphicsPipeline) {
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline);
|
||||
lastGraphicsPipeline = pipeline->pipeline;
|
||||
// Reset dynamic state so it gets refreshed with the new pipeline.
|
||||
lastStencilWriteMask = -1;
|
||||
lastStencilCompareMask = -1;
|
||||
lastStencilReference = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VKRRenderCommand::BIND_COMPUTE_PIPELINE:
|
||||
{
|
||||
VKRComputePipeline *pipeline = c.compute_pipeline.pipeline;
|
||||
if (!pipeline->pipeline) {
|
||||
// Late! Compile it.
|
||||
if (!pipeline->Create(vulkan_))
|
||||
break;
|
||||
}
|
||||
if (pipeline->pipeline != lastComputePipeline) {
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline);
|
||||
lastComputePipeline = pipeline->pipeline;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VKRRenderCommand::VIEWPORT:
|
||||
if (fb != nullptr) {
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "Common/GPU/DataFormat.h"
|
||||
|
||||
class VKRFramebuffer;
|
||||
struct VKRGraphicsPipeline;
|
||||
struct VKRComputePipeline;
|
||||
struct VKRImage;
|
||||
|
||||
enum {
|
||||
@ -20,7 +22,9 @@ enum {
|
||||
|
||||
enum class VKRRenderCommand : uint8_t {
|
||||
REMOVED,
|
||||
BIND_PIPELINE,
|
||||
BIND_PIPELINE, // raw pipeline
|
||||
BIND_GRAPHICS_PIPELINE, // async
|
||||
BIND_COMPUTE_PIPELINE, // async
|
||||
STENCIL,
|
||||
BLEND,
|
||||
VIEWPORT,
|
||||
@ -45,6 +49,12 @@ struct VkRenderData {
|
||||
struct {
|
||||
VkPipeline pipeline;
|
||||
} pipeline;
|
||||
struct {
|
||||
VKRGraphicsPipeline *pipeline;
|
||||
} graphics_pipeline;
|
||||
struct {
|
||||
VKRComputePipeline *pipeline;
|
||||
} compute_pipeline;
|
||||
struct {
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkDescriptorSet ds;
|
||||
|
@ -22,6 +22,43 @@
|
||||
|
||||
using namespace PPSSPP_VK;
|
||||
|
||||
bool VKRGraphicsPipeline::Create(VulkanContext *vulkan) {
|
||||
if (!desc) {
|
||||
// Already failed to create this one.
|
||||
return false;
|
||||
}
|
||||
VkResult result = vkCreateGraphicsPipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &desc->pipe, nullptr, &pipeline);
|
||||
delete desc;
|
||||
desc = nullptr;
|
||||
if (result == VK_INCOMPLETE) {
|
||||
// Bad return value seen on Adreno in Burnout :( Try to ignore?
|
||||
// Create a placeholder to avoid creating over and over if something is broken.
|
||||
pipeline = VK_NULL_HANDLE;
|
||||
return true;
|
||||
} else if (result != VK_SUCCESS) {
|
||||
pipeline = VK_NULL_HANDLE;
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool VKRComputePipeline::Create(VulkanContext *vulkan) {
|
||||
if (!desc) {
|
||||
// Already failed to create this one.
|
||||
return false;
|
||||
}
|
||||
VkResult result = vkCreateComputePipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &desc->pipe, nullptr, &pipeline);
|
||||
delete desc;
|
||||
desc = nullptr;
|
||||
if (result != VK_SUCCESS) {
|
||||
pipeline = VK_NULL_HANDLE;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height, const char *tag) : vulkan_(vk) {
|
||||
width = _width;
|
||||
height = _height;
|
||||
|
@ -109,6 +109,46 @@ struct BoundingRect {
|
||||
}
|
||||
};
|
||||
|
||||
// All the data needed to create a graphics pipeline.
|
||||
struct VKRGraphicsPipelineDesc {
|
||||
VkPipelineCache pipelineCache = VK_NULL_HANDLE;
|
||||
VkPipelineColorBlendStateCreateInfo cbs{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
|
||||
VkPipelineColorBlendAttachmentState blend0{};
|
||||
VkPipelineDepthStencilStateCreateInfo dss{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
|
||||
VkDynamicState dynamicStates[6]{};
|
||||
VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
|
||||
VkPipelineShaderStageCreateInfo shaderStageInfo[2]{};
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
|
||||
VkVertexInputAttributeDescription attrs[8]{};
|
||||
VkVertexInputBindingDescription ibd{};
|
||||
VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
|
||||
VkPipelineViewportStateCreateInfo views{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
|
||||
VkGraphicsPipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
|
||||
};
|
||||
|
||||
// All the data needed to create a compute pipeline.
|
||||
struct VKRComputePipelineDesc {
|
||||
VkPipelineCache pipelineCache;
|
||||
VkComputePipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
|
||||
};
|
||||
|
||||
// Wrapped pipeline, which will later allow for background compilation while emulating the rest of the frame.
|
||||
struct VKRGraphicsPipeline {
|
||||
VKRGraphicsPipelineDesc *desc = nullptr; // While non-zero, is pending and pipeline isn't valid.
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
|
||||
bool Create(VulkanContext *vulkan);
|
||||
};
|
||||
|
||||
struct VKRComputePipeline {
|
||||
VKRComputePipelineDesc *desc = nullptr;
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
|
||||
bool Create(VulkanContext *vulkan);
|
||||
};
|
||||
|
||||
class VulkanRenderManager {
|
||||
public:
|
||||
VulkanRenderManager(VulkanContext *vulkan);
|
||||
@ -152,6 +192,14 @@ public:
|
||||
void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag);
|
||||
void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag);
|
||||
|
||||
// Deferred creation, like in GL. Unlike GL though, the purpose is to allow background creation and avoiding
|
||||
// stalling the emulation thread as much as possible.
|
||||
VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc) {
|
||||
VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline();
|
||||
pipeline->desc = desc;
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
void BindPipeline(VkPipeline pipeline, PipelineFlags flags) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
_dbg_assert_(pipeline != VK_NULL_HANDLE);
|
||||
@ -161,6 +209,24 @@ public:
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
_dbg_assert_(pipeline != nullptr);
|
||||
VkRenderData data{ VKRRenderCommand::BIND_GRAPHICS_PIPELINE };
|
||||
data.graphics_pipeline.pipeline = pipeline;
|
||||
curPipelineFlags_ |= flags;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void BindPipeline(VKRComputePipeline *pipeline, PipelineFlags flags) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
_dbg_assert_(pipeline != nullptr);
|
||||
VkRenderData data{ VKRRenderCommand::BIND_COMPUTE_PIPELINE };
|
||||
data.compute_pipeline.pipeline = pipeline;
|
||||
curPipelineFlags_ |= flags;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void SetViewport(const VkViewport &vp) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
_dbg_assert_((int)vp.width >= 0);
|
||||
|
@ -826,7 +826,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
|
||||
Draw::NativeObject object = framebufferManager_->UseBufferedRendering() ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
|
||||
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, true);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, true);
|
||||
if (!pipeline || !pipeline->pipeline) {
|
||||
// Already logged, let's bail out.
|
||||
return;
|
||||
@ -957,7 +957,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
}
|
||||
Draw::NativeObject object = framebufferManager_->UseBufferedRendering() ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
|
||||
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, false);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, false);
|
||||
if (!pipeline || !pipeline->pipeline) {
|
||||
// Already logged, let's bail out.
|
||||
return;
|
||||
|
@ -34,8 +34,10 @@ void PipelineManagerVulkan::Clear() {
|
||||
// store the keys.
|
||||
|
||||
pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) {
|
||||
if (value->pipeline)
|
||||
vulkan_->Delete().QueueDeletePipeline(value->pipeline);
|
||||
if (value->pipeline) {
|
||||
vulkan_->Delete().QueueDeletePipeline(value->pipeline->pipeline);
|
||||
delete value->pipeline;
|
||||
}
|
||||
delete value;
|
||||
});
|
||||
|
||||
@ -163,13 +165,16 @@ static std::string CutFromMain(std::string str) {
|
||||
return rebuilt;
|
||||
}
|
||||
|
||||
static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pipelineCache,
|
||||
static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache,
|
||||
VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &key,
|
||||
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
|
||||
VKRGraphicsPipelineDesc *desc = new VKRGraphicsPipelineDesc();
|
||||
desc->pipelineCache = pipelineCache;
|
||||
|
||||
PROFILE_THIS_SCOPE("pipelinebuild");
|
||||
bool useBlendConstant = false;
|
||||
|
||||
VkPipelineColorBlendAttachmentState blend0{};
|
||||
VkPipelineColorBlendAttachmentState &blend0 = desc->blend0;
|
||||
blend0.blendEnable = key.blendEnable;
|
||||
if (key.blendEnable) {
|
||||
blend0.colorBlendOp = (VkBlendOp)key.blendOpColor;
|
||||
@ -181,7 +186,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
}
|
||||
blend0.colorWriteMask = key.colorWriteMask;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo cbs{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
|
||||
VkPipelineColorBlendStateCreateInfo &cbs = desc->cbs;
|
||||
cbs.flags = 0;
|
||||
cbs.pAttachments = &blend0;
|
||||
cbs.attachmentCount = 1;
|
||||
@ -191,7 +196,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
else
|
||||
cbs.logicOp = VK_LOGIC_OP_COPY;
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo dss{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
|
||||
VkPipelineDepthStencilStateCreateInfo &dss = desc->dss;
|
||||
dss.depthBoundsTestEnable = false;
|
||||
dss.stencilTestEnable = key.stencilTestEnable;
|
||||
if (key.stencilTestEnable) {
|
||||
@ -208,7 +213,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
dss.depthWriteEnable = key.depthWriteEnable;
|
||||
}
|
||||
|
||||
VkDynamicState dynamicStates[8]{};
|
||||
VkDynamicState *dynamicStates = &desc->dynamicStates[0];
|
||||
int numDyn = 0;
|
||||
if (key.blendEnable &&
|
||||
(UsesBlendConstant(key.srcAlpha) || UsesBlendConstant(key.srcColor) || UsesBlendConstant(key.destAlpha) || UsesBlendConstant(key.destColor))) {
|
||||
@ -223,12 +228,12 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
|
||||
}
|
||||
|
||||
VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
VkPipelineDynamicStateCreateInfo &ds = desc->ds;
|
||||
ds.flags = 0;
|
||||
ds.pDynamicStates = dynamicStates;
|
||||
ds.dynamicStateCount = numDyn;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
VkPipelineRasterizationStateCreateInfo &rs = desc->rs;
|
||||
rs.flags = 0;
|
||||
rs.depthBiasEnable = false;
|
||||
rs.cullMode = key.cullMode;
|
||||
@ -238,11 +243,11 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
rs.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rs.depthClampEnable = key.depthClampEnable;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
|
||||
VkPipelineMultisampleStateCreateInfo &ms = desc->ms;
|
||||
ms.pSampleMask = nullptr;
|
||||
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineShaderStageCreateInfo ss[2]{};
|
||||
VkPipelineShaderStageCreateInfo *ss = &desc->shaderStageInfo[0];
|
||||
ss[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
ss[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
ss[0].pSpecializationInfo = nullptr;
|
||||
@ -265,13 +270,14 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
return nullPipeline;
|
||||
}
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
|
||||
VkPipelineInputAssemblyStateCreateInfo &inputAssembly = desc->inputAssembly;
|
||||
inputAssembly.flags = 0;
|
||||
inputAssembly.topology = (VkPrimitiveTopology)key.topology;
|
||||
inputAssembly.primitiveRestartEnable = false;
|
||||
int vertexStride = 0;
|
||||
|
||||
VkVertexInputAttributeDescription attrs[8];
|
||||
VkVertexInputAttributeDescription *attrs = &desc->attrs[0];
|
||||
|
||||
int attributeCount;
|
||||
if (useHwTransform) {
|
||||
attributeCount = SetupVertexAttribs(attrs, *decFmt);
|
||||
@ -284,66 +290,49 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
vertexStride = (int)sizeof(TransformedVertex);
|
||||
}
|
||||
|
||||
VkVertexInputBindingDescription ibd{};
|
||||
VkVertexInputBindingDescription &ibd = desc->ibd;
|
||||
ibd.binding = 0;
|
||||
ibd.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
ibd.stride = vertexStride;
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
|
||||
VkPipelineVertexInputStateCreateInfo &vis = desc->vis;
|
||||
vis.flags = 0;
|
||||
vis.vertexBindingDescriptionCount = 1;
|
||||
vis.pVertexBindingDescriptions = &ibd;
|
||||
vis.pVertexBindingDescriptions = &desc->ibd;
|
||||
vis.vertexAttributeDescriptionCount = attributeCount;
|
||||
vis.pVertexAttributeDescriptions = attrs;
|
||||
|
||||
VkPipelineViewportStateCreateInfo views{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
|
||||
VkPipelineViewportStateCreateInfo &views = desc->views;
|
||||
views.flags = 0;
|
||||
views.viewportCount = 1;
|
||||
views.scissorCount = 1;
|
||||
views.pViewports = nullptr; // dynamic
|
||||
views.pScissors = nullptr; // dynamic
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
|
||||
VkGraphicsPipelineCreateInfo &pipe = desc->pipe;
|
||||
pipe.flags = 0;
|
||||
pipe.stageCount = 2;
|
||||
pipe.pStages = ss;
|
||||
pipe.basePipelineIndex = 0;
|
||||
|
||||
pipe.pColorBlendState = &cbs;
|
||||
pipe.pDepthStencilState = &dss;
|
||||
pipe.pRasterizationState = &rs;
|
||||
pipe.pColorBlendState = &desc->cbs;
|
||||
pipe.pDepthStencilState = &desc->dss;
|
||||
pipe.pRasterizationState = &desc->rs;
|
||||
|
||||
// We will use dynamic viewport state.
|
||||
pipe.pVertexInputState = &vis;
|
||||
pipe.pViewportState = &views;
|
||||
pipe.pVertexInputState = &desc->vis;
|
||||
pipe.pViewportState = &desc->views;
|
||||
pipe.pTessellationState = nullptr;
|
||||
pipe.pDynamicState = &ds;
|
||||
pipe.pInputAssemblyState = &inputAssembly;
|
||||
pipe.pMultisampleState = &ms;
|
||||
pipe.pDynamicState = &desc->ds;
|
||||
pipe.pInputAssemblyState = &desc->inputAssembly;
|
||||
pipe.pMultisampleState = &desc->ms;
|
||||
pipe.layout = layout;
|
||||
pipe.basePipelineHandle = VK_NULL_HANDLE;
|
||||
pipe.basePipelineIndex = 0;
|
||||
pipe.renderPass = renderPass;
|
||||
pipe.subpass = 0;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline);
|
||||
if (result != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
|
||||
if (result == VK_INCOMPLETE) {
|
||||
// Typical Adreno return value. It'll usually also log something vague, like "Failed to link shaders".
|
||||
// Let's log some stuff and try to stumble along.
|
||||
ERROR_LOG(G3D, "VS source code:\n%s\n", CutFromMain(vs->GetShaderString(SHADER_STRING_SOURCE_CODE)).c_str());
|
||||
ERROR_LOG(G3D, "FS source code:\n%s\n", CutFromMain(fs->GetShaderString(SHADER_STRING_SOURCE_CODE)).c_str());
|
||||
} else {
|
||||
_dbg_assert_msg_(false, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
|
||||
}
|
||||
// Create a placeholder to avoid creating over and over if something is broken.
|
||||
VulkanPipeline *nullPipeline = new VulkanPipeline();
|
||||
nullPipeline->pipeline = VK_NULL_HANDLE;
|
||||
nullPipeline->flags = 0;
|
||||
return nullPipeline;
|
||||
}
|
||||
VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc);
|
||||
|
||||
VulkanPipeline *vulkanPipeline = new VulkanPipeline();
|
||||
vulkanPipeline->pipeline = pipeline;
|
||||
@ -358,7 +347,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
return vulkanPipeline;
|
||||
}
|
||||
|
||||
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
|
||||
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
|
||||
if (!pipelineCache_) {
|
||||
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
||||
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
|
||||
@ -380,7 +369,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo
|
||||
return iter;
|
||||
|
||||
VulkanPipeline *pipeline = CreateVulkanPipeline(
|
||||
vulkan_->GetDevice(), pipelineCache_, layout, renderPass,
|
||||
renderManager, pipelineCache_, layout, renderPass,
|
||||
rasterKey, decFmt, vs, fs, useHwTransform);
|
||||
pipelines_.Insert(key, pipeline);
|
||||
|
||||
@ -772,7 +761,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha
|
||||
|
||||
DecVtxFormat fmt;
|
||||
fmt.InitializeFromID(key.vtxFmtId);
|
||||
VulkanPipeline *pipeline = GetOrCreatePipeline(layout, rp, key.raster,
|
||||
VulkanPipeline *pipeline = GetOrCreatePipeline(rm, layout, rp, key.raster,
|
||||
key.useHWTransform ? &fmt : 0,
|
||||
vs, fs, key.useHWTransform);
|
||||
if (!pipeline) {
|
||||
|
@ -25,9 +25,11 @@
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
#include "GPU/Vulkan/StateMappingVulkan.h"
|
||||
|
||||
#include "GPU/Vulkan/VulkanQueueRunner.h"
|
||||
|
||||
struct VKRGraphicsPipeline;
|
||||
class VulkanRenderManager;
|
||||
|
||||
struct VulkanPipelineKey {
|
||||
VulkanPipelineRasterStateKey raster; // prim is included here
|
||||
VkRenderPass renderPass;
|
||||
@ -48,7 +50,7 @@ struct VulkanPipelineKey {
|
||||
|
||||
// Simply wraps a Vulkan pipeline, providing some metadata.
|
||||
struct VulkanPipeline {
|
||||
VkPipeline pipeline;
|
||||
VKRGraphicsPipeline *pipeline;
|
||||
int flags; // PipelineFlags enum above.
|
||||
|
||||
bool UsesBlendConstant() const { return (flags & PIPELINE_FLAG_USES_BLEND_CONSTANT) != 0; }
|
||||
@ -67,7 +69,7 @@ public:
|
||||
PipelineManagerVulkan(VulkanContext *ctx);
|
||||
~PipelineManagerVulkan();
|
||||
|
||||
VulkanPipeline *GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform);
|
||||
VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform);
|
||||
int GetNumPipelines() const { return (int)pipelines_.size(); }
|
||||
|
||||
void Clear();
|
||||
|
Loading…
x
Reference in New Issue
Block a user