blob: 13daf714d909ffe338e4d4bd137bd56962801496 [file] [log] [blame]
/*
* 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);
}