| 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..13daf714d909ffe338e4d4bd137bd56962801496
|
| --- /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_spv_module_t module = 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_module_get_num_errors(module)) {
|
| + SkDebugf("%s\n", shaderString.c_str());
|
| + SkDebugf("%s\n", shaderc_module_get_error_message(module));
|
| + 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_module_get_length(module);
|
| + moduleCreateInfo.pCode = (const uint32_t*)shaderc_module_get_bytes(module);
|
| +
|
| + VkResult err = GR_VK_CALL(gpu->vkInterface(), CreateShaderModule(gpu->device(),
|
| + &moduleCreateInfo,
|
| + nullptr,
|
| + shaderModule));
|
| + shaderc_module_release(module);
|
| + 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);
|
| +}
|
|
|