/* * 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 "GrContext.h" #include "GrContextPriv.h" #include "GrShaderCaps.h" #include "GrStencilSettings.h" #include "GrVkRenderTarget.h" #include "vk/GrVkDescriptorSetManager.h" #include "vk/GrVkGpu.h" #include "vk/GrVkRenderPass.h" GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState( GrVkGpu* gpu, const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, const GrStencilSettings& stencil, GrPrimitiveType primitiveType, 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); if (!builder.emitAndInstallProcs()) { return nullptr; } return builder.finalize(stencil, primitiveType, renderPass, desc); } GrVkPipelineStateBuilder::GrVkPipelineStateBuilder(GrVkGpu* gpu, const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc, GrProgramDesc* desc) : INHERITED(primProc, pipeline, 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, Desc* desc) { 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); } if (inputs.fFlipY) { desc->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin( this->pipeline().proxy()->origin())); desc->finalize(); } return result; } GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil, GrPrimitiveType primitiveType, const GrVkRenderPass& renderPass, Desc* desc) { VkDescriptorSetLayout dsLayout[2]; VkPipelineLayout pipelineLayout; VkShaderModule vertShaderModule = VK_NULL_HANDLE; VkShaderModule geomShaderModule = VK_NULL_HANDLE; VkShaderModule fragShaderModule = VK_NULL_HANDLE; 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(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 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[3]; SkSL::Program::Settings settings; settings.fCaps = this->caps()->shaderCaps(); settings.fFlipY = this->pipeline().proxy()->origin() != kTopLeft_GrSurfaceOrigin; settings.fSharpenTextures = this->gpu()->getContext()->contextPriv().sharpenMipmappedTextures(); SkASSERT(!this->fragColorIsInOut()); SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT, fVS, &vertShaderModule, &shaderStageInfo[0], settings, desc)); SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, fFS, &fragShaderModule, &shaderStageInfo[1], settings, desc)); int numShaderStages = 2; // We always have at least vertex and fragment stages. if (this->primitiveProcessor().willUseGeoShader()) { SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT, fGS, &geomShaderModule, &shaderStageInfo[2], settings, desc)); ++numShaderStages; } GrVkPipeline* pipeline = resourceProvider.createPipeline(fPrimProc, fPipeline, stencil, shaderStageInfo, numShaderStages, primitiveType, renderPass, pipelineLayout); GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), vertShaderModule, nullptr)); GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), fragShaderModule, nullptr)); // This if check should not be needed since calling destroy on a VK_NULL_HANDLE is allowed. // However this is causing a crash in certain drivers (e.g. NVidia). if (this->primitiveProcessor().willUseGeoShader()) { GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), geomShaderModule, nullptr)); } if (!pipeline) { GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineLayout(fGpu->device(), pipelineLayout, nullptr)); return nullptr; } return new GrVkPipelineState(fGpu, pipeline, pipelineLayout, samplerDSHandle, fUniformHandles, fUniformHandler.fUniforms, fUniformHandler.fCurrentGeometryUBOOffset, fUniformHandler.fCurrentFragmentUBOOffset, (uint32_t)fUniformHandler.numSamplers(), std::move(fGeometryProcessor), std::move(fXferProcessor), std::move(fFragmentProcessors), fFragmentProcessorCnt); } ////////////////////////////////////////////////////////////////////////////// uint32_t get_blend_info_key(const GrPipeline& pipeline) { GrXferProcessor::BlendInfo blendInfo; pipeline.getXferProcessor().getBlendInfo(&blendInfo); static const uint32_t kBlendWriteShift = 1; static const uint32_t kBlendCoeffShift = 5; GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << kBlendCoeffShift)); GR_STATIC_ASSERT(kFirstAdvancedGrBlendEquation - 1 < 4); uint32_t key = blendInfo.fWriteColor; key |= (blendInfo.fSrcBlend << kBlendWriteShift); key |= (blendInfo.fDstBlend << (kBlendWriteShift + kBlendCoeffShift)); key |= (blendInfo.fEquation << (kBlendWriteShift + 2 * kBlendCoeffShift)); return key; } bool GrVkPipelineStateBuilder::Desc::Build(Desc* desc, const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, const GrStencilSettings& stencil, GrPrimitiveType primitiveType, const GrShaderCaps& caps) { if (!INHERITED::Build(desc, primProc, primitiveType == GrPrimitiveType::kPoints, pipeline, caps)) { return false; } GrProcessorKeyBuilder b(&desc->key()); GrVkRenderTarget* vkRT = (GrVkRenderTarget*)pipeline.renderTarget(); vkRT->simpleRenderPass()->genKey(&b); stencil.genKey(&b); b.add32(get_blend_info_key(pipeline)); b.add32((uint32_t)primitiveType); return true; }