First implementation of GrDawnProgramBuilder.
Conversion of SkSL to (Dawn-friendly) SPIR-V.
Conversion of GlBlendCoeff -> dawn::BlendFactor.
Conversion of GlBlendEquation -> dawn::BlendOperation.
Creation of dawn::ColorState from color format, write mask, blend state.
Building of basic BindGroupLayouts and BindGroups (the equivalent of
Vulkan's DescriptorSets).
Handling the RTAdjustment uniform, which handles the viewing transform.
Change-Id: If8aef19d71f81bc805defcf5fd7c4ebe3b9547db
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/231177
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.cpp b/src/gpu/dawn/GrDawnProgramBuilder.cpp
new file mode 100644
index 0000000..850b388
--- /dev/null
+++ b/src/gpu/dawn/GrDawnProgramBuilder.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/gpu/dawn/GrDawnProgramBuilder.h"
+
+#include "include/gpu/GrRenderTarget.h"
+#include "src/gpu/dawn/GrDawnGpu.h"
+#include "src/sksl/SkSLCompiler.h"
+
+#include "src/gpu/GrShaderUtils.h"
+
+static SkSL::String sksl_to_spirv(const GrDawnGpu* gpu, const char* shaderString,
+ SkSL::Program::Kind kind, SkSL::Program::Inputs* inputs) {
+ SkSL::Program::Settings settings;
+ std::unique_ptr<SkSL::Program> program = gpu->shaderCompiler()->convertProgram(
+ kind,
+ shaderString,
+ settings);
+ if (!program) {
+ SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str());
+ SkASSERT(false);
+ return "";
+ }
+ *inputs = program->fInputs;
+ SkSL::String code;
+ if (!gpu->shaderCompiler()->toSPIRV(*program, &code)) {
+ return "";
+ }
+ return code;
+}
+
+static dawn::BlendFactor to_dawn_blend_factor(GrBlendCoeff coeff) {
+ switch (coeff) {
+ case kZero_GrBlendCoeff:
+ return dawn::BlendFactor::Zero;
+ case kOne_GrBlendCoeff:
+ return dawn::BlendFactor::One;
+ case kSC_GrBlendCoeff:
+ return dawn::BlendFactor::SrcColor;
+ case kISC_GrBlendCoeff:
+ return dawn::BlendFactor::OneMinusSrcColor;
+ case kDC_GrBlendCoeff:
+ return dawn::BlendFactor::DstColor;
+ case kIDC_GrBlendCoeff:
+ return dawn::BlendFactor::OneMinusDstColor;
+ case kSA_GrBlendCoeff:
+ return dawn::BlendFactor::SrcAlpha;
+ case kISA_GrBlendCoeff:
+ return dawn::BlendFactor::OneMinusSrcAlpha;
+ case kDA_GrBlendCoeff:
+ return dawn::BlendFactor::DstAlpha;
+ case kIDA_GrBlendCoeff:
+ return dawn::BlendFactor::OneMinusDstAlpha;
+ case kConstC_GrBlendCoeff:
+ return dawn::BlendFactor::BlendColor;
+ case kIConstC_GrBlendCoeff:
+ return dawn::BlendFactor::OneMinusBlendColor;
+ case kConstA_GrBlendCoeff:
+ case kIConstA_GrBlendCoeff:
+ case kS2C_GrBlendCoeff:
+ case kIS2C_GrBlendCoeff:
+ case kS2A_GrBlendCoeff:
+ case kIS2A_GrBlendCoeff:
+ default:
+ SkASSERT(!"unsupported blend coefficient");
+ return dawn::BlendFactor::One;
+ }
+}
+
+static dawn::BlendOperation to_dawn_blend_operation(GrBlendEquation equation) {
+ switch (equation) {
+ case kAdd_GrBlendEquation:
+ return dawn::BlendOperation::Add;
+ case kSubtract_GrBlendEquation:
+ return dawn::BlendOperation::Subtract;
+ default:
+ SkASSERT(!"unsupported blend equation");
+ return dawn::BlendOperation::Add;
+ }
+}
+
+static dawn::ColorStateDescriptor create_color_state(const GrDawnGpu* gpu,
+ const GrPipeline& pipeline,
+ dawn::TextureFormat colorFormat) {
+ GrXferProcessor::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
+ GrBlendEquation equation = blendInfo.fEquation;
+ GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
+ GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
+
+ dawn::BlendFactor srcFactor = to_dawn_blend_factor(srcCoeff);
+ dawn::BlendFactor dstFactor = to_dawn_blend_factor(dstCoeff);
+ dawn::BlendOperation operation = to_dawn_blend_operation(equation);
+ auto mask = blendInfo.fWriteColor ? dawn::ColorWriteMask::All : dawn::ColorWriteMask::None;
+
+ dawn::BlendDescriptor colorDesc = {operation, srcFactor, dstFactor};
+ dawn::BlendDescriptor alphaDesc = {operation, srcFactor, dstFactor};
+
+ dawn::ColorStateDescriptor descriptor;
+ descriptor.format = colorFormat;
+ descriptor.alphaBlend = alphaDesc;
+ descriptor.colorBlend = colorDesc;
+ descriptor.nextInChain = nullptr;
+ descriptor.writeMask = mask;
+
+ return descriptor;
+}
+
+static dawn::BindGroupBinding make_bind_group_binding(uint32_t binding, const dawn::Buffer& buffer,
+ uint32_t offset, uint32_t size, const
+ dawn::Sampler& sampler,
+ const dawn::TextureView& textureView) {
+ dawn::BindGroupBinding result;
+ result.binding = binding;
+ result.buffer = buffer;
+ result.offset = offset;
+ result.size = size;
+ result.sampler = sampler;
+ result.textureView = textureView;
+ return result;
+}
+
+static dawn::BindGroupBinding make_bind_group_binding(uint32_t binding, const dawn::Buffer& buffer,
+ uint32_t offset, uint32_t size) {
+ return make_bind_group_binding(binding, buffer, offset, size, nullptr, nullptr);
+}
+
+sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu,
+ GrRenderTarget* renderTarget,
+ GrSurfaceOrigin origin,
+ const GrPipeline& pipeline,
+ const GrPrimitiveProcessor& primProc,
+ const GrTextureProxy* const primProcProxies[],
+ dawn::TextureFormat colorFormat,
+ GrProgramDesc* desc) {
+ GrDawnProgramBuilder builder(gpu, renderTarget, origin, primProc, primProcProxies, pipeline,
+ desc);
+ if (!builder.emitAndInstallProcs()) {
+ return nullptr;
+ }
+
+ builder.fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
+ builder.fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
+ builder.fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
+ builder.fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
+
+ builder.finalizeShaders();
+
+ SkSL::Program::Inputs vertInputs, fragInputs;
+ GrDawnUniformHandler::UniformInfoArray& uniforms = builder.fUniformHandler.fUniforms;
+ uint32_t geometryUniformSize = builder.fUniformHandler.fCurrentGeometryUBOOffset;
+ uint32_t fragmentUniformSize = builder.fUniformHandler.fCurrentFragmentUBOOffset;
+ sk_sp<GrDawnProgram> result(
+ new GrDawnProgram(uniforms, geometryUniformSize, fragmentUniformSize));
+ result->fVSModule = builder.createShaderModule(builder.fVS, SkSL::Program::kVertex_Kind,
+ &vertInputs);
+ result->fFSModule = builder.createShaderModule(builder.fFS, SkSL::Program::kFragment_Kind,
+ &fragInputs);
+ result->fGeometryProcessor = std::move(builder.fGeometryProcessor);
+ result->fXferProcessor = std::move(builder.fXferProcessor);
+ result->fFragmentProcessors = std::move(builder.fFragmentProcessors);
+ result->fFragmentProcessorCnt = builder.fFragmentProcessorCnt;
+ std::vector<dawn::BindGroupLayoutBinding> layoutBindings;
+ std::vector<dawn::BindGroupBinding> bindings;
+
+ if (0 != geometryUniformSize) {
+ dawn::BufferDescriptor desc;
+ desc.usage = dawn::BufferUsageBit::Uniform | dawn::BufferUsageBit::CopyDst;
+ desc.size = geometryUniformSize;
+ result->fGeometryUniformBuffer = gpu->device().CreateBuffer(&desc);
+ bindings.push_back(make_bind_group_binding(0, result->fGeometryUniformBuffer, 0,
+ geometryUniformSize));
+ layoutBindings.push_back({ 0, dawn::ShaderStageBit::Vertex,
+ dawn::BindingType::UniformBuffer});
+ }
+ if (0 != fragmentUniformSize) {
+ dawn::BufferDescriptor desc;
+ desc.usage = dawn::BufferUsageBit::Uniform | dawn::BufferUsageBit::CopyDst;
+ desc.size = fragmentUniformSize;
+ result->fFragmentUniformBuffer = gpu->device().CreateBuffer(&desc);
+ bindings.push_back(make_bind_group_binding(1, result->fFragmentUniformBuffer, 0,
+ fragmentUniformSize));
+ layoutBindings.push_back({ 1, dawn::ShaderStageBit::Fragment,
+ dawn::BindingType::UniformBuffer});
+ }
+ dawn::BindGroupLayoutDescriptor bindGroupLayoutDesc;
+ bindGroupLayoutDesc.bindingCount = layoutBindings.size();
+ bindGroupLayoutDesc.bindings = layoutBindings.data();
+ auto bindGroupLayout = gpu->device().CreateBindGroupLayout(&bindGroupLayoutDesc);
+ dawn::BindGroupDescriptor descriptor;
+ descriptor.layout = bindGroupLayout;
+ descriptor.bindingCount = bindings.size();
+ descriptor.bindings = bindings.data();
+ result->fUniformBindGroup = gpu->device().CreateBindGroup(&descriptor);
+ dawn::PipelineLayoutDescriptor pipelineLayoutDesc;
+ pipelineLayoutDesc.bindGroupLayoutCount = 1;
+ pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout;
+ result->fPipelineLayout = gpu->device().CreatePipelineLayout(&pipelineLayoutDesc);
+ result->fBuiltinUniformHandles = builder.fUniformHandles;
+ result->fColorState = create_color_state(gpu, pipeline, colorFormat);
+ return result;
+}
+
+GrDawnProgramBuilder::GrDawnProgramBuilder(GrDawnGpu* gpu,
+ GrRenderTarget* renderTarget,
+ GrSurfaceOrigin origin,
+ const GrPrimitiveProcessor& primProc,
+ const GrTextureProxy* const primProcProxies[],
+ const GrPipeline& pipeline,
+ GrProgramDesc* desc)
+ : INHERITED(renderTarget, origin, primProc, primProcProxies, pipeline, desc)
+ , fGpu(gpu)
+ , fVaryingHandler(this)
+ , fUniformHandler(this) {
+}
+
+dawn::ShaderModule GrDawnProgramBuilder::createShaderModule(const GrGLSLShaderBuilder& builder,
+ SkSL::Program::Kind kind,
+ SkSL::Program::Inputs* inputs) {
+ dawn::Device device = fGpu->device();
+ SkString source(builder.fCompilerString.c_str());
+
+#if 0
+ SkSL::String sksl = GrShaderUtils::PrettyPrint(builder.fCompilerString);
+ printf("converting program:\n%s\n", sksl.c_str());
+#endif
+
+ SkSL::String spirvSource = sksl_to_spirv(fGpu, source.c_str(), kind, inputs);
+
+ dawn::ShaderModuleDescriptor desc;
+ desc.codeSize = spirvSource.size() / 4;
+ desc.code = reinterpret_cast<const uint32_t*>(spirvSource.c_str());
+
+ return device.CreateShaderModule(&desc);
+};
+
+const GrCaps* GrDawnProgramBuilder::caps() const {
+ return fGpu->caps();
+}
+
+void GrDawnProgram::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
+ // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
+ if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
+ fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
+ fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
+ }
+
+ // set RT adjustment
+ SkISize size;
+ size.set(rt->width(), rt->height());
+ SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
+ if (fRenderTargetState.fRenderTargetOrigin != origin ||
+ fRenderTargetState.fRenderTargetSize != size) {
+ fRenderTargetState.fRenderTargetSize = size;
+ fRenderTargetState.fRenderTargetOrigin = origin;
+
+ float rtAdjustmentVec[4];
+ fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
+ fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
+ }
+}
+
+void GrDawnProgram::setData(const GrPrimitiveProcessor& primProc,
+ const GrRenderTarget* renderTarget,
+ GrSurfaceOrigin origin,
+ const GrPipeline& pipeline) {
+ this->setRenderTargetState(renderTarget, origin);
+ fGeometryProcessor->setData(fDataManager, primProc,
+ GrFragmentProcessor::CoordTransformIter(pipeline));
+ GrFragmentProcessor::Iter iter(pipeline);
+ GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
+ const GrFragmentProcessor* fp = iter.next();
+ GrGLSLFragmentProcessor* glslFP = glslIter.next();
+ while (fp && glslFP) {
+ glslFP->setData(fDataManager, *fp);
+ fp = iter.next();
+ glslFP = glslIter.next();
+ }
+ fDataManager.uploadUniformBuffers(fGeometryUniformBuffer,
+ fFragmentUniformBuffer);
+}