Consolidate uniforms into a single buffer

We were set up to have different uniform buffers for every draw, but it makes more sense to just put all the info into a single shared buffer.

Diffs=
0796b5c1c Consolidate uniforms into a single buffer (#5447)

Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
diff --git a/.rive_head b/.rive_head
index 6aa03ad..6875d5f 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-7ee5f7d5a9af82205d32bfb979fdaac412b51cad
+0796b5c1cd3376619615931ffe67ad93a2005a05
diff --git a/include/rive/pls/pls.hpp b/include/rive/pls/pls.hpp
index d0114d7..147494c 100644
--- a/include/rive/pls/pls.hpp
+++ b/include/rive/pls/pls.hpp
@@ -6,6 +6,7 @@
 
 #include "rive/math/mat2d.hpp"
 #include "rive/math/path_types.hpp"
+#include "rive/math/simd.hpp"
 #include "rive/math/vec2d.hpp"
 #include "rive/shapes/paint/color.hpp"
 #include "rive/shapes/paint/stroke_join.hpp"
@@ -151,41 +152,29 @@
     bool avoidFlatVaryings = false;
 };
 
-// Uniform buffer layout for the gradient color ramp shader.
-struct ColorRampUniforms
+// Per-flush shared uniforms used by all shaders.
+struct FlushUniforms
 {
-    float viewportHeight;
-};
-
-// Uniform buffer layout for the tessellation shader.
-struct TessellateUniforms
-{
-    float viewportWidth;
-    float viewportHeight;
-};
-
-// Per-flush uniforms used by the draw shader.
-struct DrawUniforms
-{
-    DrawUniforms(float viewportWidth_,
-                 float viewportHeight_,
-                 size_t gradTextureHeight,
-                 const PlatformFeatures& platformFeatures) :
-        viewportWidth(viewportWidth_),
-        viewportHeight(viewportHeight_),
-        gradTextureInverseHeight(1.f / gradTextureHeight),
+    FlushUniforms(size_t complexGradientsHeight,
+                  size_t tessDataHeight,
+                  size_t renderTargetWidth,
+                  size_t renderTargetHeight,
+                  size_t gradTextureHeight,
+                  const PlatformFeatures& platformFeatures) :
+        inverseViewports(2.f / float4{static_cast<float>(complexGradientsHeight),
+                                      static_cast<float>(tessDataHeight),
+                                      static_cast<float>(renderTargetWidth),
+                                      static_cast<float>(renderTargetHeight)}),
+        gradTextureInverseHeight(1.f / static_cast<float>(gradTextureHeight)),
         pathIDGranularity(platformFeatures.pathIDGranularity)
     {}
-    float viewportWidth;
-    float viewportHeight;
+    float4 inverseViewports; // [complexGradientsY, tessDataY, renderTargetX, renderTargetY]
     float gradTextureInverseHeight;
     uint32_t pathIDGranularity; // Spacing between adjacent path IDs (1 if IEEE compliant).
     float vertexDiscardValue = std::numeric_limits<float>::quiet_NaN();
-    uint32_t pad0 = 0;
-    uint32_t pad1 = 0;
-    uint32_t pad2 = 0;
+    uint32_t pad = 0;
 };
-static_assert(sizeof(DrawUniforms) == 8 * sizeof(uint32_t));
+static_assert(sizeof(FlushUniforms) == 8 * sizeof(uint32_t));
 
 // Gradient color stops are implemented as a horizontal span of pixels in a global gradient texture.
 // They are rendered by "GradientSpan" instances.
diff --git a/include/rive/pls/pls_render_context.hpp b/include/rive/pls/pls_render_context.hpp
index 58b1ae8..a3b3274 100644
--- a/include/rive/pls/pls_render_context.hpp
+++ b/include/rive/pls/pls_render_context.hpp
@@ -233,18 +233,6 @@
 
     virtual void allocateTessellationTexture(size_t height) = 0;
 
-    const BufferRingImpl* colorRampUniforms() const
-    {
-        return static_cast<const BufferRingImpl*>(m_colorRampUniforms.impl());
-    }
-    const BufferRingImpl* tessellateUniforms()
-    {
-        return static_cast<const BufferRingImpl*>(m_tessellateUniforms.impl());
-    }
-    const BufferRingImpl* drawUniforms()
-    {
-        return static_cast<const BufferRingImpl*>(m_drawUniforms.impl());
-    }
     const TexelBufferRing* pathBufferRing()
     {
         return static_cast<const TexelBufferRing*>(m_pathBuffer.impl());
@@ -259,6 +247,10 @@
     }
     const BufferRingImpl* gradSpanBufferRing() const { return m_gradSpanBuffer.impl(); }
     const BufferRingImpl* tessSpanBufferRing() { return m_tessSpanBuffer.impl(); }
+    const BufferRingImpl* uniformBufferRing() const
+    {
+        return static_cast<const BufferRingImpl*>(m_uniformBuffer.impl());
+    }
 
     size_t gradTextureRowsForSimpleRamps() const { return m_gradTextureRowsForSimpleRamps; }
 
@@ -428,12 +420,9 @@
     GPUResourceLimits m_currentFrameResourceUsage = {};
     GPUResourceLimits m_maxRecentResourceUsage = {};
 
-    // Here we cache the contents of the uniform buffers that only have one item (and are therefore
-    // constant throughout an entire flush). We use these cached values to determine whether the
-    // buffers need to be updated at the beginning of a flush.
-    ColorRampUniforms m_cachedColorRampUniformData{};
-    TessellateUniforms m_cachedTessUniformData{};
-    DrawUniforms m_cachedDrawUniformData{0, 0, 0, m_platformFeatures};
+    // Here we cache the contents of the uniform buffer. We use this cached value to determine
+    // whether the buffer needs to be updated at the beginning of a flush.
+    FlushUniforms m_cachedUniformData{0, 0, 0, 0, 0, m_platformFeatures};
 
     // Simple gradients only have 2 texels, so we write them to mapped texture memory from the CPU
     // instead of rendering them.
@@ -452,9 +441,7 @@
     BufferRing<TwoTexelRamp> m_gradTexelBuffer; // Simple gradients get written by the CPU.
     BufferRing<GradientSpan> m_gradSpanBuffer;  // Complex gradients get rendered by the GPU.
     BufferRing<TessVertexSpan> m_tessSpanBuffer;
-    BufferRing<ColorRampUniforms> m_colorRampUniforms;
-    BufferRing<TessellateUniforms> m_tessellateUniforms;
-    BufferRing<DrawUniforms> m_drawUniforms;
+    BufferRing<FlushUniforms> m_uniformBuffer;
 
     // How many rows of the gradient texture are dedicated to simple (two-texel) ramps?
     // This is also the y-coordinate at which the complex color ramps begin.
diff --git a/renderer/gl/pls_render_context_gl.cpp b/renderer/gl/pls_render_context_gl.cpp
index a9308a3..d18f09b 100644
--- a/renderer/gl/pls_render_context_gl.cpp
+++ b/renderer/gl/pls_render_context_gl.cpp
@@ -12,8 +12,8 @@
 
 #include "../out/obj/generated/advanced_blend.glsl.hpp"
 #include "../out/obj/generated/color_ramp.glsl.hpp"
+#include "../out/obj/generated/common.glsl.hpp"
 #include "../out/obj/generated/draw.glsl.hpp"
-#include "../out/obj/generated/math.glsl.hpp"
 #include "../out/obj/generated/tessellate.glsl.hpp"
 
 // Offset all texture indices by 1 so we, and others who share our GL context, can use GL_TEXTURE0
@@ -54,13 +54,20 @@
     assert(!m_supportsBaseInstanceInShader || m_extensions.EXT_base_instance);
 
     m_colorRampProgram = glCreateProgram();
+    const char* colorRampSources[] = {glsl::common, glsl::color_ramp};
     glutils::CompileAndAttachShader(m_colorRampProgram,
                                     GL_VERTEX_SHADER,
-                                    glsl::color_ramp,
+                                    nullptr,
+                                    0,
+                                    colorRampSources,
+                                    2,
                                     m_shaderVersionString);
     glutils::CompileAndAttachShader(m_colorRampProgram,
                                     GL_FRAGMENT_SHADER,
-                                    glsl::color_ramp,
+                                    nullptr,
+                                    0,
+                                    colorRampSources,
+                                    2,
                                     m_shaderVersionString);
     glutils::LinkProgram(m_colorRampProgram);
     glUniformBlockBinding(m_colorRampProgram,
@@ -75,7 +82,7 @@
     glGenFramebuffers(1, &m_colorRampFBO);
 
     m_tessellateProgram = glCreateProgram();
-    const char* tessellateSources[] = {glsl::math, glsl::tessellate};
+    const char* tessellateSources[] = {glsl::common, glsl::tessellate};
     glutils::CompileAndAttachShader(m_tessellateProgram,
                                     GL_VERTEX_SHADER,
                                     nullptr,
@@ -247,7 +254,7 @@
         }
 
         std::vector<const char*> sources;
-        sources.push_back(glsl::math);
+        sources.push_back(glsl::common);
         if (sourceType != SourceType::vertexOnly)
         {
             if (shaderFeatures.programFeatures.blendTier > BlendTier::srcOver)
@@ -334,6 +341,9 @@
                                  size_t tessDataHeight,
                                  bool needsClipBuffer)
 {
+    // All programs use the same set of per-flush uniforms.
+    glBindBufferBase(GL_UNIFORM_BUFFER, 0, gl_buffer_id(uniformBufferRing()));
+
     // Render the complex color ramps to the gradient texture.
     if (gradSpanCount > 0)
     {
@@ -347,7 +357,6 @@
                                GL_TEXTURE_2D,
                                gl_texture_id(gradTexelBufferRing()),
                                0);
-        glBindBufferBase(GL_UNIFORM_BUFFER, 0, gl_buffer_id(colorRampUniforms()));
         glUseProgram(m_colorRampProgram);
         glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, gradSpanCount);
     }
@@ -374,7 +383,6 @@
         glViewport(0, 0, kTessTextureWidth, tessDataHeight);
         glBindFramebuffer(GL_FRAMEBUFFER, m_tessellateFBO);
         glUseProgram(m_tessellateProgram);
-        glBindBufferBase(GL_UNIFORM_BUFFER, 0, gl_buffer_id(tessellateUniforms()));
         glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, tessVertexSpanCount);
     }
 
@@ -409,7 +417,6 @@
 
     // Issue all the draws.
     glBindVertexArray(m_drawVAO);
-    glBindBufferBase(GL_UNIFORM_BUFFER, 0, gl_buffer_id(drawUniforms()));
     drawIdx = 0;
     for (DrawList* draw = m_drawList; draw; draw = draw->next, ++drawIdx)
     {
diff --git a/renderer/metal/pls_render_context_metal.mm b/renderer/metal/pls_render_context_metal.mm
index 19666bf..6277b8a 100644
--- a/renderer/metal/pls_render_context_metal.mm
+++ b/renderer/metal/pls_render_context_metal.mm
@@ -325,7 +325,7 @@
                                                0.0,
                                                1.0}];
         [gradEncoder setRenderPipelineState:m_colorRampPipeline->pipelineState()];
-        [gradEncoder setVertexBuffer:mtl_buffer(colorRampUniforms()) offset:0 atIndex:0];
+        [gradEncoder setVertexBuffer:mtl_buffer(uniformBufferRing()) offset:0 atIndex:0];
         [gradEncoder setVertexBuffer:mtl_buffer(gradSpanBufferRing()) offset:0 atIndex:1];
         [gradEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
                         vertexStart:0
@@ -353,7 +353,7 @@
                                                0.0,
                                                1.0}];
         [tessEncoder setRenderPipelineState:m_tessPipeline->pipelineState()];
-        [tessEncoder setVertexBuffer:mtl_buffer(tessellateUniforms()) offset:0 atIndex:0];
+        [tessEncoder setVertexBuffer:mtl_buffer(uniformBufferRing()) offset:0 atIndex:0];
         [tessEncoder setVertexBuffer:mtl_buffer(tessSpanBufferRing()) offset:0 atIndex:1];
         [tessEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
                         vertexStart:0
@@ -399,7 +399,7 @@
                                        static_cast<float>(renderTarget->height()),
                                        0.0,
                                        1.0}];
-    [encoder setVertexBuffer:mtl_buffer(drawUniforms()) offset:0 atIndex:0];
+    [encoder setVertexBuffer:mtl_buffer(uniformBufferRing()) offset:0 atIndex:0];
     [encoder setVertexBuffer:m_pathWedgeVertexBuffer offset:0 atIndex:1];
     [encoder setVertexTexture:m_tessVertexTexture atIndex:kTessVertexTextureIdx];
     [encoder setVertexTexture:mtl_texture(pathBufferRing()) atIndex:kPathTextureIdx];
diff --git a/renderer/pls_render_context.cpp b/renderer/pls_render_context.cpp
index 7c26b09..f85cce7 100644
--- a/renderer/pls_render_context.cpp
+++ b/renderer/pls_render_context.cpp
@@ -355,26 +355,12 @@
     }
     COUNT_RESOURCE_SIZE(targetTessTextureHeight * kTessTextureWidth * 4 * sizeof(uint32_t));
 
-    // One-time allocation of the gradient uniform buffer ring.
-    if (m_colorRampUniforms.impl() == nullptr)
+    // One-time allocation of the uniform buffer ring.
+    if (m_uniformBuffer.impl() == nullptr)
     {
-        m_colorRampUniforms.reset(makeUniformBufferRing(1, sizeof(ColorRampUniforms)));
+        m_uniformBuffer.reset(makeUniformBufferRing(1, sizeof(FlushUniforms)));
     }
-    COUNT_RESOURCE_SIZE(m_colorRampUniforms.totalSizeInBytes());
-
-    // One-time allocation of the tessellation uniform buffer ring.
-    if (m_tessellateUniforms.impl() == nullptr)
-    {
-        m_tessellateUniforms.reset(makeUniformBufferRing(1, sizeof(TessellateUniforms)));
-    }
-    COUNT_RESOURCE_SIZE(m_tessellateUniforms.totalSizeInBytes());
-
-    // One-time allocation of the draw uniform buffer ring.
-    if (m_drawUniforms.impl() == nullptr)
-    {
-        m_drawUniforms.reset(makeUniformBufferRing(1, sizeof(DrawUniforms)));
-    }
-    COUNT_RESOURCE_SIZE(m_drawUniforms.totalSizeInBytes());
+    COUNT_RESOURCE_SIZE(m_uniformBuffer.totalSizeInBytes());
 }
 
 void PLSRenderContext::beginFrame(FrameDescriptor&& frameDescriptor)
@@ -826,40 +812,19 @@
     m_gradSpanBuffer.submit();
     m_tessSpanBuffer.submit();
 
-    if (gradSpanCount)
-    {
-        // Update the uniform buffer for rendering complex color ramps if needed.
-        ColorRampUniforms uniformData = {static_cast<float>(m_complexGradients.size())};
-        if (!bits_equal(&m_cachedColorRampUniformData, &uniformData))
-        {
-            m_colorRampUniforms.ensureMapped();
-            m_colorRampUniforms.emplace_back(uniformData);
-            m_colorRampUniforms.submit();
-            m_cachedColorRampUniformData = uniformData;
-        }
-    }
-
-    // Update the uniform buffer for rendering tessellations if needed.
-    TessellateUniforms tessUniformData = {kTessTextureWidth, static_cast<float>(tessDataHeight)};
-    if (!bits_equal(&m_cachedTessUniformData, &tessUniformData))
-    {
-        m_tessellateUniforms.ensureMapped();
-        m_tessellateUniforms.emplace_back(tessUniformData);
-        m_tessellateUniforms.submit();
-        m_cachedTessUniformData = tessUniformData;
-    }
-
     // Update the uniform buffer for drawing if needed.
-    DrawUniforms drawUniformData(m_frameDescriptor.renderTarget->width(),
-                                 m_frameDescriptor.renderTarget->height(),
-                                 gradTexelBufferRing()->height(),
-                                 m_platformFeatures);
-    if (!bits_equal(&m_cachedDrawUniformData, &drawUniformData))
+    FlushUniforms uniformData(m_complexGradients.size(),
+                              tessDataHeight,
+                              m_frameDescriptor.renderTarget->width(),
+                              m_frameDescriptor.renderTarget->height(),
+                              gradTexelBufferRing()->height(),
+                              m_platformFeatures);
+    if (!bits_equal(&m_cachedUniformData, &uniformData))
     {
-        m_drawUniforms.ensureMapped();
-        m_drawUniforms.emplace_back(drawUniformData);
-        m_drawUniforms.submit();
-        m_cachedDrawUniformData = drawUniformData;
+        m_uniformBuffer.ensureMapped();
+        m_uniformBuffer.emplace_back(uniformData);
+        m_uniformBuffer.submit();
+        m_cachedUniformData = uniformData;
     }
 
     onFlush(flushType,
diff --git a/renderer/shaders/color_ramp.glsl b/renderer/shaders/color_ramp.glsl
index a32b6fa..4965a55 100644
--- a/renderer/shaders/color_ramp.glsl
+++ b/renderer/shaders/color_ramp.glsl
@@ -14,10 +14,6 @@
 ATTR(0) uint4 span; // [horizontalSpan, y, color0, color1]
 ATTR_BLOCK_END
 
-UNIFORM_BLOCK_BEGIN(@Uniforms)
-float viewportHeight;
-UNIFORM_BLOCK_END(uniforms)
-
 half4 unpackColorInt(uint color)
 {
     return make_half4((uint4(color) >> uint4(16, 8, 0, 24)) & 0xffu) / 255.;
@@ -41,7 +37,7 @@
         float((GLSL_VERTEX_ID & 1) == 0 ? horizontalSpan & 0xffffu : horizontalSpan >> 16) / 65536.,
         float(span.y) + ((GLSL_VERTEX_ID & 2) == 0 ? .0 : 1.));
     FLD(varyings, rampColor) = unpackColorInt((GLSL_VERTEX_ID & 1) == 0 ? span.z : span.w);
-    GLSL_POSITION.xy = coord * float2(2., 2. / uniforms.viewportHeight) - 1.;
+    GLSL_POSITION.xy = coord * float2(2, uniforms.gradInverseViewportY) - 1.;
     GLSL_POSITION.zw = float2(0, 1);
     EMIT_OFFSCREEN_VERTEX(varyings);
 }
diff --git a/renderer/shaders/common.glsl b/renderer/shaders/common.glsl
new file mode 100644
index 0000000..6d73ebf
--- /dev/null
+++ b/renderer/shaders/common.glsl
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2022 Rive
+ */
+
+// Common definitions shared by multiple shaders.
+
+#define TESS_TEXTURE_WIDTH 2048.
+#define TESS_TEXTURE_WIDTH_LOG2 11
+
+#define FIRST_VERTEX_OF_CONTOUR_FLAG (1u << 31)
+#define JOIN_TYPE_MASK (3u << 29)
+#define MITER_CLIP_JOIN (3u << 29)
+#define MITER_REVERT_JOIN (2u << 29)
+#define BEVEL_JOIN (1u << 29)
+#define EMULATED_STROKE_CAP_FLAG (1u << 28)
+#define JOIN_TANGENT_0_FLAG (1u << 27)
+#define JOIN_TANGENT_INNER_FLAG (1u << 26)
+#define LEFT_JOIN_FLAG (1u << 25)
+#define RIGHT_JOIN_FLAG (1u << 24)
+#define CONTOUR_ID_MASK 0xffffu
+
+#define PI 3.141592653589793238
+
+INLINE float2 unchecked_mix(float2 a, float2 b, float t) { return (b - a) * t + a; }
+
+INLINE float atan2(float2 v)
+{
+    float bias = .0;
+    if (abs(v.x) > abs(v.y))
+    {
+        v = float2(v.y, -v.x);
+        bias = PI / 2.;
+    }
+    return atan(v.y, v.x) + bias;
+}
+
+INLINE half4 unmultiply(half4 color)
+{
+    if (color.a != .0)
+        color.rgb *= 1.0 / color.a;
+    return color;
+}
+
+#ifdef @VERTEX
+
+UNIFORM_BLOCK_BEGIN(@Uniforms)
+float gradInverseViewportY;
+float tessInverseViewportY;
+float renderTargetInverseViewportX;
+float renderTargetInverseViewportY;
+float gradTextureInverseHeight;
+uint pathIDGranularity; // Spacing between adjacent path IDs (1 if IEEE compliant).
+float vertexDiscardValue;
+uint pad;
+UNIFORM_BLOCK_END(uniforms)
+
+#endif
diff --git a/renderer/shaders/draw.glsl b/renderer/shaders/draw.glsl
index b296ab0..a013a99 100644
--- a/renderer/shaders/draw.glsl
+++ b/renderer/shaders/draw.glsl
@@ -8,22 +8,8 @@
 #define FAN_VERTEX 1
 #define FAN_MIDPOINT_VERTEX 2
 
-#define FIRST_VERTEX_OF_CONTOUR_FLAG (1u << 31)
-#define JOIN_TYPE_MASK (3u << 29)
-#define MITER_CLIP_JOIN (3u << 29)
-#define MITER_REVERT_JOIN (2u << 29)
-#define BEVEL_JOIN (1u << 29)
-#define EMULATED_STROKE_CAP_FLAG (1u << 28)
-#define JOIN_TANGENT_0_FLAG (1u << 27)
-#define JOIN_TANGENT_INNER_FLAG (1u << 26)
-#define LEFT_JOIN_FLAG (1u << 25)
-#define RIGHT_JOIN_FLAG (1u << 24)
-#define CONTOUR_ID_MASK 0xffffu
-
 #define GRAD_TEXTURE_WIDTH 512.
 
-#define TESS_TEXTURE_WIDTH_LOG2 11
-
 #define EVEN_ODD_FLAG (1u << 31)
 #define SOLID_COLOR_PAINT_TYPE 0u
 #define LINEAR_GRADIENT_PAINT_TYPE 1u
@@ -52,16 +38,6 @@
 
 #ifdef @VERTEX
 
-UNIFORM_BLOCK_BEGIN(@Uniforms)
-float2 viewportSize;
-float gradTextureInverseHeight;
-uint pathIDGranularity;
-float vertexDiscardValue;
-uint pad0;
-uint pad1;
-uint pad2;
-UNIFORM_BLOCK_END(uniforms)
-
 // Only used by GL platforms that don't support EXT_base_instance.
 #ifdef @BASE_INSTANCE_POLYFILL
 uniform int @baseInstancePolyfill;
@@ -366,7 +342,9 @@
     }
     FLD(varyings, varying_paint) = paint;
 
-    GLSL_POSITION.xy = vertexPosition * (float2(2, -2) / uniforms.viewportSize) + float2(-1, 1);
+    GLSL_POSITION.xy = vertexPosition * float2(uniforms.renderTargetInverseViewportX,
+                                               -uniforms.renderTargetInverseViewportY) +
+                       float2(-1, 1);
     GLSL_POSITION.zw = float2(0, 1);
     EMIT_VERTEX(varyings);
 }
diff --git a/renderer/shaders/math.glsl b/renderer/shaders/math.glsl
deleted file mode 100644
index b4f8f62..0000000
--- a/renderer/shaders/math.glsl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2022 Rive
- */
-
-// Common math utilities.
-
-#define PI 3.141592653589793238
-
-INLINE float2 unchecked_mix(float2 a, float2 b, float t) { return (b - a) * t + a; }
-
-INLINE float atan2(float2 v)
-{
-    float bias = .0;
-    if (abs(v.x) > abs(v.y))
-    {
-        v = float2(v.y, -v.x);
-        bias = PI / 2.;
-    }
-    return atan(v.y, v.x) + bias;
-}
-
-INLINE half4 unmultiply(half4 color)
-{
-    if (color.a != .0)
-        color.rgb *= 1.0 / color.a;
-    return color;
-}
diff --git a/renderer/shaders/metal/color_ramp.metal b/renderer/shaders/metal/color_ramp.metal
index 5f00569..b5afc61 100644
--- a/renderer/shaders/metal/color_ramp.metal
+++ b/renderer/shaders/metal/color_ramp.metal
@@ -4,4 +4,5 @@
 #define FRAGMENT
 
 #include "../../../out/obj/generated/metal.minified.glsl"
+#include "../../../out/obj/generated/common.minified.glsl"
 #include "../../../out/obj/generated/color_ramp.minified.glsl"
diff --git a/renderer/shaders/metal/draw.metal b/renderer/shaders/metal/draw.metal
index aefce48..c12656f 100644
--- a/renderer/shaders/metal/draw.metal
+++ b/renderer/shaders/metal/draw.metal
@@ -1,7 +1,10 @@
+#define VERTEX
+#define FRAGMENT
+#
 #include <metal_stdlib>
 
 #include "../../../out/obj/generated/metal.minified.glsl"
-#include "../../../out/obj/generated/math.minified.glsl"
+#include "../../../out/obj/generated/common.minified.glsl"
 
 #define ENABLE_ADVANCED_BLEND
 #include "../../../out/obj/generated/advanced_blend.minified.glsl"
@@ -36,8 +39,6 @@
 //     1000
 
 // Vertex and fragment combinations.
-#define VERTEX
-#define FRAGMENT
 namespace r0000
 {
 #include "../../../out/obj/generated/draw.minified.glsl"
diff --git a/renderer/shaders/metal/tessellate.metal b/renderer/shaders/metal/tessellate.metal
index dcd32f4..07b0933 100644
--- a/renderer/shaders/metal/tessellate.metal
+++ b/renderer/shaders/metal/tessellate.metal
@@ -4,5 +4,5 @@
 #define FRAGMENT
 
 #include "../../../out/obj/generated/metal.minified.glsl"
-#include "../../../out/obj/generated/math.minified.glsl"
+#include "../../../out/obj/generated/common.minified.glsl"
 #include "../../../out/obj/generated/tessellate.minified.glsl"
diff --git a/renderer/shaders/tessellate.glsl b/renderer/shaders/tessellate.glsl
index 6bffebb..fb8b2e4 100644
--- a/renderer/shaders/tessellate.glsl
+++ b/renderer/shaders/tessellate.glsl
@@ -11,17 +11,6 @@
 
 #define MAX_PARAMETRIC_SEGMENTS_LOG2 10 // Max 1024 segments.
 
-#define FIRST_VERTEX_OF_CONTOUR_FLAG (1u << 31)
-#define JOIN_TYPE_MASK (3u << 29)
-#define MITER_CLIP_JOIN (3u << 29)
-#define MITER_REVERT_JOIN (2u << 29)
-#define BEVEL_JOIN (1u << 29)
-#define EMULATED_STROKE_CAP_FLAG (1u << 28)
-#define JOIN_TANGENT_0_FLAG (1u << 27)
-#define JOIN_TANGENT_INNER_FLAG (1u << 26)
-#define LEFT_JOIN_FLAG (1u << 25)
-#define RIGHT_JOIN_FLAG (1u << 24)
-
 #ifdef @VERTEX
 ATTR_BLOCK_BEGIN(Attrs)
 ATTR(0) float4 attr_p0p1;
@@ -50,10 +39,6 @@
 }
 
 #ifdef @VERTEX
-UNIFORM_BLOCK_BEGIN(@Uniforms)
-float2 viewportSize;
-UNIFORM_BLOCK_END(uniforms)
-
 float cosine_between_vectors(float2 a, float2 b)
 {
     // FIXME(crbug.com/800804,skbug.com/11268): This can overflow if we don't normalize exponents.
@@ -134,7 +119,7 @@
     }
     FLD(varyings, contourIDWithFlags) = outContourIDWithFlags;
 
-    GLSL_POSITION.xy = coord * (float2(2, 2) / uniforms.viewportSize) + float2(-1, -1);
+    GLSL_POSITION.xy = coord * float2(2. / TESS_TEXTURE_WIDTH, uniforms.tessInverseViewportY) - 1.;
     GLSL_POSITION.zw = float2(0, 1);
     EMIT_OFFSCREEN_VERTEX(varyings);
 }