/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "vk/GrVkPipelineStateBuilder.h" #include "GrShaderCaps.h" #include "vk/GrVkDescriptorSetManager.h" #include "vk/GrVkGpu.h" #include "vk/GrVkRenderPass.h" GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState( GrVkGpu* gpu, const GrPipeline& pipeline, const GrStencilSettings& stencil, const GrPrimitiveProcessor& primProc, GrPrimitiveType primitiveType, const GrVkPipelineState::Desc& desc, const GrVkRenderPass& renderPass) { // create a builder. This will be handed off to effects so they can use it to add // uniforms, varyings, textures, etc GrVkPipelineStateBuilder builder(gpu, pipeline, primProc, desc); GrGLSLExpr4 inputColor; GrGLSLExpr4 inputCoverage; if (!builder.emitAndInstallProcs(&inputColor, &inputCoverage)) { builder.cleanupFragmentProcessors(); return nullptr; } return builder.finalize(stencil, primitiveType, renderPass, desc); } GrVkPipelineStateBuilder::GrVkPipelineStateBuilder(GrVkGpu* gpu, const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, const GrProgramDesc& desc) : INHERITED(pipeline, primProc, desc) , fGpu(gpu) , fVaryingHandler(this) , fUniformHandler(this) { } const GrCaps* GrVkPipelineStateBuilder::caps() const { return fGpu->caps(); } void GrVkPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) { outputColor.addLayoutQualifier("location = 0, index = 0"); } void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) { outputColor.addLayoutQualifier("location = 0, index = 1"); } bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage, const GrGLSLShaderBuilder& builder, VkShaderModule* shaderModule, VkPipelineShaderStageCreateInfo* stageInfo, const SkSL::Program::Settings& settings) { SkString shaderString; for (int i = 0; i < builder.fCompilerStrings.count(); ++i) { if (builder.fCompilerStrings[i]) { shaderString.append(builder.fCompilerStrings[i]); shaderString.append("\n"); } } SkSL::Program::Inputs inputs; bool result = GrCompileVkShaderModule(fGpu, shaderString.c_str(), stage, shaderModule, stageInfo, settings, &inputs); if (!result) { return false; } if (inputs.fRTHeight) { this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); } return result; } GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil, GrPrimitiveType primitiveType, const GrVkRenderPass& renderPass, const GrVkPipelineState::Desc& desc) { VkDescriptorSetLayout dsLayout[2]; VkPipelineLayout pipelineLayout; VkShaderModule vertShaderModule; VkShaderModule fragShaderModule; GrVkResourceProvider& resourceProvider = fGpu->resourceProvider(); // These layouts are not owned by the PipelineStateBuilder and thus should not be destroyed dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout(); GrVkDescriptorSetManager::Handle samplerDSHandle; resourceProvider.getSamplerDescriptorSetHandle(fUniformHandler, &samplerDSHandle); dsLayout[GrVkUniformHandler::kSamplerDescSet] = resourceProvider.getSamplerDSLayout(samplerDSHandle); // Create the VkPipelineLayout VkPipelineLayoutCreateInfo layoutCreateInfo; memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags)); layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; layoutCreateInfo.pNext = 0; layoutCreateInfo.flags = 0; layoutCreateInfo.setLayoutCount = 2; layoutCreateInfo.pSetLayouts = dsLayout; layoutCreateInfo.pushConstantRangeCount = 0; layoutCreateInfo.pPushConstantRanges = nullptr; GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), CreatePipelineLayout(fGpu->device(), &layoutCreateInfo, nullptr, &pipelineLayout)); // We need to enable the following extensions so that the compiler can correctly make spir-v // from our glsl shaders. fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n"); fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n"); fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n"); fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n"); this->finalizeShaders(); VkPipelineShaderStageCreateInfo shaderStageInfo[2]; SkSL::Program::Settings settings; settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin; SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT, fVS, &vertShaderModule, &shaderStageInfo[0], settings)); // TODO: geometry shader support. SkASSERT(!this->primitiveProcessor().willUseGeoShader()); SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, fFS, &fragShaderModule, &shaderStageInfo[1], settings)); GrVkPipeline* pipeline = resourceProvider.createPipeline(fPipeline, stencil, fPrimProc, shaderStageInfo, 2, primitiveType, renderPass, pipelineLayout); GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), vertShaderModule, nullptr)); GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), fragShaderModule, nullptr)); if (!pipeline) { GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineLayout(fGpu->device(), pipelineLayout, nullptr)); this->cleanupFragmentProcessors(); return nullptr; } return new GrVkPipelineState(fGpu, desc, pipeline, pipelineLayout, samplerDSHandle, fUniformHandles, fUniformHandler.fUniforms, fUniformHandler.fCurrentVertexUBOOffset, fUniformHandler.fCurrentFragmentUBOOffset, (uint32_t)fUniformHandler.numSamplers(), fGeometryProcessor, fXferProcessor, fFragmentProcessors); }