Index: src/gpu/vk/GrVkProgramBuilder.cpp |
diff --git a/src/gpu/vk/GrVkProgramBuilder.cpp b/src/gpu/vk/GrVkProgramBuilder.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..916b8c3b5f92546a846153e9ab954d7ee5720187 |
--- /dev/null |
+++ b/src/gpu/vk/GrVkProgramBuilder.cpp |
@@ -0,0 +1,323 @@ |
+/* |
+* 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/GrVkProgramBuilder.h" |
+ |
+#include "vk/GrVkGpu.h" |
+#include "vk/GrVkRenderPass.h" |
+#include "vk/GrVkProgram.h" |
+ |
+GrVkProgram* GrVkProgramBuilder::CreateProgram(GrVkGpu* gpu, |
+ const DrawArgs& args, |
+ GrPrimitiveType primitiveType, |
+ const GrVkRenderPass& renderPass) { |
+ // create a builder. This will be handed off to effects so they can use it to add |
+ // uniforms, varyings, textures, etc |
+ GrVkProgramBuilder builder(gpu, args); |
+ |
+ GrGLSLExpr4 inputColor; |
+ GrGLSLExpr4 inputCoverage; |
+ |
+ if (!builder.emitAndInstallProcs(&inputColor, |
+ &inputCoverage, |
+ gpu->vkCaps().maxSampledTextures())) { |
+ builder.cleanupFragmentProcessors(); |
+ return nullptr; |
+ } |
+ |
+ return builder.finalize(args, primitiveType, renderPass); |
+} |
+ |
+GrVkProgramBuilder::GrVkProgramBuilder(GrVkGpu* gpu, const DrawArgs& args) |
+ : INHERITED(args) |
+ , fGpu(gpu) |
+ , fVaryingHandler(this) |
+ , fUniformHandler(this) { |
+} |
+ |
+const GrCaps* GrVkProgramBuilder::caps() const { |
+ return fGpu->caps(); |
+} |
+const GrGLSLCaps* GrVkProgramBuilder::glslCaps() const { |
+ return fGpu->vkCaps().glslCaps(); |
+} |
+ |
+void GrVkProgramBuilder::finalizeFragmentOutputColor(GrGLSLShaderVar& outputColor) { |
+ outputColor.setLayoutQualifier("location = 0"); |
+} |
+ |
+void GrVkProgramBuilder::emitSamplers(const GrProcessor& processor, |
+ GrGLSLTextureSampler::TextureSamplerArray* outSamplers) { |
+ int numTextures = processor.numTextures(); |
+ UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures); |
+ SkString name; |
+ for (int t = 0; t < numTextures; ++t) { |
+ name.printf("%d", t); |
+ localSamplerUniforms[t] = |
+ fUniformHandler.addUniform(kFragment_GrShaderFlag, |
+ kSampler2D_GrSLType, kDefault_GrSLPrecision, |
+ name.c_str()); |
+ outSamplers->emplace_back(localSamplerUniforms[t], processor.textureAccess(t)); |
+ } |
+} |
+ |
+VkShaderStageFlags visibility_to_vk_stage_flags(uint32_t visibility) { |
+ VkShaderStageFlags flags = 0; |
+ |
+ if (visibility & kVertex_GrShaderFlag) { |
+ flags |= VK_SHADER_STAGE_VERTEX_BIT; |
+ } |
+ if (visibility & kGeometry_GrShaderFlag) { |
+ flags |= VK_SHADER_STAGE_GEOMETRY_BIT; |
+ } |
+ if (visibility & kFragment_GrShaderFlag) { |
+ flags |= VK_SHADER_STAGE_FRAGMENT_BIT; |
+ } |
+ return flags; |
+} |
+ |
+shaderc_shader_kind vk_shader_stage_to_shaderc_kind(VkShaderStageFlagBits stage) { |
+ if (VK_SHADER_STAGE_VERTEX_BIT == stage) { |
+ return shaderc_glsl_vertex_shader; |
+ } |
+ SkASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == stage); |
+ return shaderc_glsl_fragment_shader; |
+} |
+ |
+bool GrVkProgramBuilder::CreateVkShaderModule(const GrVkGpu* gpu, |
+ VkShaderStageFlagBits stage, |
+ const GrGLSLShaderBuilder& builder, |
+ VkShaderModule* shaderModule, |
+ VkPipelineShaderStageCreateInfo* stageInfo) { |
+ SkString shaderString; |
+ for (int i = 0; i < builder.fCompilerStrings.count(); ++i) { |
+ if (builder.fCompilerStrings[i]) { |
+ shaderString.append(builder.fCompilerStrings[i]); |
+ shaderString.append("\n"); |
+ } |
+ } |
+ |
+ shaderc_compiler_t compiler = gpu->shadercCompiler(); |
+ |
+ shaderc_compile_options_t options = shaderc_compile_options_initialize(); |
+ shaderc_compile_options_set_forced_version_profile(options, 140, shaderc_profile_none); |
+ |
+ shaderc_shader_kind shadercStage = vk_shader_stage_to_shaderc_kind(stage); |
+ shaderc_compilation_result_t result = shaderc_compile_into_spv(compiler, |
+ shaderString.c_str(), |
+ strlen(shaderString.c_str()), |
+ shadercStage, |
+ "shader", |
+ "main", |
+ options); |
+ shaderc_compile_options_release(options); |
+#ifdef SK_DEBUG |
+ if (shaderc_result_get_num_errors(result)) { |
+ SkDebugf("%s\n", shaderString.c_str()); |
+ SkDebugf("%s\n", shaderc_result_get_error_message(result)); |
+ return false; |
+ } |
+#endif |
+ |
+ VkShaderModuleCreateInfo moduleCreateInfo; |
+ memset(&moduleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo)); |
+ moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; |
+ moduleCreateInfo.pNext = nullptr; |
+ moduleCreateInfo.flags = 0; |
+ moduleCreateInfo.codeSize = shaderc_result_get_length(result); |
+ moduleCreateInfo.pCode = (const uint32_t*)shaderc_result_get_bytes(result); |
+ |
+ VkResult err = GR_VK_CALL(gpu->vkInterface(), CreateShaderModule(gpu->device(), |
+ &moduleCreateInfo, |
+ nullptr, |
+ shaderModule)); |
+ shaderc_result_release(result); |
+ if (err) { |
+ return false; |
+ } |
+ |
+ memset(stageInfo, 0, sizeof(VkPipelineShaderStageCreateInfo)); |
+ stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
+ stageInfo->pNext = nullptr; |
+ stageInfo->flags = 0; |
+ stageInfo->stage = stage; |
+ stageInfo->module = *shaderModule; |
+ stageInfo->pName = "main"; |
+ stageInfo->pSpecializationInfo = nullptr; |
+ |
+ return true; |
+} |
+ |
+GrVkProgram* GrVkProgramBuilder::finalize(const DrawArgs& args, |
+ GrPrimitiveType primitiveType, |
+ const GrVkRenderPass& renderPass) { |
+ VkDescriptorSetLayout dsLayout[2]; |
+ VkPipelineLayout pipelineLayout; |
+ VkShaderModule vertShaderModule; |
+ VkShaderModule fragShaderModule; |
+ |
+ uint32_t numSamplers = fSamplerUniforms.count(); |
+ |
+ SkAutoTDeleteArray<VkDescriptorSetLayoutBinding> dsSamplerBindings( |
+ new VkDescriptorSetLayoutBinding[numSamplers]); |
+ for (uint32_t i = 0; i < numSamplers; ++i) { |
+ UniformHandle uniHandle = fSamplerUniforms[i]; |
+ GrVkUniformHandler::UniformInfo uniformInfo = fUniformHandler.getUniformInfo(uniHandle); |
+ SkASSERT(kSampler2D_GrSLType == uniformInfo.fVariable.getType()); |
+ SkASSERT(0 == uniformInfo.fSetNumber); |
+ SkASSERT(uniformInfo.fBinding == i); |
+ dsSamplerBindings[i].binding = uniformInfo.fBinding; |
+ dsSamplerBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
+ dsSamplerBindings[i].descriptorCount = 1; |
+ dsSamplerBindings[i].stageFlags = visibility_to_vk_stage_flags(uniformInfo.fVisibility); |
+ dsSamplerBindings[i].pImmutableSamplers = nullptr; |
+ } |
+ |
+ VkDescriptorSetLayoutCreateInfo dsSamplerLayoutCreateInfo; |
+ memset(&dsSamplerLayoutCreateInfo, 0, sizeof(VkDescriptorSetLayoutCreateInfo)); |
+ dsSamplerLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; |
+ dsSamplerLayoutCreateInfo.pNext = nullptr; |
+ dsSamplerLayoutCreateInfo.flags = 0; |
+ dsSamplerLayoutCreateInfo.bindingCount = fSamplerUniforms.count(); |
+ // Setting to nullptr fixes an error in the param checker validation layer. Even though |
+ // bindingCount is 0 (which is valid), it still tries to validate pBindings unless it is null. |
+ dsSamplerLayoutCreateInfo.pBindings = fSamplerUniforms.count() ? dsSamplerBindings.get() : |
+ nullptr; |
+ |
+ GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), |
+ CreateDescriptorSetLayout(fGpu->device(), |
+ &dsSamplerLayoutCreateInfo, |
+ nullptr, |
+ &dsLayout[GrVkUniformHandler::kSamplerDescSet])); |
+ |
+ // Create Uniform Buffer Descriptor |
+ // We always attach uniform buffers to descriptor set 1. The vertex uniform buffer will have |
+ // binding 0 and the fragment binding 1. |
+ VkDescriptorSetLayoutBinding dsUniBindings[2]; |
+ memset(&dsUniBindings, 0, 2 * sizeof(VkDescriptorSetLayoutBinding)); |
+ dsUniBindings[0].binding = GrVkUniformHandler::kVertexBinding; |
+ dsUniBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; |
+ dsUniBindings[0].descriptorCount = fUniformHandler.hasVertexUniforms() ? 1 : 0; |
+ dsUniBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; |
+ dsUniBindings[0].pImmutableSamplers = nullptr; |
+ dsUniBindings[1].binding = GrVkUniformHandler::kFragBinding; |
+ dsUniBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; |
+ dsUniBindings[1].descriptorCount = fUniformHandler.hasFragmentUniforms() ? 1 : 0; |
+ dsUniBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; |
+ dsUniBindings[1].pImmutableSamplers = nullptr; |
+ |
+ VkDescriptorSetLayoutCreateInfo dsUniformLayoutCreateInfo; |
+ memset(&dsUniformLayoutCreateInfo, 0, sizeof(VkDescriptorSetLayoutCreateInfo)); |
+ dsUniformLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; |
+ dsUniformLayoutCreateInfo.pNext = nullptr; |
+ dsUniformLayoutCreateInfo.flags = 0; |
+ dsUniformLayoutCreateInfo.bindingCount = 2; |
+ dsUniformLayoutCreateInfo.pBindings = dsUniBindings; |
+ |
+ GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), CreateDescriptorSetLayout( |
+ fGpu->device(), |
+ &dsUniformLayoutCreateInfo, |
+ nullptr, |
+ &dsLayout[GrVkUniformHandler::kUniformBufferDescSet])); |
+ |
+ // 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]; |
+ SkAssertResult(CreateVkShaderModule(fGpu, |
+ VK_SHADER_STAGE_VERTEX_BIT, |
+ fVS, |
+ &vertShaderModule, |
+ &shaderStageInfo[0])); |
+ |
+ SkAssertResult(CreateVkShaderModule(fGpu, |
+ VK_SHADER_STAGE_FRAGMENT_BIT, |
+ fFS, |
+ &fragShaderModule, |
+ &shaderStageInfo[1])); |
+ |
+ GrVkResourceProvider& resourceProvider = fGpu->resourceProvider(); |
+ GrVkPipeline* pipeline = resourceProvider.createPipeline(*args.fPipeline, |
+ *args.fPrimitiveProcessor, |
+ 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)); |
+ GR_VK_CALL(fGpu->vkInterface(), DestroyDescriptorSetLayout(fGpu->device(), dsLayout[0], |
+ nullptr)); |
+ GR_VK_CALL(fGpu->vkInterface(), DestroyDescriptorSetLayout(fGpu->device(), dsLayout[1], |
+ nullptr)); |
+ return nullptr; |
+ } |
+ |
+ |
+ GrVkDescriptorPool::DescriptorTypeCounts typeCounts; |
+ typeCounts.setTypeCount(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2); |
+ SkASSERT(numSamplers < 256); |
+ typeCounts.setTypeCount(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, (uint8_t)numSamplers); |
+ GrVkDescriptorPool* descriptorPool = |
+ fGpu->resourceProvider().findOrCreateCompatibleDescriptorPool(typeCounts); |
+ |
+ VkDescriptorSetAllocateInfo dsAllocateInfo; |
+ memset(&dsAllocateInfo, 0, sizeof(VkDescriptorSetAllocateInfo)); |
+ dsAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; |
+ dsAllocateInfo.pNext = nullptr; |
+ dsAllocateInfo.descriptorPool = descriptorPool->descPool(); |
+ dsAllocateInfo.descriptorSetCount = 2; |
+ dsAllocateInfo.pSetLayouts = dsLayout; |
+ |
+ VkDescriptorSet descriptorSets[2]; |
+ GR_VK_CALL_ERRCHECK(fGpu->vkInterface(), AllocateDescriptorSets(fGpu->device(), |
+ &dsAllocateInfo, |
+ descriptorSets)); |
+ |
+ return new GrVkProgram(fGpu, |
+ pipeline, |
+ pipelineLayout, |
+ dsLayout, |
+ descriptorPool, |
+ descriptorSets, |
+ fUniformHandles, |
+ fUniformHandler.fUniforms, |
+ fUniformHandler.fCurrentVertexUBOOffset, |
+ fUniformHandler.fCurrentFragmentUBOOffset, |
+ numSamplers, |
+ fGeometryProcessor, |
+ fXferProcessor, |
+ fFragmentProcessors); |
+} |