Dawn: Implement RenderPipeline caching (optimization).

Implement RenderPipeline caching. This moves creation of all pipeline-
related objects from GrDawnGpuCommandBuffer.cpp to GrDawnProgramBuilder.

Change-Id: I42797750877b655ee19347406946302b296f3758
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/236917
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/dawn/GrDawnGpu.cpp b/src/gpu/dawn/GrDawnGpu.cpp
index 7799f2a..c8b89a6 100644
--- a/src/gpu/dawn/GrDawnGpu.cpp
+++ b/src/gpu/dawn/GrDawnGpu.cpp
@@ -16,10 +16,12 @@
 #include "src/gpu/GrPipeline.h"
 #include "src/gpu/GrRenderTargetPriv.h"
 #include "src/gpu/GrSemaphore.h"
+#include "src/gpu/GrStencilSettings.h"
 #include "src/gpu/GrTexturePriv.h"
 #include "src/gpu/dawn/GrDawnBuffer.h"
 #include "src/gpu/dawn/GrDawnCaps.h"
 #include "src/gpu/dawn/GrDawnOpsRenderPass.h"
+#include "src/gpu/dawn/GrDawnProgramBuilder.h"
 #include "src/gpu/dawn/GrDawnRenderTarget.h"
 #include "src/gpu/dawn/GrDawnStencilAttachment.h"
 #include "src/gpu/dawn/GrDawnTexture.h"
@@ -33,6 +35,55 @@
 #include <unistd.h>
 #endif // !defined(SK_BUILD_FOR_WIN)
 
+const int kMaxRenderPipelineEntries = 1024;
+
+namespace {
+
+// FIXME: taken from GrVkPipelineState; refactor.
+uint32_t get_blend_info_key(const GrPipeline& pipeline) {
+    GrXferProcessor::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
+
+    static const uint32_t kBlendWriteShift = 1;
+    static const uint32_t kBlendCoeffShift = 5;
+    GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << kBlendCoeffShift));
+    GR_STATIC_ASSERT(kFirstAdvancedGrBlendEquation - 1 < 4);
+
+    uint32_t key = blendInfo.fWriteColor;
+    key |= (blendInfo.fSrcBlend << kBlendWriteShift);
+    key |= (blendInfo.fDstBlend << (kBlendWriteShift + kBlendCoeffShift));
+    key |= (blendInfo.fEquation << (kBlendWriteShift + 2 * kBlendCoeffShift));
+
+    return key;
+}
+
+class Desc : public GrProgramDesc {
+public:
+    static bool Build(Desc* desc,
+                      GrRenderTarget* rt,
+                      const GrPipeline& pipeline,
+                      const GrPrimitiveProcessor& primProc,
+                      GrPrimitiveType primitiveType,
+                      bool hasPoints,
+                      bool hasDepthStencil,
+                      GrGpu* gpu) {
+        if (!GrProgramDesc::Build(desc, rt, primProc, hasPoints, pipeline, gpu)) {
+            return false;
+        }
+        GrProcessorKeyBuilder b(&desc->key());
+
+        GrStencilSettings stencil;
+        stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(), 8);
+        stencil.genKey(&b);
+        b.add32(rt->config());
+        b.add32(static_cast<int32_t>(hasDepthStencil));
+        b.add32(get_blend_info_key(pipeline));
+        b.add32(static_cast<uint32_t>(primitiveType));
+        return true;
+    }
+};
+
+};
+
 sk_sp<GrGpu> GrDawnGpu::Make(const dawn::Device& device,
                              const GrContextOptions& options, GrContext* context) {
     if (!device) {
@@ -50,7 +101,8 @@
         , fDevice(device)
         , fQueue(device.CreateQueue())
         , fCompiler(new SkSL::Compiler())
-        , fUniformRingBuffer(this, dawn::BufferUsageBit::Uniform) {
+        , fUniformRingBuffer(this, dawn::BufferUsageBit::Uniform)
+        , fRenderPipelineCache(kMaxRenderPipelineEntries) {
     fCaps.reset(new GrDawnCaps(options));
 }
 
@@ -556,6 +608,36 @@
     return nullptr;
 }
 
+sk_sp<GrDawnProgram> GrDawnGpu::getOrCreateRenderPipeline(
+        GrRenderTarget* rt,
+        GrSurfaceOrigin origin,
+        const GrPipeline& pipeline,
+        const GrPrimitiveProcessor& primProc,
+        const GrTextureProxy* const* primProcProxies,
+        bool hasPoints,
+        GrPrimitiveType primitiveType) {
+    bool hasDepthStencil = rt->renderTargetPriv().getStencilAttachment() != nullptr;
+    Desc desc;
+    if (!Desc::Build(&desc, rt, pipeline, primProc, primitiveType, hasPoints, hasDepthStencil,
+                     this)) {
+        return nullptr;
+    }
+
+    if (sk_sp<GrDawnProgram>* program = fRenderPipelineCache.find(desc)) {
+        return *program;
+    }
+
+    dawn::TextureFormat colorFormat;
+    SkAssertResult(GrPixelConfigToDawnFormat(rt->config(), &colorFormat));
+    dawn::TextureFormat stencilFormat = dawn::TextureFormat::Depth24PlusStencil8;
+
+    sk_sp<GrDawnProgram> program = GrDawnProgramBuilder::Build(
+        this, rt, origin, pipeline, primProc, primProcProxies, primitiveType, colorFormat,
+        hasDepthStencil, stencilFormat, &desc);
+    fRenderPipelineCache.insert(desc, program);
+    return program;
+}
+
 GrDawnRingBuffer::Slice GrDawnGpu::allocateUniformRingBufferSlice(int size) {
     return fUniformRingBuffer.allocate(size);
 }
diff --git a/src/gpu/dawn/GrDawnGpu.h b/src/gpu/dawn/GrDawnGpu.h
index 2098c3c..d1c49ee 100644
--- a/src/gpu/dawn/GrDawnGpu.h
+++ b/src/gpu/dawn/GrDawnGpu.h
@@ -10,10 +10,12 @@
 
 #include "src/gpu/GrGpu.h"
 #include "dawn/dawncpp.h"
+#include "src/core/SkLRUCache.h"
 #include "src/gpu/dawn/GrDawnRingBuffer.h"
 
 class GrDawnOpsRenderPass;
 class GrPipeline;
+struct GrDawnProgram;
 
 namespace SkSL {
     class Compiler;
@@ -82,6 +84,14 @@
 
     sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
 
+    sk_sp<GrDawnProgram> getOrCreateRenderPipeline(GrRenderTarget*,
+                                                   GrSurfaceOrigin origin,
+                                                   const GrPipeline&,
+                                                   const GrPrimitiveProcessor&,
+                                                   const GrTextureProxy* const* primProcProxies,
+                                                   bool hasPoints,
+                                                   GrPrimitiveType primitiveType);
+
     GrDawnRingBuffer::Slice allocateUniformRingBufferSlice(int size);
     dawn::CommandEncoder getCopyEncoder();
     void flushCopyEncoder();
@@ -154,6 +164,14 @@
     dawn::CommandEncoder                            fCopyEncoder;
     std::vector<dawn::CommandBuffer>                fCommandBuffers;
 
+    struct ProgramDescHash {
+        uint32_t operator()(const GrProgramDesc& desc) const {
+            return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0);
+        }
+    };
+
+    SkLRUCache<GrProgramDesc, sk_sp<GrDawnProgram>, ProgramDescHash>    fRenderPipelineCache;
+
     typedef GrGpu INHERITED;
 };
 
diff --git a/src/gpu/dawn/GrDawnOpsRenderPass.cpp b/src/gpu/dawn/GrDawnOpsRenderPass.cpp
index d14a88c..e8abcf1 100644
--- a/src/gpu/dawn/GrDawnOpsRenderPass.cpp
+++ b/src/gpu/dawn/GrDawnOpsRenderPass.cpp
@@ -124,51 +124,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-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 kInt_GrVertexAttribType:
-        return dawn::VertexFormat::Int;
-    case kUByte4_norm_GrVertexAttribType:
-        return dawn::VertexFormat::UChar4Norm;
-    default:
-        SkASSERT(!"unsupported vertex format");
-        return dawn::VertexFormat::Float4;
-    }
-}
-
-static dawn::PrimitiveTopology to_dawn_primitive_topology(GrPrimitiveType primitiveType) {
-    switch (primitiveType) {
-        case GrPrimitiveType::kTriangles:
-            return dawn::PrimitiveTopology::TriangleList;
-        case GrPrimitiveType::kTriangleStrip:
-            return dawn::PrimitiveTopology::TriangleStrip;
-        case GrPrimitiveType::kPoints:
-            return dawn::PrimitiveTopology::PointList;
-        case GrPrimitiveType::kLines:
-            return dawn::PrimitiveTopology::LineList;
-        case GrPrimitiveType::kLineStrip:
-            return dawn::PrimitiveTopology::LineStrip;
-        case GrPrimitiveType::kLinesAdjacency:
-        default:
-            SkASSERT(!"unsupported primitive topology");
-            return dawn::PrimitiveTopology::TriangleList;
-    }
-}
-
 void GrDawnOpsRenderPass::setScissorState(
         const GrPipeline& pipeline,
         const GrPipeline::FixedDynamicState* fixedDynamicState,
@@ -194,96 +149,16 @@
                                           const GrPipeline::DynamicStateArrays* dynamicStateArrays,
                                           const GrPrimitiveType primitiveType,
                                           bool hasPoints) {
-    GrProgramDesc desc;
-    GrProgramDesc::Build(&desc, fRenderTarget, primProc, hasPoints, pipeline, fGpu);
-    dawn::TextureFormat colorFormat;
-    SkAssertResult(GrPixelConfigToDawnFormat(fRenderTarget->config(), &colorFormat));
-    dawn::TextureFormat stencilFormat = dawn::TextureFormat::Depth24PlusStencil8;
-    bool hasDepthStencil = fRenderTarget->renderTargetPriv().getStencilAttachment() != nullptr;
-    sk_sp<GrDawnProgram> program = GrDawnProgramBuilder::Build(fGpu, fRenderTarget, fOrigin,
-                                                               pipeline, primProc, primProcProxies,
-                                                               colorFormat, hasDepthStencil,
-                                                               stencilFormat, &desc);
-    SkASSERT(program);
+    sk_sp<GrDawnProgram> program = fGpu->getOrCreateRenderPipeline(fRenderTarget,
+                                                                  fOrigin,
+                                                                  pipeline,
+                                                                  primProc,
+                                                                  primProcProxies,
+                                                                  hasPoints,
+                                                                  primitiveType);
     auto bindGroup = program->setData(fGpu, fRenderTarget, fOrigin, primProc, pipeline,
                                       primProcProxies);
-
-    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::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 = to_dawn_primitive_topology(primitiveType);
-    rpDesc.sampleCount = 1;
-    rpDesc.depthStencilState = hasDepthStencil ? &program->fDepthStencilState : nullptr;
-    rpDesc.colorStateCount = 1;
-    dawn::ColorStateDescriptor* colorStates[] = { &program->fColorState };
-    rpDesc.colorStates = colorStates;
-    dawn::RenderPipeline renderPipeline = fGpu->device().CreateRenderPipeline(&rpDesc);
-    fPassEncoder.SetPipeline(renderPipeline);
+    fPassEncoder.SetPipeline(program->fRenderPipeline);
     fPassEncoder.SetBindGroup(0, bindGroup, 0, nullptr);
     if (pipeline.isStencilEnabled()) {
         fPassEncoder.SetStencilReference(pipeline.getUserStencil()->fFront.fRef);
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.cpp b/src/gpu/dawn/GrDawnProgramBuilder.cpp
index db51fce..9d68b77 100644
--- a/src/gpu/dawn/GrDawnProgramBuilder.cpp
+++ b/src/gpu/dawn/GrDawnProgramBuilder.cpp
@@ -180,6 +180,51 @@
     return dawn::AddressMode::ClampToEdge;
 }
 
+static dawn::PrimitiveTopology to_dawn_primitive_topology(GrPrimitiveType primitiveType) {
+    switch (primitiveType) {
+        case GrPrimitiveType::kTriangles:
+            return dawn::PrimitiveTopology::TriangleList;
+        case GrPrimitiveType::kTriangleStrip:
+            return dawn::PrimitiveTopology::TriangleStrip;
+        case GrPrimitiveType::kPoints:
+            return dawn::PrimitiveTopology::PointList;
+        case GrPrimitiveType::kLines:
+            return dawn::PrimitiveTopology::LineList;
+        case GrPrimitiveType::kLineStrip:
+            return dawn::PrimitiveTopology::LineStrip;
+        case GrPrimitiveType::kLinesAdjacency:
+        default:
+            SkASSERT(!"unsupported primitive topology");
+            return dawn::PrimitiveTopology::TriangleList;
+    }
+}
+
+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 kInt_GrVertexAttribType:
+        return dawn::VertexFormat::Int;
+    case kUByte4_norm_GrVertexAttribType:
+        return dawn::VertexFormat::UChar4Norm;
+    default:
+        SkASSERT(!"unsupported vertex format");
+        return dawn::VertexFormat::Float4;
+    }
+}
+
 static dawn::ColorStateDescriptor create_color_state(const GrDawnGpu* gpu,
                                                      const GrPipeline& pipeline,
                                                      dawn::TextureFormat colorFormat) {
@@ -222,17 +267,7 @@
         GrSurfaceOrigin origin) {
     dawn::DepthStencilStateDescriptor state;
     state.format = depthStencilFormat;
-    state.depthWriteEnabled = false;
-    state.depthCompare = dawn::CompareFunction::Always;
-    if (stencilSettings.isDisabled()) {
-        dawn::StencilStateFaceDescriptor stencilFace;
-        stencilFace.compare = dawn::CompareFunction::Always;
-        stencilFace.failOp = dawn::StencilOperation::Keep;
-        stencilFace.depthFailOp = dawn::StencilOperation::Keep;
-        stencilFace.passOp = dawn::StencilOperation::Keep;
-        state.stencilReadMask = state.stencilWriteMask = 0x0;
-        state.stencilBack = state.stencilFront = stencilFace;
-    } else {
+    if (!stencilSettings.isDisabled()) {
         const GrStencilSettings::Face& front = stencilSettings.front(origin);
         state.stencilReadMask = front.fTestMask;
         state.stencilWriteMask = front.fWriteMask;
@@ -294,6 +329,7 @@
                                                  const GrPipeline& pipeline,
                                                  const GrPrimitiveProcessor& primProc,
                                                  const GrTextureProxy* const primProcProxies[],
+                                                 GrPrimitiveType primitiveType,
                                                  dawn::TextureFormat colorFormat,
                                                  bool hasDepthStencil,
                                                  dawn::TextureFormat depthStencilFormat,
@@ -317,16 +353,15 @@
     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);
+    auto vsModule = builder.createShaderModule(builder.fVS, SkSL::Program::kVertex_Kind,
+                                               &vertInputs);
+    auto fsModule = 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) {
         layoutBindings.push_back({ GrDawnUniformHandler::kGeometryBinding,
                                    dawn::ShaderStageBit::Vertex,
@@ -351,15 +386,85 @@
     dawn::PipelineLayoutDescriptor pipelineLayoutDesc;
     pipelineLayoutDesc.bindGroupLayoutCount = 1;
     pipelineLayoutDesc.bindGroupLayouts = &result->fBindGroupLayout;
-    result->fPipelineLayout = gpu->device().CreatePipelineLayout(&pipelineLayoutDesc);
+    auto pipelineLayout = gpu->device().CreatePipelineLayout(&pipelineLayoutDesc);
     result->fBuiltinUniformHandles = builder.fUniformHandles;
-    result->fColorState = create_color_state(gpu, pipeline, colorFormat);
+    auto colorState = create_color_state(gpu, pipeline, colorFormat);
+    dawn::DepthStencilStateDescriptor depthStencilState;
     GrStencilSettings stencil;
     if (pipeline.isStencilEnabled()) {
         int numStencilBits = renderTarget->renderTargetPriv().numStencilBits();
         stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(), numStencilBits);
     }
-    result->fDepthStencilState = create_depth_stencil_state(stencil, depthStencilFormat, origin);
+    depthStencilState = create_depth_stencil_state(stencil, depthStencilFormat, origin);
+
+    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.attributeCount = vertexAttributes.size();
+        input.attributes = &vertexAttributes.front();
+        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.attributeCount = instanceAttributes.size();
+        input.attributes = &instanceAttributes.front();
+        inputs.push_back(input);
+    }
+    dawn::VertexInputDescriptor vertexInput;
+    vertexInput.indexFormat = dawn::IndexFormat::Uint16;
+    vertexInput.bufferCount = inputs.size();
+    vertexInput.buffers = &inputs.front();
+
+    dawn::PipelineStageDescriptor vsDesc;
+    vsDesc.module = vsModule;
+    vsDesc.entryPoint = "main";
+
+    dawn::PipelineStageDescriptor fsDesc;
+    fsDesc.module = fsModule;
+    fsDesc.entryPoint = "main";
+
+    dawn::RenderPipelineDescriptor rpDesc;
+    rpDesc.layout = pipelineLayout;
+    rpDesc.vertexStage = &vsDesc;
+    rpDesc.fragmentStage = &fsDesc;
+    rpDesc.vertexInput = &vertexInput;
+    rpDesc.primitiveTopology = to_dawn_primitive_topology(primitiveType);
+    if (hasDepthStencil) {
+        rpDesc.depthStencilState = &depthStencilState;
+    }
+    rpDesc.colorStateCount = 1;
+    dawn::ColorStateDescriptor* colorStatesPtr[] = { &colorState };
+    rpDesc.colorStates = colorStatesPtr;
+    result->fRenderPipeline = gpu->device().CreateRenderPipeline(&rpDesc);
     return result;
 }
 
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.h b/src/gpu/dawn/GrDawnProgramBuilder.h
index a98f270..7a18679 100644
--- a/src/gpu/dawn/GrDawnProgramBuilder.h
+++ b/src/gpu/dawn/GrDawnProgramBuilder.h
@@ -54,17 +54,12 @@
                   uint32_t fragmentUniformSize)
       : fDataManager(uniforms, geometryUniformSize, fragmentUniformSize) {
     }
-    dawn::ShaderModule fVSModule;
-    dawn::ShaderModule fFSModule;
     std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
     std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
     std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
     int fFragmentProcessorCnt;
     dawn::BindGroupLayout fBindGroupLayout;
-    dawn::PipelineLayout fPipelineLayout;
-    dawn::BindGroup fBindGroup;
-    dawn::ColorStateDescriptor fColorState;
-    dawn::DepthStencilStateDescriptor fDepthStencilState;
+    dawn::RenderPipeline fRenderPipeline;
     GrDawnProgramDataManager fDataManager;
     RenderTargetState fRenderTargetState;
     BuiltinUniformHandles fBuiltinUniformHandles;
@@ -83,6 +78,7 @@
                                       const GrPipeline&,
                                       const GrPrimitiveProcessor&,
                                       const GrTextureProxy* const primProcProxies[],
+                                      GrPrimitiveType primitiveType,
                                       dawn::TextureFormat colorFormat,
                                       bool hasDepthStencil,
                                       dawn::TextureFormat depthStencilFormat,