Add GrD3DPipelineStateDataManager.

* Creates a common class between GrVkPipelineStateDataManager and
GrD3DPipelineStateDataManager so they can share code (will do
for Metal as well in separate CL)
* Adds means for tracking and setting uniform data.

Change-Id: Ie0dc3a3d26f533201e316d255965a646bcecb842
Bug: skia:9935
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290636
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 2310000..cf26ed1 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -244,6 +244,8 @@
   "$_src/gpu/GrTransferFromRenderTask.h",
   "$_src/gpu/GrTriangulator.cpp",
   "$_src/gpu/GrTriangulator.h",
+  "$_src/gpu/GrUniformDataManager.cpp",
+  "$_src/gpu/GrUniformDataManager.h",
   "$_src/gpu/GrUserStencilSettings.h",
   "$_src/gpu/GrWaitRenderTask.cpp",
   "$_src/gpu/GrWaitRenderTask.h",
@@ -759,6 +761,8 @@
   "$_src/gpu/d3d/GrD3DPipelineState.h",
   "$_src/gpu/d3d/GrD3DPipelineStateBuilder.cpp",
   "$_src/gpu/d3d/GrD3DPipelineStateBuilder.h",
+  "$_src/gpu/d3d/GrD3DPipelineStateDataManager.cpp",
+  "$_src/gpu/d3d/GrD3DPipelineStateDataManager.h",
   "$_src/gpu/d3d/GrD3DRenderTarget.cpp",
   "$_src/gpu/d3d/GrD3DRenderTarget.h",
   "$_src/gpu/d3d/GrD3DResourceProvider.cpp",
diff --git a/src/gpu/GrUniformDataManager.cpp b/src/gpu/GrUniformDataManager.cpp
new file mode 100644
index 0000000..549057a
--- /dev/null
+++ b/src/gpu/GrUniformDataManager.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/gpu/GrUniformDataManager.h"
+
+#include "src/gpu/GrShaderVar.h"
+
+GrUniformDataManager::GrUniformDataManager(uint32_t uniformCount, uint32_t uniformSize)
+    : fUniformSize(uniformSize)
+    , fUniformsDirty(false) {
+    fUniformData.reset(uniformSize);
+    fUniforms.push_back_n(uniformCount);
+    // subclasses fill in the uniforms in their constructor
+}
+
+void* GrUniformDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const {
+    fUniformsDirty = true;
+    return static_cast<char*>(fUniformData.get())+uni.fOffset;
+}
+
+void GrUniformDataManager::set1i(UniformHandle u, int32_t i) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType);
+    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    memcpy(buffer, &i, sizeof(int32_t));
+}
+
+void GrUniformDataManager::set1iv(UniformHandle u,
+                                          int arrayCount,
+                                          const int32_t v[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType);
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(int32_t) == 4);
+    for (int i = 0; i < arrayCount; ++i) {
+        const int32_t* curVec = &v[i];
+        memcpy(buffer, curVec, sizeof(int32_t));
+        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
+    }
+}
+
+void GrUniformDataManager::set1f(UniformHandle u, float v0) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType);
+    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(float) == 4);
+    memcpy(buffer, &v0, sizeof(float));
+}
+
+void GrUniformDataManager::set1fv(UniformHandle u,
+                                          int arrayCount,
+                                          const float v[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType);
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(float) == 4);
+    for (int i = 0; i < arrayCount; ++i) {
+        const float* curVec = &v[i];
+        memcpy(buffer, curVec, sizeof(float));
+        buffer = static_cast<char*>(buffer) + 4*sizeof(float);
+    }
+}
+
+void GrUniformDataManager::set2i(UniformHandle u, int32_t i0, int32_t i1) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType);
+    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    int32_t v[2] = { i0, i1 };
+    memcpy(buffer, v, 2 * sizeof(int32_t));
+}
+
+void GrUniformDataManager::set2iv(UniformHandle u,
+                                          int arrayCount,
+                                          const int32_t v[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType);
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(int32_t) == 4);
+    for (int i = 0; i < arrayCount; ++i) {
+        const int32_t* curVec = &v[2 * i];
+        memcpy(buffer, curVec, 2 * sizeof(int32_t));
+        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
+    }
+}
+
+void GrUniformDataManager::set2f(UniformHandle u, float v0, float v1) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType);
+    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(float) == 4);
+    float v[2] = { v0, v1 };
+    memcpy(buffer, v, 2 * sizeof(float));
+}
+
+void GrUniformDataManager::set2fv(UniformHandle u,
+                                          int arrayCount,
+                                          const float v[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType);
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(float) == 4);
+    for (int i = 0; i < arrayCount; ++i) {
+        const float* curVec = &v[2 * i];
+        memcpy(buffer, curVec, 2 * sizeof(float));
+        buffer = static_cast<char*>(buffer) + 4*sizeof(float);
+    }
+}
+
+void GrUniformDataManager::set3i(UniformHandle u,
+                                         int32_t i0,
+                                         int32_t i1,
+                                         int32_t i2) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType);
+    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    int32_t v[3] = { i0, i1, i2 };
+    memcpy(buffer, v, 3 * sizeof(int32_t));
+}
+
+void GrUniformDataManager::set3iv(UniformHandle u,
+                                          int arrayCount,
+                                          const int32_t v[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType);
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(int32_t) == 4);
+    for (int i = 0; i < arrayCount; ++i) {
+        const int32_t* curVec = &v[3 * i];
+        memcpy(buffer, curVec, 3 * sizeof(int32_t));
+        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
+    }
+}
+
+void GrUniformDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType);
+    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(float) == 4);
+    float v[3] = { v0, v1, v2 };
+    memcpy(buffer, v, 3 * sizeof(float));
+}
+
+void GrUniformDataManager::set3fv(UniformHandle u,
+                                          int arrayCount,
+                                          const float v[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType);
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(float) == 4);
+    for (int i = 0; i < arrayCount; ++i) {
+        const float* curVec = &v[3 * i];
+        memcpy(buffer, curVec, 3 * sizeof(float));
+        buffer = static_cast<char*>(buffer) + 4*sizeof(float);
+    }
+}
+
+void GrUniformDataManager::set4i(UniformHandle u,
+                                         int32_t i0,
+                                         int32_t i1,
+                                         int32_t i2,
+                                         int32_t i3) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType);
+    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    int32_t v[4] = { i0, i1, i2, i3 };
+    memcpy(buffer, v, 4 * sizeof(int32_t));
+}
+
+void GrUniformDataManager::set4iv(UniformHandle u,
+                                          int arrayCount,
+                                          const int32_t v[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType);
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(int32_t) == 4);
+    for (int i = 0; i < arrayCount; ++i) {
+        const int32_t* curVec = &v[4 * i];
+        memcpy(buffer, curVec, 4 * sizeof(int32_t));
+        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
+    }
+}
+
+void GrUniformDataManager::set4f(UniformHandle u,
+                                         float v0,
+                                         float v1,
+                                         float v2,
+                                         float v3) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType);
+    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(float) == 4);
+    float v[4] = { v0, v1, v2, v3 };
+    memcpy(buffer, v, 4 * sizeof(float));
+}
+
+void GrUniformDataManager::set4fv(UniformHandle u,
+                                          int arrayCount,
+                                          const float v[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType);
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = this->getBufferPtrAndMarkDirty(uni);
+    SkASSERT(sizeof(float) == 4);
+    memcpy(buffer, v, arrayCount * 4 * sizeof(float));
+}
+
+void GrUniformDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const {
+    this->setMatrices<2>(u, 1, matrix);
+}
+
+void GrUniformDataManager::setMatrix2fv(UniformHandle u,
+                                                int arrayCount,
+                                                const float m[]) const {
+    this->setMatrices<2>(u, arrayCount, m);
+}
+
+void GrUniformDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const {
+    this->setMatrices<3>(u, 1, matrix);
+}
+
+void GrUniformDataManager::setMatrix3fv(UniformHandle u,
+                                                int arrayCount,
+                                                const float m[]) const {
+    this->setMatrices<3>(u, arrayCount, m);
+}
+
+void GrUniformDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const {
+    this->setMatrices<4>(u, 1, matrix);
+}
+
+void GrUniformDataManager::setMatrix4fv(UniformHandle u,
+                                                int arrayCount,
+                                                const float m[]) const {
+    this->setMatrices<4>(u, arrayCount, m);
+}
+
+template<int N> struct set_uniform_matrix;
+
+template<int N> inline void GrUniformDataManager::setMatrices(UniformHandle u,
+                                                                      int arrayCount,
+                                                                     const float matrices[]) const {
+    const Uniform& uni = fUniforms[u.toIndex()];
+    SkASSERT(uni.fType == kFloat2x2_GrSLType + (N - 2) ||
+             uni.fType == kHalf2x2_GrSLType + (N - 2));
+    SkASSERT(arrayCount > 0);
+    SkASSERT(arrayCount <= uni.fArrayCount ||
+             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
+
+    void* buffer = fUniformData.get();
+    fUniformsDirty = true;
+
+    set_uniform_matrix<N>::set(buffer, uni.fOffset, arrayCount, matrices);
+}
+
+template<int N> struct set_uniform_matrix {
+    inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) {
+        static_assert(sizeof(float) == 4);
+        buffer = static_cast<char*>(buffer) + uniformOffset;
+        for (int i = 0; i < count; ++i) {
+            const float* matrix = &matrices[N * N * i];
+            for (int j = 0; j < N; ++j) {
+                memcpy(buffer, &matrix[j * N], N * sizeof(float));
+                buffer = static_cast<char*>(buffer) + 4 * sizeof(float);
+            }
+        }
+    }
+};
+
+template<> struct set_uniform_matrix<4> {
+    inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) {
+        static_assert(sizeof(float) == 4);
+        buffer = static_cast<char*>(buffer) + uniformOffset;
+        memcpy(buffer, matrices, count * 16 * sizeof(float));
+    }
+};
+
diff --git a/src/gpu/GrUniformDataManager.h b/src/gpu/GrUniformDataManager.h
new file mode 100644
index 0000000..d36e69a
--- /dev/null
+++ b/src/gpu/GrUniformDataManager.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrUniformDataManager_DEFINED
+#define GrUniformDataManager_DEFINED
+
+#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
+
+#include "include/private/GrTypesPriv.h"
+#include "include/private/SkTArray.h"
+#include "src/core/SkAutoMalloc.h"
+
+class GrUniformDataManager : public GrGLSLProgramDataManager {
+public:
+    GrUniformDataManager(uint32_t uniformCount, uint32_t uniformSize);
+
+    void set1i(UniformHandle, int32_t) const override;
+    void set1iv(UniformHandle, int arrayCount, const int32_t v[]) const override;
+    void set1f(UniformHandle, float v0) const override;
+    void set1fv(UniformHandle, int arrayCount, const float v[]) const override;
+    void set2i(UniformHandle, int32_t, int32_t) const override;
+    void set2iv(UniformHandle, int arrayCount, const int32_t v[]) const override;
+    void set2f(UniformHandle, float, float) const override;
+    void set2fv(UniformHandle, int arrayCount, const float v[]) const override;
+    void set3i(UniformHandle, int32_t, int32_t, int32_t) const override;
+    void set3iv(UniformHandle, int arrayCount, const int32_t v[]) const override;
+    void set3f(UniformHandle, float, float, float) const override;
+    void set3fv(UniformHandle, int arrayCount, const float v[]) const override;
+    void set4i(UniformHandle, int32_t, int32_t, int32_t, int32_t) const override;
+    void set4iv(UniformHandle, int arrayCount, const int32_t v[]) const override;
+    void set4f(UniformHandle, float, float, float, float) const override;
+    void set4fv(UniformHandle, int arrayCount, const float v[]) const override;
+    // matrices are column-major, the first two upload a single matrix, the latter two upload
+    // arrayCount matrices into a uniform array.
+    void setMatrix2f(UniformHandle, const float matrix[]) const override;
+    void setMatrix3f(UniformHandle, const float matrix[]) const override;
+    void setMatrix4f(UniformHandle, const float matrix[]) const override;
+    void setMatrix2fv(UniformHandle, int arrayCount, const float matrices[]) const override;
+    void setMatrix3fv(UniformHandle, int arrayCount, const float matrices[]) const override;
+    void setMatrix4fv(UniformHandle, int arrayCount, const float matrices[]) const override;
+
+    // for nvpr only
+    void setPathFragmentInputTransform(VaryingHandle u, int components,
+                                       const SkMatrix& matrix) const override {
+        SK_ABORT("Only supported in NVPR, which is only available in GL");
+    }
+
+protected:
+    struct Uniform {
+        uint32_t fOffset;
+        SkDEBUGCODE(
+            GrSLType    fType;
+            int         fArrayCount;
+        );
+    };
+
+    template<int N> inline void setMatrices(UniformHandle, int arrayCount,
+                                            const float matrices[]) const;
+
+    void* getBufferPtrAndMarkDirty(const Uniform& uni) const;
+
+    uint32_t fUniformSize;
+
+    SkTArray<Uniform, true> fUniforms;
+
+    mutable SkAutoMalloc fUniformData;
+    mutable bool         fUniformsDirty;
+};
+
+#endif
diff --git a/src/gpu/d3d/GrD3DOpsRenderPass.cpp b/src/gpu/d3d/GrD3DOpsRenderPass.cpp
index bd681f9..689a11c 100644
--- a/src/gpu/d3d/GrD3DOpsRenderPass.cpp
+++ b/src/gpu/d3d/GrD3DOpsRenderPass.cpp
@@ -145,6 +145,7 @@
         return false;
     }
 
+    pipelineState->setData(fRenderTarget, info);
     fGpu->currentCommandList()->setPipelineState(std::move(pipelineState));
 
     set_stencil_ref(fGpu, info);
diff --git a/src/gpu/d3d/GrD3DPipelineState.cpp b/src/gpu/d3d/GrD3DPipelineState.cpp
index 2135176..073a7a0 100644
--- a/src/gpu/d3d/GrD3DPipelineState.cpp
+++ b/src/gpu/d3d/GrD3DPipelineState.cpp
@@ -12,391 +12,66 @@
 #include "src/gpu/GrStencilSettings.h"
 #include "src/gpu/d3d/GrD3DGpu.h"
 #include "src/gpu/d3d/GrD3DRootSignature.h"
+#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
+#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
+#include "src/gpu/glsl/GrGLSLXferProcessor.h"
 
-static DXGI_FORMAT attrib_type_to_format(GrVertexAttribType type) {
-    switch (type) {
-        case kFloat_GrVertexAttribType:
-            return DXGI_FORMAT_R32_FLOAT;
-        case kFloat2_GrVertexAttribType:
-            return DXGI_FORMAT_R32G32_FLOAT;
-        case kFloat3_GrVertexAttribType:
-            return DXGI_FORMAT_R32G32B32_FLOAT;
-        case kFloat4_GrVertexAttribType:
-            return DXGI_FORMAT_R32G32B32A32_FLOAT;
-        case kHalf_GrVertexAttribType:
-            return DXGI_FORMAT_R16_FLOAT;
-        case kHalf2_GrVertexAttribType:
-            return DXGI_FORMAT_R16G16_FLOAT;
-        case kHalf4_GrVertexAttribType:
-            return DXGI_FORMAT_R16G16B16A16_FLOAT;
-        case kInt2_GrVertexAttribType:
-            return DXGI_FORMAT_R32G32_SINT;
-        case kInt3_GrVertexAttribType:
-            return DXGI_FORMAT_R32G32B32_SINT;
-        case kInt4_GrVertexAttribType:
-            return DXGI_FORMAT_R32G32B32A32_SINT;
-        case kByte_GrVertexAttribType:
-            return DXGI_FORMAT_R8_SINT;
-        case kByte2_GrVertexAttribType:
-            return DXGI_FORMAT_R8G8_SINT;
-        case kByte4_GrVertexAttribType:
-            return DXGI_FORMAT_R8G8B8A8_SINT;
-        case kUByte_GrVertexAttribType:
-            return DXGI_FORMAT_R8_UINT;
-        case kUByte2_GrVertexAttribType:
-            return DXGI_FORMAT_R8G8_UINT;
-        case kUByte4_GrVertexAttribType:
-            return DXGI_FORMAT_R8G8B8A8_UINT;
-        case kUByte_norm_GrVertexAttribType:
-            return DXGI_FORMAT_R8_UNORM;
-        case kUByte4_norm_GrVertexAttribType:
-            return DXGI_FORMAT_R8G8B8A8_UNORM;
-        case kShort2_GrVertexAttribType:
-            return DXGI_FORMAT_R16G16_SINT;
-        case kShort4_GrVertexAttribType:
-            return DXGI_FORMAT_R16G16B16A16_SINT;
-        case kUShort2_GrVertexAttribType:
-            return DXGI_FORMAT_R16G16_UINT;
-        case kUShort2_norm_GrVertexAttribType:
-            return DXGI_FORMAT_R16G16_UNORM;
-        case kInt_GrVertexAttribType:
-            return DXGI_FORMAT_R32_SINT;
-        case kUint_GrVertexAttribType:
-            return DXGI_FORMAT_R32_UINT;
-        case kUShort_norm_GrVertexAttribType:
-            return DXGI_FORMAT_R16_UNORM;
-        case kUShort4_norm_GrVertexAttribType:
-            return DXGI_FORMAT_R16G16B16A16_UNORM;
+GrD3DPipelineState::GrD3DPipelineState(
+        gr_cp<ID3D12PipelineState> pipelineState,
+        const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
+        const UniformInfoArray& uniforms, uint32_t uniformSize,
+        std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
+        std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
+        std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
+        int fragmentProcessorCnt)
+    : fPipelineState(std::move(pipelineState))
+    , fBuiltinUniformHandles(builtinUniformHandles)
+    , fGeometryProcessor(std::move(geometryProcessor))
+    , fXferProcessor(std::move(xferProcessor))
+    , fFragmentProcessors(std::move(fragmentProcessors))
+    , fFragmentProcessorCnt(fragmentProcessorCnt)
+    , fDataManager(uniforms, uniformSize) {}
+
+void GrD3DPipelineState::setData(const GrRenderTarget* renderTarget,
+                                 const GrProgramInfo& programInfo) {
+    this->setRenderTargetState(renderTarget, programInfo.origin());
+
+    GrFragmentProcessor::PipelineCoordTransformRange transformRange(programInfo.pipeline());
+    fGeometryProcessor->setData(fDataManager, programInfo.primProc(), transformRange);
+    GrFragmentProcessor::CIter fpIter(programInfo.pipeline());
+    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
+    for (; fpIter && glslIter; ++fpIter, ++glslIter) {
+        glslIter->setData(fDataManager, *fpIter);
     }
-    SK_ABORT("Unknown vertex attrib type");
-}
+    SkASSERT(!fpIter && !glslIter);
 
-static void setup_vertex_input_layout(const GrPrimitiveProcessor& primProc,
-                                      D3D12_INPUT_ELEMENT_DESC* inputElements) {
-    unsigned int slotNumber = 0;
-    unsigned int vertexSlot = 0;
-    unsigned int instanceSlot = 0;
-    if (primProc.hasVertexAttributes()) {
-        vertexSlot = slotNumber++;
-    }
-    if (primProc.hasInstanceAttributes()) {
-        instanceSlot = slotNumber++;
-    }
+    {
+        SkIPoint offset;
+        GrTexture* dstTexture = programInfo.pipeline().peekDstTexture(&offset);
 
-    unsigned int currentAttrib = 0;
-    unsigned int vertexAttributeOffset = 0;
-
-    for (const auto& attrib : primProc.vertexAttributes()) {
-        // When using SPIRV-Cross it converts the location modifier in SPIRV to be
-        // TEXCOORD<N> where N is the location value for eveery vertext attribute
-        inputElements[currentAttrib] = {"TEXCOORD", currentAttrib,
-                                        attrib_type_to_format(attrib.cpuType()),
-                                        vertexSlot, vertexAttributeOffset,
-                                        D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0};
-        vertexAttributeOffset += attrib.sizeAlign4();
-        currentAttrib++;
-    }
-    SkASSERT(vertexAttributeOffset == primProc.vertexStride());
-
-    unsigned int instanceAttributeOffset = 0;
-    for (const auto& attrib : primProc.instanceAttributes()) {
-        // When using SPIRV-Cross it converts the location modifier in SPIRV to be
-        // TEXCOORD<N> where N is the location value for eveery vertext attribute
-        inputElements[currentAttrib] = {"TEXCOORD", currentAttrib,
-                                        attrib_type_to_format(attrib.cpuType()),
-                                        instanceSlot, instanceAttributeOffset,
-                                        D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0};
-        instanceAttributeOffset += attrib.sizeAlign4();
-        currentAttrib++;
-    }
-    SkASSERT(instanceAttributeOffset == primProc.instanceStride());
-}
-
-static D3D12_BLEND blend_coeff_to_d3d_blend(GrBlendCoeff coeff) {
-    switch (coeff) {
-        case kZero_GrBlendCoeff:
-            return D3D12_BLEND_ZERO;
-        case kOne_GrBlendCoeff:
-            return D3D12_BLEND_ONE;
-        case kSC_GrBlendCoeff:
-            return D3D12_BLEND_SRC_COLOR;
-        case kISC_GrBlendCoeff:
-            return D3D12_BLEND_INV_SRC_COLOR;
-        case kDC_GrBlendCoeff:
-            return D3D12_BLEND_DEST_COLOR;
-        case kIDC_GrBlendCoeff:
-            return D3D12_BLEND_INV_DEST_COLOR;
-        case kSA_GrBlendCoeff:
-            return D3D12_BLEND_SRC_ALPHA;
-        case kISA_GrBlendCoeff:
-            return D3D12_BLEND_INV_SRC_ALPHA;
-        case kDA_GrBlendCoeff:
-            return D3D12_BLEND_DEST_ALPHA;
-        case kIDA_GrBlendCoeff:
-            return D3D12_BLEND_INV_DEST_ALPHA;
-        case kConstC_GrBlendCoeff:
-            return D3D12_BLEND_BLEND_FACTOR;
-        case kIConstC_GrBlendCoeff:
-            return D3D12_BLEND_INV_BLEND_FACTOR;
-        case kS2C_GrBlendCoeff:
-            return D3D12_BLEND_SRC1_COLOR;
-        case kIS2C_GrBlendCoeff:
-            return D3D12_BLEND_INV_SRC1_COLOR;
-        case kS2A_GrBlendCoeff:
-            return D3D12_BLEND_SRC1_ALPHA;
-        case kIS2A_GrBlendCoeff:
-            return D3D12_BLEND_INV_SRC1_ALPHA;
-        case kIllegal_GrBlendCoeff:
-            return D3D12_BLEND_ZERO;
-    }
-    SkUNREACHABLE;
-}
-
-static D3D12_BLEND blend_coeff_to_d3d_blend_for_alpha(GrBlendCoeff coeff) {
-    switch (coeff) {
-        // Force all srcColor used in alpha slot to alpha version.
-        case kSC_GrBlendCoeff:
-            return D3D12_BLEND_SRC_ALPHA;
-        case kISC_GrBlendCoeff:
-            return D3D12_BLEND_INV_SRC_ALPHA;
-        case kDC_GrBlendCoeff:
-            return D3D12_BLEND_DEST_ALPHA;
-        case kIDC_GrBlendCoeff:
-            return D3D12_BLEND_INV_DEST_ALPHA;
-        case kS2C_GrBlendCoeff:
-            return D3D12_BLEND_SRC1_ALPHA;
-        case kIS2C_GrBlendCoeff:
-            return D3D12_BLEND_INV_SRC1_ALPHA;
-
-        default:
-            return blend_coeff_to_d3d_blend(coeff);
+        fXferProcessor->setData(fDataManager, programInfo.pipeline().getXferProcessor(),
+                                dstTexture, offset);
     }
 }
 
+void GrD3DPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
 
-static D3D12_BLEND_OP blend_equation_to_d3d_op(GrBlendEquation equation) {
-    switch (equation) {
-        case kAdd_GrBlendEquation:
-            return D3D12_BLEND_OP_ADD;
-        case kSubtract_GrBlendEquation:
-            return D3D12_BLEND_OP_SUBTRACT;
-        case kReverseSubtract_GrBlendEquation:
-            return D3D12_BLEND_OP_REV_SUBTRACT;
-        default:
-            SkUNREACHABLE;
-    }
-}
-
-static void fill_in_blend_state(const GrPipeline& pipeline, D3D12_BLEND_DESC* blendDesc) {
-    blendDesc->AlphaToCoverageEnable = false;
-    blendDesc->IndependentBlendEnable = false;
-
-    const GrXferProcessor::BlendInfo& blendInfo = pipeline.getXferProcessor().getBlendInfo();
-
-    GrBlendEquation equation = blendInfo.fEquation;
-    GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
-    GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
-    bool blendOff = GrBlendShouldDisable(equation, srcCoeff, dstCoeff);
-
-    auto& rtBlend = blendDesc->RenderTarget[0];
-    rtBlend.BlendEnable = !blendOff;
-    if (!blendOff) {
-        rtBlend.SrcBlend = blend_coeff_to_d3d_blend(srcCoeff);
-        rtBlend.DestBlend = blend_coeff_to_d3d_blend(dstCoeff);
-        rtBlend.BlendOp = blend_equation_to_d3d_op(equation);
-        rtBlend.SrcBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(srcCoeff);
-        rtBlend.DestBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(dstCoeff);
-        rtBlend.BlendOpAlpha = blend_equation_to_d3d_op(equation);
+    // 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()));
     }
 
-    if (!blendInfo.fWriteColor) {
-        rtBlend.RenderTargetWriteMask = 0;
-    } else {
-        rtBlend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+    // set RT adjustment
+    SkISize dimensions = rt->dimensions();
+    SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
+    if (fRenderTargetState.fRenderTargetOrigin != origin ||
+        fRenderTargetState.fRenderTargetSize != dimensions) {
+        fRenderTargetState.fRenderTargetSize = dimensions;
+        fRenderTargetState.fRenderTargetOrigin = origin;
+
+        float rtAdjustmentVec[4];
+        fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
+        fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
     }
 }
-
-static void fill_in_rasterizer_state(const GrPipeline& pipeline, const GrCaps* caps,
-                                     D3D12_RASTERIZER_DESC* rasterizer) {
-    rasterizer->FillMode = (caps->wireframeMode() || pipeline.isWireframe()) ?
-                           D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID;
-    rasterizer->CullMode = D3D12_CULL_MODE_NONE;
-    rasterizer->FrontCounterClockwise = true;
-    rasterizer->DepthBias = 0;
-    rasterizer->DepthBiasClamp = 0.0f;
-    rasterizer->SlopeScaledDepthBias = 0.0f;
-    rasterizer->DepthClipEnable = false;
-    rasterizer->MultisampleEnable = pipeline.isHWAntialiasState();
-    rasterizer->AntialiasedLineEnable = false;
-    rasterizer->ForcedSampleCount = 0;
-    rasterizer->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
-}
-
-static D3D12_STENCIL_OP stencil_op_to_d3d_op(GrStencilOp op) {
-    switch (op) {
-        case GrStencilOp::kKeep:
-            return D3D12_STENCIL_OP_KEEP;
-        case GrStencilOp::kZero:
-            return D3D12_STENCIL_OP_ZERO;
-        case GrStencilOp::kReplace:
-            return D3D12_STENCIL_OP_REPLACE;
-        case GrStencilOp::kInvert:
-            return D3D12_STENCIL_OP_INVERT;
-        case GrStencilOp::kIncWrap:
-            return D3D12_STENCIL_OP_INCR;
-        case GrStencilOp::kDecWrap:
-            return D3D12_STENCIL_OP_DECR;
-        case GrStencilOp::kIncClamp:
-            return D3D12_STENCIL_OP_INCR_SAT;
-        case GrStencilOp::kDecClamp:
-            return D3D12_STENCIL_OP_DECR_SAT;
-    }
-    SkUNREACHABLE;
-}
-
-static D3D12_COMPARISON_FUNC stencil_test_to_d3d_func(GrStencilTest test) {
-    switch (test) {
-        case GrStencilTest::kAlways:
-            return D3D12_COMPARISON_FUNC_ALWAYS;
-        case GrStencilTest::kNever:
-            return D3D12_COMPARISON_FUNC_NEVER;
-        case GrStencilTest::kGreater:
-            return D3D12_COMPARISON_FUNC_GREATER;
-        case GrStencilTest::kGEqual:
-            return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
-        case GrStencilTest::kLess:
-            return D3D12_COMPARISON_FUNC_LESS;
-        case GrStencilTest::kLEqual:
-            return D3D12_COMPARISON_FUNC_LESS_EQUAL;
-        case GrStencilTest::kEqual:
-            return D3D12_COMPARISON_FUNC_EQUAL;
-        case GrStencilTest::kNotEqual:
-            return D3D12_COMPARISON_FUNC_NOT_EQUAL;
-    }
-    SkUNREACHABLE;
-}
-
-static void setup_stencilop_desc(D3D12_DEPTH_STENCILOP_DESC* desc,
-                                 const GrStencilSettings::Face& stencilFace) {
-    desc->StencilFailOp = stencil_op_to_d3d_op(stencilFace.fFailOp);
-    desc->StencilDepthFailOp = desc->StencilFailOp;
-    desc->StencilPassOp = stencil_op_to_d3d_op(stencilFace.fPassOp);
-    desc->StencilFunc = stencil_test_to_d3d_func(stencilFace.fTest);
-}
-
-static void fill_in_depth_stencil_state(const GrProgramInfo& programInfo,
-                                        D3D12_DEPTH_STENCIL_DESC* dsDesc) {
-    GrStencilSettings stencilSettings = programInfo.nonGLStencilSettings();
-    GrSurfaceOrigin origin = programInfo.origin();
-
-    dsDesc->DepthEnable = false;
-    dsDesc->DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
-    dsDesc->DepthFunc = D3D12_COMPARISON_FUNC_NEVER;
-    dsDesc->StencilEnable = !stencilSettings.isDisabled();
-    if (!stencilSettings.isDisabled()) {
-        if (stencilSettings.isTwoSided()) {
-            const auto& frontFace = stencilSettings.postOriginCCWFace(origin);
-            const auto& backFace = stencilSettings.postOriginCCWFace(origin);
-
-            SkASSERT(frontFace.fTestMask == backFace.fTestMask);
-            SkASSERT(frontFace.fWriteMask == backFace.fWriteMask);
-            dsDesc->StencilReadMask = frontFace.fTestMask;
-            dsDesc->StencilWriteMask = frontFace.fWriteMask;
-
-            setup_stencilop_desc(&dsDesc->FrontFace, frontFace);
-            setup_stencilop_desc(&dsDesc->BackFace, backFace);
-        } else {
-            dsDesc->StencilReadMask = stencilSettings.singleSidedFace().fTestMask;
-            dsDesc->StencilWriteMask = stencilSettings.singleSidedFace().fTestMask;
-            setup_stencilop_desc(&dsDesc->FrontFace, stencilSettings.singleSidedFace());
-            dsDesc->BackFace = dsDesc->FrontFace;
-        }
-    }
-}
-
-static D3D12_PRIMITIVE_TOPOLOGY_TYPE gr_primitive_type_to_d3d(GrPrimitiveType primitiveType) {
-    switch (primitiveType) {
-        case GrPrimitiveType::kTriangles:
-        case GrPrimitiveType::kTriangleStrip: //fall through
-            return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
-        case GrPrimitiveType::kPoints:
-            return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
-        case GrPrimitiveType::kLines: // fall through
-        case GrPrimitiveType::kLineStrip:
-            return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
-        case GrPrimitiveType::kPatches: // fall through, unsupported
-        case GrPrimitiveType::kPath: // fall through, unsupported
-        default:
-            SkUNREACHABLE;
-    }
-}
-
-sk_sp<GrD3DPipelineState> GrD3DPipelineState::Make(GrD3DGpu* gpu,
-                                                   const GrProgramInfo& programInfo,
-                                                   sk_sp<GrD3DRootSignature> rootSig,
-                                                   gr_cp<ID3DBlob> vertexShader,
-                                                   gr_cp<ID3DBlob> geometryShader,
-                                                   gr_cp<ID3DBlob> pixelShader,
-                                                   DXGI_FORMAT renderTargetFormat,
-                                                   DXGI_FORMAT depthStencilFormat,
-                                                   unsigned int sampleQualityLevel) {
-    D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
-
-    psoDesc.pRootSignature = rootSig->rootSignature();
-
-    psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()),
-                   vertexShader->GetBufferSize() };
-    psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()),
-                   pixelShader->GetBufferSize() };
-
-    if (geometryShader.get()) {
-        psoDesc.GS = { reinterpret_cast<UINT8*>(geometryShader->GetBufferPointer()),
-                       geometryShader->GetBufferSize() };
-    }
-
-    psoDesc.StreamOutput = {nullptr, 0, nullptr, 0, 0};
-
-    fill_in_blend_state(programInfo.pipeline(), &psoDesc.BlendState);
-    psoDesc.SampleMask = UINT_MAX;
-
-    fill_in_rasterizer_state(programInfo.pipeline(), gpu->caps(), &psoDesc.RasterizerState);
-
-    fill_in_depth_stencil_state(programInfo, &psoDesc.DepthStencilState);
-
-    unsigned int totalAttributeCnt = programInfo.primProc().numVertexAttributes() +
-            programInfo.primProc().numInstanceAttributes();
-    SkAutoSTArray<4, D3D12_INPUT_ELEMENT_DESC> inputElements(totalAttributeCnt);
-    setup_vertex_input_layout(programInfo.primProc(), inputElements.get());
-
-    psoDesc.InputLayout = { inputElements.get(), totalAttributeCnt };
-
-    psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
-
-    // This is for geometry or hull shader primitives
-    psoDesc.PrimitiveTopologyType = gr_primitive_type_to_d3d(programInfo.primitiveType());
-
-    psoDesc.NumRenderTargets = 1;
-
-    psoDesc.RTVFormats[0] = renderTargetFormat;
-
-    psoDesc.DSVFormat = depthStencilFormat;
-
-    unsigned int numRasterSamples = programInfo.numRasterSamples();
-    psoDesc.SampleDesc = {numRasterSamples, sampleQualityLevel};
-
-    // Only used for multi-adapter systems.
-    psoDesc.NodeMask = 0;
-
-    psoDesc.CachedPSO = {nullptr, 0};
-    psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
-
-    gr_cp<ID3D12PipelineState> pipelineState;
-    SkDEBUGCODE(HRESULT hr = )gpu->device()->CreateGraphicsPipelineState(
-            &psoDesc, IID_PPV_ARGS(&pipelineState));
-    SkASSERT(SUCCEEDED(hr));
-
-    return sk_sp<GrD3DPipelineState>(new GrD3DPipelineState(std::move(pipelineState)));
-}
-
-GrD3DPipelineState::GrD3DPipelineState(gr_cp<ID3D12PipelineState> pipelineState)
-        : fPipelineState(std::move(pipelineState)) {}
diff --git a/src/gpu/d3d/GrD3DPipelineState.h b/src/gpu/d3d/GrD3DPipelineState.h
index b6eb50a..e8c6c45 100644
--- a/src/gpu/d3d/GrD3DPipelineState.h
+++ b/src/gpu/d3d/GrD3DPipelineState.h
@@ -12,6 +12,8 @@
 #include "include/gpu/GrTypes.h"
 #include "include/gpu/d3d/GrD3DTypes.h"
 #include "src/gpu/GrManagedResource.h"
+#include "src/gpu/d3d/GrD3DPipelineStateDataManager.h"
+#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
 
 class GrD3DGpu;
 class GrD3DRootSignature;
@@ -19,14 +21,16 @@
 
 class GrD3DPipelineState : public GrManagedResource {
 public:
-    static sk_sp<GrD3DPipelineState> Make(GrD3DGpu* gpu, const GrProgramInfo&,
-                                          sk_sp<GrD3DRootSignature> rootSig,
-                                          gr_cp<ID3DBlob> vertexShader,
-                                          gr_cp<ID3DBlob> geometryShader,
-                                          gr_cp<ID3DBlob> pixelShader,
-                                          DXGI_FORMAT renderTargetFormat,
-                                          DXGI_FORMAT depthStencilFormat,
-                                          unsigned int sampleQualityLevel);
+    using UniformInfoArray = GrD3DPipelineStateDataManager::UniformInfoArray;
+
+    GrD3DPipelineState(gr_cp<ID3D12PipelineState> pipelineState,
+                       const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
+                       const UniformInfoArray& uniforms,
+                       uint32_t uniformSize,
+                       std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
+                       std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
+                       std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragProcessors,
+                       int fragmentProcessorCnt);
 
 #ifdef SK_TRACE_MANAGED_RESOURCES
     /** Output a human-readable dump of this resource's information
@@ -42,11 +46,61 @@
 
     ID3D12PipelineState* pipelineState() const { return fPipelineState.get(); }
 
+    void setData(const GrRenderTarget* renderTarget, const GrProgramInfo& programInfo);
+
 private:
-    GrD3DPipelineState(gr_cp<ID3D12PipelineState> pipelineState);
+    /**
+     * We use the RT's size and origin to adjust from Skia device space to d3d normalized device
+     * space and to make device space positions have the correct origin for processors that require
+     * them.
+     */
+    struct RenderTargetState {
+        SkISize         fRenderTargetSize;
+        GrSurfaceOrigin fRenderTargetOrigin;
+
+        RenderTargetState() { this->invalidate(); }
+        void invalidate() {
+            fRenderTargetSize.fWidth = -1;
+            fRenderTargetSize.fHeight = -1;
+            fRenderTargetOrigin = (GrSurfaceOrigin)-1;
+        }
+
+        /**
+        * Gets a float4 that adjusts the position from Skia device coords to D3D's normalized device
+        * coords. Assuming the transformed position, pos, is a homogeneous float3, the vec, v, is
+        * applied as such:
+        * pos.x = dot(v.xy, pos.xz)
+        * pos.y = dot(v.zw, pos.yz)
+        */
+        void getRTAdjustmentVec(float* destVec) {
+            destVec[0] = 2.f / fRenderTargetSize.fWidth;
+            destVec[1] = -1.f;
+            if (kBottomLeft_GrSurfaceOrigin == fRenderTargetOrigin) {
+                destVec[2] = -2.f / fRenderTargetSize.fHeight;
+                destVec[3] = 1.f;
+            } else {
+                destVec[2] = 2.f / fRenderTargetSize.fHeight;
+                destVec[3] = -1.f;
+            }
+        }
+    };
+
+    // Helper for setData() that sets the view matrix and loads the render target height uniform
+    void setRenderTargetState(const GrRenderTarget*, GrSurfaceOrigin);
 
     gr_cp<ID3D12PipelineState> fPipelineState;
 
+    // Tracks the current render target uniforms stored in the vertex buffer.
+    RenderTargetState fRenderTargetState;
+    GrGLSLBuiltinUniformHandles fBuiltinUniformHandles;
+
+    // Processors in the GrD3DPipelineState
+    std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
+    std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
+    std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
+    int fFragmentProcessorCnt;
+
+    GrD3DPipelineStateDataManager fDataManager;
 };
 
 #endif
diff --git a/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp b/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp
index f03858e..4e60fe4 100644
--- a/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp
+++ b/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp
@@ -120,6 +120,387 @@
     }
 }
 
+static DXGI_FORMAT attrib_type_to_format(GrVertexAttribType type) {
+    switch (type) {
+    case kFloat_GrVertexAttribType:
+        return DXGI_FORMAT_R32_FLOAT;
+    case kFloat2_GrVertexAttribType:
+        return DXGI_FORMAT_R32G32_FLOAT;
+    case kFloat3_GrVertexAttribType:
+        return DXGI_FORMAT_R32G32B32_FLOAT;
+    case kFloat4_GrVertexAttribType:
+        return DXGI_FORMAT_R32G32B32A32_FLOAT;
+    case kHalf_GrVertexAttribType:
+        return DXGI_FORMAT_R16_FLOAT;
+    case kHalf2_GrVertexAttribType:
+        return DXGI_FORMAT_R16G16_FLOAT;
+    case kHalf4_GrVertexAttribType:
+        return DXGI_FORMAT_R16G16B16A16_FLOAT;
+    case kInt2_GrVertexAttribType:
+        return DXGI_FORMAT_R32G32_SINT;
+    case kInt3_GrVertexAttribType:
+        return DXGI_FORMAT_R32G32B32_SINT;
+    case kInt4_GrVertexAttribType:
+        return DXGI_FORMAT_R32G32B32A32_SINT;
+    case kByte_GrVertexAttribType:
+        return DXGI_FORMAT_R8_SINT;
+    case kByte2_GrVertexAttribType:
+        return DXGI_FORMAT_R8G8_SINT;
+    case kByte4_GrVertexAttribType:
+        return DXGI_FORMAT_R8G8B8A8_SINT;
+    case kUByte_GrVertexAttribType:
+        return DXGI_FORMAT_R8_UINT;
+    case kUByte2_GrVertexAttribType:
+        return DXGI_FORMAT_R8G8_UINT;
+    case kUByte4_GrVertexAttribType:
+        return DXGI_FORMAT_R8G8B8A8_UINT;
+    case kUByte_norm_GrVertexAttribType:
+        return DXGI_FORMAT_R8_UNORM;
+    case kUByte4_norm_GrVertexAttribType:
+        return DXGI_FORMAT_R8G8B8A8_UNORM;
+    case kShort2_GrVertexAttribType:
+        return DXGI_FORMAT_R16G16_SINT;
+    case kShort4_GrVertexAttribType:
+        return DXGI_FORMAT_R16G16B16A16_SINT;
+    case kUShort2_GrVertexAttribType:
+        return DXGI_FORMAT_R16G16_UINT;
+    case kUShort2_norm_GrVertexAttribType:
+        return DXGI_FORMAT_R16G16_UNORM;
+    case kInt_GrVertexAttribType:
+        return DXGI_FORMAT_R32_SINT;
+    case kUint_GrVertexAttribType:
+        return DXGI_FORMAT_R32_UINT;
+    case kUShort_norm_GrVertexAttribType:
+        return DXGI_FORMAT_R16_UNORM;
+    case kUShort4_norm_GrVertexAttribType:
+        return DXGI_FORMAT_R16G16B16A16_UNORM;
+    }
+    SK_ABORT("Unknown vertex attrib type");
+}
+
+static void setup_vertex_input_layout(const GrPrimitiveProcessor& primProc,
+                                      D3D12_INPUT_ELEMENT_DESC* inputElements) {
+    unsigned int slotNumber = 0;
+    unsigned int vertexSlot = 0;
+    unsigned int instanceSlot = 0;
+    if (primProc.hasVertexAttributes()) {
+        vertexSlot = slotNumber++;
+    }
+    if (primProc.hasInstanceAttributes()) {
+        instanceSlot = slotNumber++;
+    }
+
+    unsigned int currentAttrib = 0;
+    unsigned int vertexAttributeOffset = 0;
+
+    for (const auto& attrib : primProc.vertexAttributes()) {
+        // When using SPIRV-Cross it converts the location modifier in SPIRV to be
+        // TEXCOORD<N> where N is the location value for eveery vertext attribute
+        inputElements[currentAttrib] = { "TEXCOORD", currentAttrib,
+                                        attrib_type_to_format(attrib.cpuType()),
+                                        vertexSlot, vertexAttributeOffset,
+                                        D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
+        vertexAttributeOffset += attrib.sizeAlign4();
+        currentAttrib++;
+    }
+    SkASSERT(vertexAttributeOffset == primProc.vertexStride());
+
+    unsigned int instanceAttributeOffset = 0;
+    for (const auto& attrib : primProc.instanceAttributes()) {
+        // When using SPIRV-Cross it converts the location modifier in SPIRV to be
+        // TEXCOORD<N> where N is the location value for eveery vertext attribute
+        inputElements[currentAttrib] = { "TEXCOORD", currentAttrib,
+                                        attrib_type_to_format(attrib.cpuType()),
+                                        instanceSlot, instanceAttributeOffset,
+                                        D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 };
+        instanceAttributeOffset += attrib.sizeAlign4();
+        currentAttrib++;
+    }
+    SkASSERT(instanceAttributeOffset == primProc.instanceStride());
+}
+
+static D3D12_BLEND blend_coeff_to_d3d_blend(GrBlendCoeff coeff) {
+    switch (coeff) {
+    case kZero_GrBlendCoeff:
+        return D3D12_BLEND_ZERO;
+    case kOne_GrBlendCoeff:
+        return D3D12_BLEND_ONE;
+    case kSC_GrBlendCoeff:
+        return D3D12_BLEND_SRC_COLOR;
+    case kISC_GrBlendCoeff:
+        return D3D12_BLEND_INV_SRC_COLOR;
+    case kDC_GrBlendCoeff:
+        return D3D12_BLEND_DEST_COLOR;
+    case kIDC_GrBlendCoeff:
+        return D3D12_BLEND_INV_DEST_COLOR;
+    case kSA_GrBlendCoeff:
+        return D3D12_BLEND_SRC_ALPHA;
+    case kISA_GrBlendCoeff:
+        return D3D12_BLEND_INV_SRC_ALPHA;
+    case kDA_GrBlendCoeff:
+        return D3D12_BLEND_DEST_ALPHA;
+    case kIDA_GrBlendCoeff:
+        return D3D12_BLEND_INV_DEST_ALPHA;
+    case kConstC_GrBlendCoeff:
+        return D3D12_BLEND_BLEND_FACTOR;
+    case kIConstC_GrBlendCoeff:
+        return D3D12_BLEND_INV_BLEND_FACTOR;
+    case kS2C_GrBlendCoeff:
+        return D3D12_BLEND_SRC1_COLOR;
+    case kIS2C_GrBlendCoeff:
+        return D3D12_BLEND_INV_SRC1_COLOR;
+    case kS2A_GrBlendCoeff:
+        return D3D12_BLEND_SRC1_ALPHA;
+    case kIS2A_GrBlendCoeff:
+        return D3D12_BLEND_INV_SRC1_ALPHA;
+    case kIllegal_GrBlendCoeff:
+        return D3D12_BLEND_ZERO;
+    }
+    SkUNREACHABLE;
+}
+
+static D3D12_BLEND blend_coeff_to_d3d_blend_for_alpha(GrBlendCoeff coeff) {
+    switch (coeff) {
+        // Force all srcColor used in alpha slot to alpha version.
+    case kSC_GrBlendCoeff:
+        return D3D12_BLEND_SRC_ALPHA;
+    case kISC_GrBlendCoeff:
+        return D3D12_BLEND_INV_SRC_ALPHA;
+    case kDC_GrBlendCoeff:
+        return D3D12_BLEND_DEST_ALPHA;
+    case kIDC_GrBlendCoeff:
+        return D3D12_BLEND_INV_DEST_ALPHA;
+    case kS2C_GrBlendCoeff:
+        return D3D12_BLEND_SRC1_ALPHA;
+    case kIS2C_GrBlendCoeff:
+        return D3D12_BLEND_INV_SRC1_ALPHA;
+
+    default:
+        return blend_coeff_to_d3d_blend(coeff);
+    }
+}
+
+
+static D3D12_BLEND_OP blend_equation_to_d3d_op(GrBlendEquation equation) {
+    switch (equation) {
+    case kAdd_GrBlendEquation:
+        return D3D12_BLEND_OP_ADD;
+    case kSubtract_GrBlendEquation:
+        return D3D12_BLEND_OP_SUBTRACT;
+    case kReverseSubtract_GrBlendEquation:
+        return D3D12_BLEND_OP_REV_SUBTRACT;
+    default:
+        SkUNREACHABLE;
+    }
+}
+
+static void fill_in_blend_state(const GrPipeline& pipeline, D3D12_BLEND_DESC* blendDesc) {
+    blendDesc->AlphaToCoverageEnable = false;
+    blendDesc->IndependentBlendEnable = false;
+
+    const GrXferProcessor::BlendInfo& blendInfo = pipeline.getXferProcessor().getBlendInfo();
+
+    GrBlendEquation equation = blendInfo.fEquation;
+    GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
+    GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
+    bool blendOff = GrBlendShouldDisable(equation, srcCoeff, dstCoeff);
+
+    auto& rtBlend = blendDesc->RenderTarget[0];
+    rtBlend.BlendEnable = !blendOff;
+    if (!blendOff) {
+        rtBlend.SrcBlend = blend_coeff_to_d3d_blend(srcCoeff);
+        rtBlend.DestBlend = blend_coeff_to_d3d_blend(dstCoeff);
+        rtBlend.BlendOp = blend_equation_to_d3d_op(equation);
+        rtBlend.SrcBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(srcCoeff);
+        rtBlend.DestBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(dstCoeff);
+        rtBlend.BlendOpAlpha = blend_equation_to_d3d_op(equation);
+    }
+
+    if (!blendInfo.fWriteColor) {
+        rtBlend.RenderTargetWriteMask = 0;
+    } else {
+        rtBlend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+    }
+}
+
+static void fill_in_rasterizer_state(const GrPipeline& pipeline, const GrCaps* caps,
+                                     D3D12_RASTERIZER_DESC* rasterizer) {
+    rasterizer->FillMode = (caps->wireframeMode() || pipeline.isWireframe()) ?
+        D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID;
+    rasterizer->CullMode = D3D12_CULL_MODE_NONE;
+    rasterizer->FrontCounterClockwise = true;
+    rasterizer->DepthBias = 0;
+    rasterizer->DepthBiasClamp = 0.0f;
+    rasterizer->SlopeScaledDepthBias = 0.0f;
+    rasterizer->DepthClipEnable = false;
+    rasterizer->MultisampleEnable = pipeline.isHWAntialiasState();
+    rasterizer->AntialiasedLineEnable = false;
+    rasterizer->ForcedSampleCount = 0;
+    rasterizer->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+}
+
+static D3D12_STENCIL_OP stencil_op_to_d3d_op(GrStencilOp op) {
+    switch (op) {
+    case GrStencilOp::kKeep:
+        return D3D12_STENCIL_OP_KEEP;
+    case GrStencilOp::kZero:
+        return D3D12_STENCIL_OP_ZERO;
+    case GrStencilOp::kReplace:
+        return D3D12_STENCIL_OP_REPLACE;
+    case GrStencilOp::kInvert:
+        return D3D12_STENCIL_OP_INVERT;
+    case GrStencilOp::kIncWrap:
+        return D3D12_STENCIL_OP_INCR;
+    case GrStencilOp::kDecWrap:
+        return D3D12_STENCIL_OP_DECR;
+    case GrStencilOp::kIncClamp:
+        return D3D12_STENCIL_OP_INCR_SAT;
+    case GrStencilOp::kDecClamp:
+        return D3D12_STENCIL_OP_DECR_SAT;
+    }
+    SkUNREACHABLE;
+}
+
+static D3D12_COMPARISON_FUNC stencil_test_to_d3d_func(GrStencilTest test) {
+    switch (test) {
+    case GrStencilTest::kAlways:
+        return D3D12_COMPARISON_FUNC_ALWAYS;
+    case GrStencilTest::kNever:
+        return D3D12_COMPARISON_FUNC_NEVER;
+    case GrStencilTest::kGreater:
+        return D3D12_COMPARISON_FUNC_GREATER;
+    case GrStencilTest::kGEqual:
+        return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
+    case GrStencilTest::kLess:
+        return D3D12_COMPARISON_FUNC_LESS;
+    case GrStencilTest::kLEqual:
+        return D3D12_COMPARISON_FUNC_LESS_EQUAL;
+    case GrStencilTest::kEqual:
+        return D3D12_COMPARISON_FUNC_EQUAL;
+    case GrStencilTest::kNotEqual:
+        return D3D12_COMPARISON_FUNC_NOT_EQUAL;
+    }
+    SkUNREACHABLE;
+}
+
+static void setup_stencilop_desc(D3D12_DEPTH_STENCILOP_DESC* desc,
+                                 const GrStencilSettings::Face& stencilFace) {
+    desc->StencilFailOp = stencil_op_to_d3d_op(stencilFace.fFailOp);
+    desc->StencilDepthFailOp = desc->StencilFailOp;
+    desc->StencilPassOp = stencil_op_to_d3d_op(stencilFace.fPassOp);
+    desc->StencilFunc = stencil_test_to_d3d_func(stencilFace.fTest);
+}
+
+static void fill_in_depth_stencil_state(const GrProgramInfo& programInfo,
+                                        D3D12_DEPTH_STENCIL_DESC* dsDesc) {
+    GrStencilSettings stencilSettings = programInfo.nonGLStencilSettings();
+    GrSurfaceOrigin origin = programInfo.origin();
+
+    dsDesc->DepthEnable = false;
+    dsDesc->DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
+    dsDesc->DepthFunc = D3D12_COMPARISON_FUNC_NEVER;
+    dsDesc->StencilEnable = !stencilSettings.isDisabled();
+    if (!stencilSettings.isDisabled()) {
+        if (stencilSettings.isTwoSided()) {
+            const auto& frontFace = stencilSettings.postOriginCCWFace(origin);
+            const auto& backFace = stencilSettings.postOriginCCWFace(origin);
+
+            SkASSERT(frontFace.fTestMask == backFace.fTestMask);
+            SkASSERT(frontFace.fWriteMask == backFace.fWriteMask);
+            dsDesc->StencilReadMask = frontFace.fTestMask;
+            dsDesc->StencilWriteMask = frontFace.fWriteMask;
+
+            setup_stencilop_desc(&dsDesc->FrontFace, frontFace);
+            setup_stencilop_desc(&dsDesc->BackFace, backFace);
+        } else {
+            dsDesc->StencilReadMask = stencilSettings.singleSidedFace().fTestMask;
+            dsDesc->StencilWriteMask = stencilSettings.singleSidedFace().fTestMask;
+            setup_stencilop_desc(&dsDesc->FrontFace, stencilSettings.singleSidedFace());
+            dsDesc->BackFace = dsDesc->FrontFace;
+        }
+    }
+}
+
+static D3D12_PRIMITIVE_TOPOLOGY_TYPE gr_primitive_type_to_d3d(GrPrimitiveType primitiveType) {
+    switch (primitiveType) {
+    case GrPrimitiveType::kTriangles:
+    case GrPrimitiveType::kTriangleStrip: //fall through
+        return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+    case GrPrimitiveType::kPoints:
+        return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
+    case GrPrimitiveType::kLines: // fall through
+    case GrPrimitiveType::kLineStrip:
+        return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
+    case GrPrimitiveType::kPatches: // fall through, unsupported
+    case GrPrimitiveType::kPath: // fall through, unsupported
+    default:
+        SkUNREACHABLE;
+    }
+}
+
+gr_cp<ID3D12PipelineState> create_pipeline_state(
+    GrD3DGpu* gpu, const GrProgramInfo& programInfo, sk_sp<GrD3DRootSignature> rootSig,
+    gr_cp<ID3DBlob> vertexShader, gr_cp<ID3DBlob> geometryShader, gr_cp<ID3DBlob> pixelShader,
+    DXGI_FORMAT renderTargetFormat, DXGI_FORMAT depthStencilFormat,
+    unsigned int sampleQualityLevel) {
+    D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+
+    psoDesc.pRootSignature = rootSig->rootSignature();
+
+    psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()),
+                   vertexShader->GetBufferSize() };
+    psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()),
+                   pixelShader->GetBufferSize() };
+
+    if (geometryShader.get()) {
+        psoDesc.GS = { reinterpret_cast<UINT8*>(geometryShader->GetBufferPointer()),
+                       geometryShader->GetBufferSize() };
+    }
+
+    psoDesc.StreamOutput = { nullptr, 0, nullptr, 0, 0 };
+
+    fill_in_blend_state(programInfo.pipeline(), &psoDesc.BlendState);
+    psoDesc.SampleMask = UINT_MAX;
+
+    fill_in_rasterizer_state(programInfo.pipeline(), gpu->caps(), &psoDesc.RasterizerState);
+
+    fill_in_depth_stencil_state(programInfo, &psoDesc.DepthStencilState);
+
+    unsigned int totalAttributeCnt = programInfo.primProc().numVertexAttributes() +
+        programInfo.primProc().numInstanceAttributes();
+    SkAutoSTArray<4, D3D12_INPUT_ELEMENT_DESC> inputElements(totalAttributeCnt);
+    setup_vertex_input_layout(programInfo.primProc(), inputElements.get());
+
+    psoDesc.InputLayout = { inputElements.get(), totalAttributeCnt };
+
+    psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
+
+    // This is for geometry or hull shader primitives
+    psoDesc.PrimitiveTopologyType = gr_primitive_type_to_d3d(programInfo.primitiveType());
+
+    psoDesc.NumRenderTargets = 1;
+
+    psoDesc.RTVFormats[0] = renderTargetFormat;
+
+    psoDesc.DSVFormat = depthStencilFormat;
+
+    unsigned int numRasterSamples = programInfo.numRasterSamples();
+    psoDesc.SampleDesc = { numRasterSamples, sampleQualityLevel };
+
+    // Only used for multi-adapter systems.
+    psoDesc.NodeMask = 0;
+
+    psoDesc.CachedPSO = { nullptr, 0 };
+    psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
+
+    gr_cp<ID3D12PipelineState> pipelineState;
+    SkDEBUGCODE(HRESULT hr = )gpu->device()->CreateGraphicsPipelineState(
+        &psoDesc, IID_PPV_ARGS(&pipelineState));
+    SkASSERT(SUCCEEDED(hr));
+
+    return pipelineState;
+}
+
 sk_sp<GrD3DPipelineState> GrD3DPipelineStateBuilder::finalize() {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
 
@@ -170,8 +551,17 @@
     }
 
     const GrD3DRenderTarget* rt = static_cast<const GrD3DRenderTarget*>(fRenderTarget);
-    return GrD3DPipelineState::Make(fGpu, fProgramInfo, std::move(rootSig),
-                                    std::move(vertexShader), std::move(geometryShader),
-                                    std::move(pixelShader), rt->dxgiFormat(),
-                                    rt->stencilDxgiFormat(), rt->sampleQualityLevel());
+    gr_cp<ID3D12PipelineState> pipelineState = create_pipeline_state(
+            fGpu, fProgramInfo, std::move(rootSig), std::move(vertexShader),
+            std::move(geometryShader), std::move(pixelShader), rt->dxgiFormat(),
+            rt->stencilDxgiFormat(), rt->sampleQualityLevel());
+
+    return sk_sp<GrD3DPipelineState>(new GrD3DPipelineState(std::move(pipelineState),
+                                                            fUniformHandles,
+                                                            fUniformHandler.fUniforms,
+                                                            fUniformHandler.fCurrentUBOOffset,
+                                                            std::move(fGeometryProcessor),
+                                                            std::move(fXferProcessor),
+                                                            std::move(fFragmentProcessors),
+                                                            fFragmentProcessorCnt));
 }
diff --git a/src/gpu/d3d/GrD3DPipelineStateDataManager.cpp b/src/gpu/d3d/GrD3DPipelineStateDataManager.cpp
new file mode 100644
index 0000000..9326099
--- /dev/null
+++ b/src/gpu/d3d/GrD3DPipelineStateDataManager.cpp
@@ -0,0 +1,28 @@
+/*
+* 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 "src/gpu/d3d/GrD3DPipelineStateDataManager.h"
+
+GrD3DPipelineStateDataManager::GrD3DPipelineStateDataManager(const UniformInfoArray& uniforms,
+                                                             uint32_t uniformSize)
+    : INHERITED(uniforms.count(), uniformSize) {
+    // We must add uniforms in same order as the UniformInfoArray so that UniformHandles already
+    // owned by other objects will still match up here.
+    int i = 0;
+    for (const auto& uniformInfo : uniforms.items()) {
+        Uniform& uniform = fUniforms[i];
+        SkASSERT(GrShaderVar::kNonArray == uniformInfo.fVariable.getArrayCount() ||
+                 uniformInfo.fVariable.getArrayCount() > 0);
+        SkDEBUGCODE(
+            uniform.fArrayCount = uniformInfo.fVariable.getArrayCount();
+            uniform.fType = uniformInfo.fVariable.getType();
+        )
+
+        uniform.fOffset = uniformInfo.fUBOOffset;
+        ++i;
+    }
+}
diff --git a/src/gpu/d3d/GrD3DPipelineStateDataManager.h b/src/gpu/d3d/GrD3DPipelineStateDataManager.h
new file mode 100644
index 0000000..14d9c2e
--- /dev/null
+++ b/src/gpu/d3d/GrD3DPipelineStateDataManager.h
@@ -0,0 +1,29 @@
+/*
+* Copyright 2020 Google LLC
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef GrD3DPipelineStateDataManager_DEFINED
+#define GrD3DPipelineStateDataManager_DEFINED
+
+#include "src/gpu/GrUniformDataManager.h"
+
+#include "include/gpu/d3d/GrD3DTypes.h"
+#include "src/gpu/GrSPIRVUniformHandler.h"
+
+class GrD3DPipelineStateDataManager : public GrUniformDataManager {
+public:
+    typedef GrSPIRVUniformHandler::UniformInfoArray UniformInfoArray;
+
+    GrD3DPipelineStateDataManager(const UniformInfoArray&,
+                                  uint32_t uniformSize);
+
+    // TODO: upload to uniform buffer
+
+private:
+    typedef GrUniformDataManager INHERITED;
+};
+
+#endif
diff --git a/src/gpu/vk/GrVkPipelineStateDataManager.cpp b/src/gpu/vk/GrVkPipelineStateDataManager.cpp
index bd0c8d4..8377437 100644
--- a/src/gpu/vk/GrVkPipelineStateDataManager.cpp
+++ b/src/gpu/vk/GrVkPipelineStateDataManager.cpp
@@ -12,11 +12,8 @@
 
 GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArray& uniforms,
                                                            uint32_t uniformSize)
-    : fUniformSize(uniformSize)
-    , fUniformsDirty(false) {
-    fUniformData.reset(uniformSize);
-    fUniforms.push_back_n(uniforms.count());
-    // We must add uniforms in same order is the UniformInfoArray so that UniformHandles already
+    : INHERITED(uniforms.count(), uniformSize) {
+    // We must add uniforms in same order as the UniformInfoArray so that UniformHandles already
     // owned by other objects will still match up here.
     int i = 0;
     for (const auto& uniformInfo : uniforms.items()) {
@@ -33,306 +30,6 @@
     }
 }
 
-void* GrVkPipelineStateDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const {
-    fUniformsDirty = true;
-    return static_cast<char*>(fUniformData.get())+uni.fOffset;
-}
-
-void GrVkPipelineStateDataManager::set1i(UniformHandle u, int32_t i) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType);
-    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    memcpy(buffer, &i, sizeof(int32_t));
-}
-
-void GrVkPipelineStateDataManager::set1iv(UniformHandle u,
-                                          int arrayCount,
-                                          const int32_t v[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType);
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(int32_t) == 4);
-    for (int i = 0; i < arrayCount; ++i) {
-        const int32_t* curVec = &v[i];
-        memcpy(buffer, curVec, sizeof(int32_t));
-        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
-    }
-}
-
-void GrVkPipelineStateDataManager::set1f(UniformHandle u, float v0) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType);
-    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(float) == 4);
-    memcpy(buffer, &v0, sizeof(float));
-}
-
-void GrVkPipelineStateDataManager::set1fv(UniformHandle u,
-                                          int arrayCount,
-                                          const float v[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType);
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(float) == 4);
-    for (int i = 0; i < arrayCount; ++i) {
-        const float* curVec = &v[i];
-        memcpy(buffer, curVec, sizeof(float));
-        buffer = static_cast<char*>(buffer) + 4*sizeof(float);
-    }
-}
-
-void GrVkPipelineStateDataManager::set2i(UniformHandle u, int32_t i0, int32_t i1) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType);
-    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    int32_t v[2] = { i0, i1 };
-    memcpy(buffer, v, 2 * sizeof(int32_t));
-}
-
-void GrVkPipelineStateDataManager::set2iv(UniformHandle u,
-                                          int arrayCount,
-                                          const int32_t v[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType);
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(int32_t) == 4);
-    for (int i = 0; i < arrayCount; ++i) {
-        const int32_t* curVec = &v[2 * i];
-        memcpy(buffer, curVec, 2 * sizeof(int32_t));
-        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
-    }
-}
-
-void GrVkPipelineStateDataManager::set2f(UniformHandle u, float v0, float v1) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType);
-    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(float) == 4);
-    float v[2] = { v0, v1 };
-    memcpy(buffer, v, 2 * sizeof(float));
-}
-
-void GrVkPipelineStateDataManager::set2fv(UniformHandle u,
-                                          int arrayCount,
-                                          const float v[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType);
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(float) == 4);
-    for (int i = 0; i < arrayCount; ++i) {
-        const float* curVec = &v[2 * i];
-        memcpy(buffer, curVec, 2 * sizeof(float));
-        buffer = static_cast<char*>(buffer) + 4*sizeof(float);
-    }
-}
-
-void GrVkPipelineStateDataManager::set3i(UniformHandle u,
-                                         int32_t i0,
-                                         int32_t i1,
-                                         int32_t i2) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType);
-    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    int32_t v[3] = { i0, i1, i2 };
-    memcpy(buffer, v, 3 * sizeof(int32_t));
-}
-
-void GrVkPipelineStateDataManager::set3iv(UniformHandle u,
-                                          int arrayCount,
-                                          const int32_t v[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType);
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(int32_t) == 4);
-    for (int i = 0; i < arrayCount; ++i) {
-        const int32_t* curVec = &v[3 * i];
-        memcpy(buffer, curVec, 3 * sizeof(int32_t));
-        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
-    }
-}
-
-void GrVkPipelineStateDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType);
-    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(float) == 4);
-    float v[3] = { v0, v1, v2 };
-    memcpy(buffer, v, 3 * sizeof(float));
-}
-
-void GrVkPipelineStateDataManager::set3fv(UniformHandle u,
-                                          int arrayCount,
-                                          const float v[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType);
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(float) == 4);
-    for (int i = 0; i < arrayCount; ++i) {
-        const float* curVec = &v[3 * i];
-        memcpy(buffer, curVec, 3 * sizeof(float));
-        buffer = static_cast<char*>(buffer) + 4*sizeof(float);
-    }
-}
-
-void GrVkPipelineStateDataManager::set4i(UniformHandle u,
-                                         int32_t i0,
-                                         int32_t i1,
-                                         int32_t i2,
-                                         int32_t i3) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType);
-    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    int32_t v[4] = { i0, i1, i2, i3 };
-    memcpy(buffer, v, 4 * sizeof(int32_t));
-}
-
-void GrVkPipelineStateDataManager::set4iv(UniformHandle u,
-                                          int arrayCount,
-                                          const int32_t v[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType);
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(int32_t) == 4);
-    for (int i = 0; i < arrayCount; ++i) {
-        const int32_t* curVec = &v[4 * i];
-        memcpy(buffer, curVec, 4 * sizeof(int32_t));
-        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
-    }
-}
-
-void GrVkPipelineStateDataManager::set4f(UniformHandle u,
-                                         float v0,
-                                         float v1,
-                                         float v2,
-                                         float v3) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType);
-    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(float) == 4);
-    float v[4] = { v0, v1, v2, v3 };
-    memcpy(buffer, v, 4 * sizeof(float));
-}
-
-void GrVkPipelineStateDataManager::set4fv(UniformHandle u,
-                                          int arrayCount,
-                                          const float v[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType);
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = this->getBufferPtrAndMarkDirty(uni);
-    SkASSERT(sizeof(float) == 4);
-    memcpy(buffer, v, arrayCount * 4 * sizeof(float));
-}
-
-void GrVkPipelineStateDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const {
-    this->setMatrices<2>(u, 1, matrix);
-}
-
-void GrVkPipelineStateDataManager::setMatrix2fv(UniformHandle u,
-                                                int arrayCount,
-                                                const float m[]) const {
-    this->setMatrices<2>(u, arrayCount, m);
-}
-
-void GrVkPipelineStateDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const {
-    this->setMatrices<3>(u, 1, matrix);
-}
-
-void GrVkPipelineStateDataManager::setMatrix3fv(UniformHandle u,
-                                                int arrayCount,
-                                                const float m[]) const {
-    this->setMatrices<3>(u, arrayCount, m);
-}
-
-void GrVkPipelineStateDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const {
-    this->setMatrices<4>(u, 1, matrix);
-}
-
-void GrVkPipelineStateDataManager::setMatrix4fv(UniformHandle u,
-                                                int arrayCount,
-                                                const float m[]) const {
-    this->setMatrices<4>(u, arrayCount, m);
-}
-
-template<int N> struct set_uniform_matrix;
-
-template<int N> inline void GrVkPipelineStateDataManager::setMatrices(UniformHandle u,
-                                                                      int arrayCount,
-                                                                     const float matrices[]) const {
-    const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kFloat2x2_GrSLType + (N - 2) ||
-             uni.fType == kHalf2x2_GrSLType + (N - 2));
-    SkASSERT(arrayCount > 0);
-    SkASSERT(arrayCount <= uni.fArrayCount ||
-             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
-
-    void* buffer = fUniformData.get();
-    fUniformsDirty = true;
-
-    set_uniform_matrix<N>::set(buffer, uni.fOffset, arrayCount, matrices);
-}
-
-template<int N> struct set_uniform_matrix {
-    inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) {
-        static_assert(sizeof(float) == 4);
-        buffer = static_cast<char*>(buffer) + uniformOffset;
-        for (int i = 0; i < count; ++i) {
-            const float* matrix = &matrices[N * N * i];
-            for (int j = 0; j < N; ++j) {
-                memcpy(buffer, &matrix[j * N], N * sizeof(float));
-                buffer = static_cast<char*>(buffer) + 4 * sizeof(float);
-            }
-        }
-    }
-};
-
-template<> struct set_uniform_matrix<4> {
-    inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) {
-        static_assert(sizeof(float) == 4);
-        buffer = static_cast<char*>(buffer) + uniformOffset;
-        memcpy(buffer, matrices, count * 16 * sizeof(float));
-    }
-};
-
 bool GrVkPipelineStateDataManager::uploadUniformBuffers(GrVkGpu* gpu,
                                                         GrVkUniformBuffer* buffer) const {
     bool updatedBuffer = false;
diff --git a/src/gpu/vk/GrVkPipelineStateDataManager.h b/src/gpu/vk/GrVkPipelineStateDataManager.h
index 91d5092..b090dd6 100644
--- a/src/gpu/vk/GrVkPipelineStateDataManager.h
+++ b/src/gpu/vk/GrVkPipelineStateDataManager.h
@@ -8,78 +8,28 @@
 #ifndef GrVkPipelineStateDataManager_DEFINED
 #define GrVkPipelineStateDataManager_DEFINED
 
-#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
+#include "src/gpu/GrUniformDataManager.h"
 
 #include "include/gpu/vk/GrVkTypes.h"
-#include "src/core/SkAutoMalloc.h"
 #include "src/gpu/vk/GrVkUniformHandler.h"
 
 class GrVkGpu;
 class GrVkUniformBuffer;
 
-class GrVkPipelineStateDataManager : public GrGLSLProgramDataManager {
+class GrVkPipelineStateDataManager : public GrUniformDataManager {
 public:
     typedef GrVkUniformHandler::UniformInfoArray UniformInfoArray;
 
     GrVkPipelineStateDataManager(const UniformInfoArray&,
                                  uint32_t uniformSize);
 
-    void set1i(UniformHandle, int32_t) const override;
-    void set1iv(UniformHandle, int arrayCount, const int32_t v[]) const override;
-    void set1f(UniformHandle, float v0) const override;
-    void set1fv(UniformHandle, int arrayCount, const float v[]) const override;
-    void set2i(UniformHandle, int32_t, int32_t) const override;
-    void set2iv(UniformHandle, int arrayCount, const int32_t v[]) const override;
-    void set2f(UniformHandle, float, float) const override;
-    void set2fv(UniformHandle, int arrayCount, const float v[]) const override;
-    void set3i(UniformHandle, int32_t, int32_t, int32_t) const override;
-    void set3iv(UniformHandle, int arrayCount, const int32_t v[]) const override;
-    void set3f(UniformHandle, float, float, float) const override;
-    void set3fv(UniformHandle, int arrayCount, const float v[]) const override;
-    void set4i(UniformHandle, int32_t, int32_t, int32_t, int32_t) const override;
-    void set4iv(UniformHandle, int arrayCount, const int32_t v[]) const override;
-    void set4f(UniformHandle, float, float, float, float) const override;
-    void set4fv(UniformHandle, int arrayCount, const float v[]) const override;
-    // matrices are column-major, the first two upload a single matrix, the latter two upload
-    // arrayCount matrices into a uniform array.
-    void setMatrix2f(UniformHandle, const float matrix[]) const override;
-    void setMatrix3f(UniformHandle, const float matrix[]) const override;
-    void setMatrix4f(UniformHandle, const float matrix[]) const override;
-    void setMatrix2fv(UniformHandle, int arrayCount, const float matrices[]) const override;
-    void setMatrix3fv(UniformHandle, int arrayCount, const float matrices[]) const override;
-    void setMatrix4fv(UniformHandle, int arrayCount, const float matrices[]) const override;
-
-    // for nvpr only
-    void setPathFragmentInputTransform(VaryingHandle u, int components,
-                                       const SkMatrix& matrix) const override {
-        SK_ABORT("Only supported in NVPR, which is not in vulkan");
-    }
-
     // Returns true if either the geometry or fragment buffers needed to generate a new underlying
     // VkBuffer object in order upload data. If true is returned, this is a signal to the caller
     // that they will need to update the descriptor set that is using these buffers.
     bool uploadUniformBuffers(GrVkGpu* gpu,
                               GrVkUniformBuffer* buffer) const;
 private:
-    struct Uniform {
-        uint32_t fOffset;
-        SkDEBUGCODE(
-            GrSLType    fType;
-            int         fArrayCount;
-        );
-    };
-
-    template<int N> inline void setMatrices(UniformHandle, int arrayCount,
-                                            const float matrices[]) const;
-
-    void* getBufferPtrAndMarkDirty(const Uniform& uni) const;
-
-    uint32_t fUniformSize;
-
-    SkTArray<Uniform, true> fUniforms;
-
-    mutable SkAutoMalloc fUniformData;
-    mutable bool         fUniformsDirty;
+    typedef GrUniformDataManager INHERITED;
 };
 
 #endif