Dawn backend: first triangle.

Nothing is cached in this initial version; all the magic happens in
GrDawnGpuRTCommandBuffer::beginDraw(). It builds the program,
sets the uniform data, converts the vertex attributes, initializes
rasterization state and blend state, creates a pipeline and bind group
and sets them.
send[Indexed]InstancedMeshToGpu() encodes the Dawn draw commands.
GrDawnGpuProgramBuilder::beginRenderPass() then finishes
the command encoder and submits the resulting command buffer.

Change-Id: Ie9c160cd18a2c4ef1bde66f86a52227e3bf1b570
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/230457
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
diff --git a/src/gpu/dawn/GrDawnCaps.cpp b/src/gpu/dawn/GrDawnCaps.cpp
index 8964d61..df906ed 100644
--- a/src/gpu/dawn/GrDawnCaps.cpp
+++ b/src/gpu/dawn/GrDawnCaps.cpp
@@ -10,7 +10,8 @@
 GrDawnCaps::GrDawnCaps(const GrContextOptions& contextOptions) : INHERITED(contextOptions) {
     fBufferMapThreshold = SK_MaxS32;  // FIXME: get this from Dawn?
     fShaderCaps.reset(new GrShaderCaps(contextOptions));
-    fMaxTextureSize = 2048;
+    fMaxTextureSize = 2048; // FIXME
+    fMaxVertexAttributes = 16; // FIXME
     fPerformPartialClearsAsDraws = true;
 }
 
@@ -50,6 +51,10 @@
         case GrColorType::kRGBA_8888:
             if (dawn::TextureFormat::RGBA8Unorm == dawnFormat) {
                 return kRGBA_8888_GrPixelConfig;
+            } else if (dawn::TextureFormat::BGRA8Unorm == *dawnFormat) {
+                // FIXME: This shouldn't be necessary, but on some platforms (Mac)
+                // Skia byte order is RGBA, while preferred swap format is BGRA.
+                return kBGRA_8888_GrPixelConfig;
             }
             break;
         case GrColorType::kRGB_888x:
@@ -57,6 +62,8 @@
         case GrColorType::kBGRA_8888:
             if (dawn::TextureFormat::BGRA8Unorm == dawnFormat) {
                 return kBGRA_8888_GrPixelConfig;
+            } else if (dawn::TextureFormat::RGBA8Unorm == *dawnFormat) {
+                return kRGBA_8888_GrPixelConfig;
             }
             break;
         default:
diff --git a/src/gpu/dawn/GrDawnGpu.cpp b/src/gpu/dawn/GrDawnGpu.cpp
index 29d8ffa..791bc1e 100644
--- a/src/gpu/dawn/GrDawnGpu.cpp
+++ b/src/gpu/dawn/GrDawnGpu.cpp
@@ -17,6 +17,7 @@
 #include "src/gpu/GrRenderTargetPriv.h"
 #include "src/gpu/GrSemaphore.h"
 #include "src/gpu/GrTexturePriv.h"
+#include "src/gpu/dawn/GrDawnBuffer.h"
 #include "src/gpu/dawn/GrDawnCaps.h"
 #include "src/gpu/dawn/GrDawnGpuCommandBuffer.h"
 #include "src/gpu/dawn/GrDawnRenderTarget.h"
@@ -75,8 +76,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 sk_sp<GrGpuBuffer> GrDawnGpu::onCreateBuffer(size_t size, GrGpuBufferType type,
                                              GrAccessPattern accessPattern, const void* data) {
-    SkASSERT(!"unimplemented");
-    return nullptr;
+    sk_sp<GrGpuBuffer> b(new GrDawnBuffer(this, size, type, accessPattern));
+    if (data && b) {
+        b->updateData(data, size);
+    }
+    return b;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp b/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp
index d2db9a6..87ede07 100644
--- a/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp
+++ b/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp
@@ -7,15 +7,18 @@
 
 #include "src/gpu/dawn/GrDawnGpuCommandBuffer.h"
 
-#include "include/core/SkRect.h"
 #include "src/gpu/GrFixedClip.h"
 #include "src/gpu/GrMesh.h"
 #include "src/gpu/GrOpFlushState.h"
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrRenderTargetPriv.h"
 #include "src/gpu/GrTexturePriv.h"
+#include "src/gpu/dawn/GrDawnBuffer.h"
 #include "src/gpu/dawn/GrDawnGpu.h"
+#include "src/gpu/dawn/GrDawnProgramBuilder.h"
 #include "src/gpu/dawn/GrDawnRenderTarget.h"
+#include "src/gpu/dawn/GrDawnUtil.h"
+#include "src/sksl/SkSLCompiler.h"
 
 void GrDawnGpuTextureCommandBuffer::copy(GrSurface* src, const SkIRect& srcRect,
                                          const SkIPoint& dstPoint) {
@@ -55,13 +58,31 @@
                                                    const LoadAndStoreInfo& colorInfo,
                                                    const StencilLoadAndStoreInfo& stencilInfo)
         : INHERITED(rt, origin)
-        , fGpu(gpu) {
-    this->init();
+        , fGpu(gpu)
+        , fColorInfo(colorInfo) {
+    fEncoder = fGpu->device().CreateCommandEncoder();
+    fPassEncoder = beginRenderPass();
 }
 
-void GrDawnGpuRTCommandBuffer::init() {
-}
+dawn::RenderPassEncoder GrDawnGpuRTCommandBuffer::beginRenderPass() {
+    dawn::Texture texture = static_cast<GrDawnRenderTarget*>(fRenderTarget)->texture();
+    dawn::TextureView colorView = texture.CreateDefaultView();
+    const float *c = fColorInfo.fClearColor.vec();
+    dawn::LoadOp colorOp = to_dawn_load_op(fColorInfo.fLoadOp);
 
+    dawn::RenderPassColorAttachmentDescriptor colorAttachment;
+    colorAttachment.attachment = colorView;
+    colorAttachment.resolveTarget = nullptr;
+    colorAttachment.clearColor = { c[0], c[1], c[2], c[3] };
+    colorAttachment.loadOp = colorOp;
+    colorAttachment.storeOp = dawn::StoreOp::Store;
+    dawn::RenderPassColorAttachmentDescriptor* colorAttachments = { &colorAttachment };
+    dawn::RenderPassDescriptor renderPassDescriptor;
+    renderPassDescriptor.colorAttachmentCount = 1;
+    renderPassDescriptor.colorAttachments = &colorAttachments;
+    renderPassDescriptor.depthStencilAttachment = nullptr;
+    return fEncoder.BeginRenderPass(&renderPassDescriptor);
+}
 
 GrDawnGpuRTCommandBuffer::~GrDawnGpuRTCommandBuffer() {
 }
@@ -69,11 +90,13 @@
 GrGpu* GrDawnGpuRTCommandBuffer::gpu() { return fGpu; }
 
 void GrDawnGpuRTCommandBuffer::end() {
+    fPassEncoder.EndPass();
 }
 
 void GrDawnGpuRTCommandBuffer::submit() {
-    if (fCommandBuffer) {
-        fGpu->queue().Submit(1, &fCommandBuffer);
+    dawn::CommandBuffer commandBuffer = fEncoder.Finish();
+    if (commandBuffer) {
+        fGpu->queue().Submit(1, &commandBuffer);
     }
 }
 
@@ -111,9 +134,130 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrDawnGpuRTCommandBuffer::bindGeometry(const GrBuffer* indexBuffer,
-                                            const GrBuffer* vertexBuffer,
-                                            const GrBuffer* instanceBuffer) {
+static dawn::VertexFormat to_dawn_vertex_format(GrVertexAttribType type) {
+    switch (type) {
+    case kFloat_GrVertexAttribType:
+    case kHalf_GrVertexAttribType:
+        return dawn::VertexFormat::Float;
+    case kFloat2_GrVertexAttribType:
+    case kHalf2_GrVertexAttribType:
+        return dawn::VertexFormat::Float2;
+    case kFloat3_GrVertexAttribType:
+    case kHalf3_GrVertexAttribType:
+        return dawn::VertexFormat::Float3;
+    case kFloat4_GrVertexAttribType:
+    case kHalf4_GrVertexAttribType:
+        return dawn::VertexFormat::Float4;
+    case kUShort2_GrVertexAttribType:
+        return dawn::VertexFormat::UShort2;
+    case kUByte4_norm_GrVertexAttribType:
+        return dawn::VertexFormat::UChar4Norm;
+    default:
+        SkASSERT(!"unsupported vertex format");
+        return dawn::VertexFormat::Float4;
+    }
+}
+
+void GrDawnGpuRTCommandBuffer::beginDraw(const GrPipeline& pipeline,
+                                         const GrPrimitiveProcessor& primProc,
+                                         const GrTextureProxy* const primProcProxies[],
+                                         bool hasPoints) {
+    GrProgramDesc desc;
+    GrProgramDesc::Build(&desc, fRenderTarget, primProc, hasPoints, pipeline, fGpu);
+    dawn::TextureFormat colorFormat;
+    SkAssertResult(GrPixelConfigToDawnFormat(fRenderTarget->config(), &colorFormat));
+    sk_sp<GrDawnProgram> program = GrDawnProgramBuilder::Build(fGpu, fRenderTarget, fOrigin,
+                                                               pipeline, primProc, primProcProxies,
+                                                               colorFormat, &desc);
+    SkASSERT(program);
+    program->setData(primProc, fRenderTarget, fOrigin, pipeline);
+
+    std::vector<dawn::VertexBufferDescriptor> inputs;
+    std::vector<dawn::VertexAttributeDescriptor> vertexAttributes;
+    if (primProc.numVertexAttributes() > 0) {
+        size_t offset = 0;
+        int i = 0;
+        for (const auto& attrib : primProc.vertexAttributes()) {
+            dawn::VertexAttributeDescriptor attribute;
+            attribute.shaderLocation = i;
+            attribute.offset = offset;
+            attribute.format = to_dawn_vertex_format(attrib.cpuType());
+            vertexAttributes.push_back(attribute);
+            offset += attrib.sizeAlign4();
+            i++;
+        }
+        dawn::VertexBufferDescriptor input;
+        input.stride = offset;
+        input.stepMode = dawn::InputStepMode::Vertex;
+        input.attributes = &vertexAttributes.front();
+        input.attributeCount = vertexAttributes.size();
+        inputs.push_back(input);
+    }
+    std::vector<dawn::VertexAttributeDescriptor> instanceAttributes;
+    if (primProc.numInstanceAttributes() > 0) {
+        size_t offset = 0;
+        int i = 0;
+        for (const auto& attrib : primProc.instanceAttributes()) {
+            dawn::VertexAttributeDescriptor attribute;
+            attribute.shaderLocation = i;
+            attribute.offset = offset;
+            attribute.format = to_dawn_vertex_format(attrib.cpuType());
+            instanceAttributes.push_back(attribute);
+            offset += attrib.sizeAlign4();
+            i++;
+        }
+        dawn::VertexBufferDescriptor input;
+        input.stride = offset;
+        input.stepMode = dawn::InputStepMode::Instance;
+        input.attributes = &instanceAttributes.front();
+        input.attributeCount = instanceAttributes.size();
+        inputs.push_back(input);
+    }
+    dawn::VertexInputDescriptor vertexInput;
+    vertexInput.bufferCount = inputs.size();
+    vertexInput.buffers = &inputs.front();
+    vertexInput.indexFormat = dawn::IndexFormat::Uint16;
+
+    dawn::PipelineStageDescriptor vsDesc;
+    vsDesc.module = program->fVSModule;
+    vsDesc.entryPoint = "main";
+
+    dawn::PipelineStageDescriptor fsDesc;
+    fsDesc.module = program->fFSModule;
+    fsDesc.entryPoint = "main";
+
+    dawn::StencilStateFaceDescriptor stencilFace;
+    stencilFace.compare = dawn::CompareFunction::Always;
+    stencilFace.failOp = dawn::StencilOperation::Keep;
+    stencilFace.depthFailOp = dawn::StencilOperation::Keep;
+    stencilFace.passOp = dawn::StencilOperation::Replace;
+
+    dawn::RasterizationStateDescriptor rastDesc;
+
+    rastDesc.frontFace = dawn::FrontFace::CW;
+    rastDesc.cullMode = dawn::CullMode::None;
+    rastDesc.depthBias = 0;
+    rastDesc.depthBiasSlopeScale = 0.0f;
+    rastDesc.depthBiasClamp = 0.0f;
+
+    dawn::RenderPipelineDescriptor rpDesc;
+    rpDesc.layout = program->fPipelineLayout;
+    rpDesc.vertexStage = &vsDesc;
+    rpDesc.fragmentStage = &fsDesc;
+    rpDesc.vertexInput = &vertexInput;
+    rpDesc.rasterizationState = &rastDesc;
+    rpDesc.primitiveTopology = dawn::PrimitiveTopology::TriangleList;
+    rpDesc.sampleCount = 1;
+    rpDesc.depthStencilState = nullptr;
+    rpDesc.colorStateCount = 1;
+    dawn::ColorStateDescriptor* colorStates[] = { &program->fColorState };
+    rpDesc.colorStates = colorStates;
+    dawn::RenderPipeline renderPipeline = fGpu->device().CreateRenderPipeline(&rpDesc);
+    fPassEncoder.SetPipeline(renderPipeline);
+    fPassEncoder.SetBindGroup(0, program->fUniformBindGroup, 0, nullptr);
+}
+
+void GrDawnGpuRTCommandBuffer::endDraw() {
 }
 
 void GrDawnGpuRTCommandBuffer::onDraw(const GrPrimitiveProcessor& primProc,
@@ -126,12 +270,24 @@
     if (!meshCount) {
         return;
     }
-    GrFragmentProcessor::Iter iter(pipeline);
-
+    bool hasPoints = false;
     for (int i = 0; i < meshCount; ++i) {
-        const GrMesh& mesh = meshes[i];
-        mesh.sendToGpu(this);
+        if (meshes[i].primitiveType() == GrPrimitiveType::kPoints) {
+            hasPoints = true;
+        }
     }
+    const GrTextureProxy* const* primProcProxies = nullptr;
+    if (dynamicStateArrays && dynamicStateArrays->fPrimitiveProcessorTextures) {
+        primProcProxies = dynamicStateArrays->fPrimitiveProcessorTextures;
+    } else if (fixedDynamicState) {
+        primProcProxies = fixedDynamicState->fPrimitiveProcessorTextures;
+    }
+
+    beginDraw(pipeline, primProc, primProcProxies, hasPoints);
+    for (int i = 0; i < meshCount; ++i) {
+        meshes[i].sendToGpu(this);
+    }
+    endDraw();
 }
 
 void GrDawnGpuRTCommandBuffer::sendInstancedMeshToGpu(GrPrimitiveType,
@@ -141,7 +297,10 @@
                                                       const GrBuffer* instanceBuffer,
                                                       int instanceCount,
                                                       int baseInstance) {
-    this->bindGeometry(nullptr, vertexBuffer, instanceBuffer);
+    static const uint64_t vertexBufferOffsets[1] = {0};
+    dawn::Buffer vb = static_cast<const GrDawnBuffer*>(vertexBuffer)->get();
+    fPassEncoder.SetVertexBuffers(0, 1, &vb, vertexBufferOffsets);
+    fPassEncoder.Draw(vertexCount, 1, baseVertex, baseInstance);
     fGpu->stats()->incNumDraws();
 }
 
@@ -155,7 +314,12 @@
                                                              int instanceCount,
                                                              int baseInstance,
                                                              GrPrimitiveRestart restart) {
-    this->bindGeometry(indexBuffer, vertexBuffer, instanceBuffer);
+    uint64_t vertexBufferOffsets[1];
+    vertexBufferOffsets[0] = 0;
+    dawn::Buffer vb = static_cast<const GrDawnBuffer*>(vertexBuffer)->get();
+    dawn::Buffer ib = static_cast<const GrDawnBuffer*>(indexBuffer)->get();
+    fPassEncoder.SetIndexBuffer(ib, 0);
+    fPassEncoder.SetVertexBuffers(0, 1, &vb, vertexBufferOffsets);
+    fPassEncoder.DrawIndexed(indexCount, 1, baseIndex, baseVertex, baseInstance);
     fGpu->stats()->incNumDraws();
 }
-
diff --git a/src/gpu/dawn/GrDawnGpuCommandBuffer.h b/src/gpu/dawn/GrDawnGpuCommandBuffer.h
index be78096..b3a7486 100644
--- a/src/gpu/dawn/GrDawnGpuCommandBuffer.h
+++ b/src/gpu/dawn/GrDawnGpuCommandBuffer.h
@@ -62,6 +62,7 @@
     void begin() override { }
     void end() override;
 
+    dawn::RenderPassEncoder beginRenderPass();
     void transferFrom(const SkIRect& srcRect, GrColorType surfaceColorType,
                       GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
                       size_t offset) override;
@@ -74,15 +75,14 @@
     void submit();
 
 private:
-    void init();
-
     GrGpu* gpu() override;
 
-    // Bind vertex and index buffers
-    void bindGeometry(const GrBuffer* indexBuffer,
-                      const GrBuffer* vertexBuffer,
-                      const GrBuffer* instanceBuffer);
+    void beginDraw(const GrPipeline& pipeline,
+                   const GrPrimitiveProcessor& primProc,
+                   const GrTextureProxy* const primProcProxies[],
+                   bool hasPoints);
 
+    void endDraw();
     void onDraw(const GrPrimitiveProcessor& primProc,
                 const GrPipeline& pipeline,
                 const GrPipeline::FixedDynamicState* fixedDynamicState,
@@ -140,8 +140,10 @@
         SkIPoint        fDstPoint;
     };
 
-    dawn::CommandBuffer         fCommandBuffer;
     GrDawnGpu*                  fGpu;
+    dawn::CommandEncoder        fEncoder;
+    dawn::RenderPassEncoder     fPassEncoder;
+    LoadAndStoreInfo            fColorInfo;
 
     typedef GrGpuRTCommandBuffer INHERITED;
 };
diff --git a/src/gpu/dawn/GrDawnRenderTarget.h b/src/gpu/dawn/GrDawnRenderTarget.h
index e4f0939..ed95abb 100644
--- a/src/gpu/dawn/GrDawnRenderTarget.h
+++ b/src/gpu/dawn/GrDawnRenderTarget.h
@@ -34,6 +34,7 @@
 
     GrBackendRenderTarget getBackendRenderTarget() const override;
     GrBackendFormat backendFormat() const override;
+    dawn::Texture texture() const { return fInfo.fTexture; }
 
 protected:
     GrDawnRenderTarget(GrDawnGpu* gpu,