[gtk+/wip/otte/shader: 132/156] gskspv: Generate code for the extended instructions



commit 928e1dae758e5c31bfb6fb0e9f349ee76a3c4e1d
Author: Benjamin Otte <otte redhat com>
Date:   Mon Oct 16 02:44:09 2017 +0200

    gskspv: Generate code for the extended instructions
    
    This way, we can use the same approach to emit code for built-in
    functions that we use for the rest of SPIRV emission.

 gsk/extinst.glsl.std.450.grammar.json  |  642 +++++++++++
 gsk/gskspvenumsglslprivate.h           |  114 ++
 gsk/gskspvwriter.c                     |   12 +-
 gsk/gskspvwritergeneratedglslprivate.h | 1820 ++++++++++++++++++++++++++++++++
 gsk/gskspvwritergeneratedprivate.h     |    3 +
 gsk/gskspvwriterprivate.h              |    4 +
 gsk/spirv.js                           |   54 +-
 7 files changed, 2635 insertions(+), 14 deletions(-)
---
diff --git a/gsk/extinst.glsl.std.450.grammar.json b/gsk/extinst.glsl.std.450.grammar.json
new file mode 100644
index 0000000..3d9f39e
--- /dev/null
+++ b/gsk/extinst.glsl.std.450.grammar.json
@@ -0,0 +1,642 @@
+{
+  "copyright" : [
+    "Copyright (c) 2014-2016 The Khronos Group Inc.",
+    "",
+    "Permission is hereby granted, free of charge, to any person obtaining a copy",
+    "of this software and/or associated documentation files (the \"Materials\"),",
+    "to deal in the Materials without restriction, including without limitation",
+    "the rights to use, copy, modify, merge, publish, distribute, sublicense,",
+    "and/or sell copies of the Materials, and to permit persons to whom the",
+    "Materials are furnished to do so, subject to the following conditions:",
+    "",
+    "The above copyright notice and this permission notice shall be included in",
+    "all copies or substantial portions of the Materials.",
+    "",
+    "MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS",
+    "STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND",
+    "HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ ",
+    "",
+    "THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS",
+    "OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
+    "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL",
+    "THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
+    "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING",
+    "FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS",
+    "IN THE MATERIALS."
+  ],
+  "version" : 100,
+  "revision" : 2,
+  "instructions" : [
+    {
+      "opname" : "Round",
+      "opcode" : 1,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "RoundEven",
+      "opcode" : 2,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Trunc",
+      "opcode" : 3,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "FAbs",
+      "opcode" : 4,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "SAbs",
+      "opcode" : 5,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "FSign",
+      "opcode" : 6,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "SSign",
+      "opcode" : 7,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Floor",
+      "opcode" : 8,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Ceil",
+      "opcode" : 9,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Fract",
+      "opcode" : 10,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Radians",
+      "opcode" : 11,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'degrees'" }
+      ]
+    },
+    {
+      "opname" : "Degrees",
+      "opcode" : 12,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'radians'" }
+      ]
+    },
+    {
+      "opname" : "Sin",
+      "opcode" : 13,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Cos",
+      "opcode" : 14,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Tan",
+      "opcode" : 15,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Asin",
+      "opcode" : 16,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Acos",
+      "opcode" : 17,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Atan",
+      "opcode" : 18,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'y_over_x'" }
+      ]
+    },
+    {
+      "opname" : "Sinh",
+      "opcode" : 19,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Cosh",
+      "opcode" : 20,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Tanh",
+      "opcode" : 21,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Asinh",
+      "opcode" : 22,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Acosh",
+      "opcode" : 23,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Atanh",
+      "opcode" : 24,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Atan2",
+      "opcode" : 25,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'y'" },
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Pow",
+      "opcode" : 26,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "Exp",
+      "opcode" : 27,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Log",
+      "opcode" : 28,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Exp2",
+      "opcode" : 29,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Log2",
+      "opcode" : 30,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Sqrt",
+      "opcode" : 31,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "InverseSqrt",
+      "opcode" : 32,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Determinant",
+      "opcode" : 33,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "MatrixInverse",
+      "opcode" : 34,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Modf",
+      "opcode" : 35,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'i'" }
+      ]
+    },
+    {
+      "opname" : "ModfStruct",
+      "opcode" : 36,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "FMin",
+      "opcode" : 37,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "UMin",
+      "opcode" : 38,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "SMin",
+      "opcode" : 39,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "FMax",
+      "opcode" : 40,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "UMax",
+      "opcode" : 41,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "SMax",
+      "opcode" : 42,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "FClamp",
+      "opcode" : 43,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'minVal'" },
+        { "kind" : "IdRef", "name" : "'maxVal'" }
+      ]
+    },
+    {
+      "opname" : "UClamp",
+      "opcode" : 44,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'minVal'" },
+        { "kind" : "IdRef", "name" : "'maxVal'" }
+      ]
+    },
+    {
+      "opname" : "SClamp",
+      "opcode" : 45,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'minVal'" },
+        { "kind" : "IdRef", "name" : "'maxVal'" }
+      ]
+    },
+    {
+      "opname" : "FMix",
+      "opcode" : 46,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" },
+        { "kind" : "IdRef", "name" : "'a'" }
+      ]
+    },
+    {
+      "opname" : "IMix",
+      "opcode" : 47,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" },
+        { "kind" : "IdRef", "name" : "'a'" }
+      ]
+    },
+    {
+      "opname" : "Step",
+      "opcode" : 48,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'edge'" },
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "SmoothStep",
+      "opcode" : 49,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'edge0'" },
+        { "kind" : "IdRef", "name" : "'edge1'" },
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Fma",
+      "opcode" : 50,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'a'" },
+        { "kind" : "IdRef", "name" : "'b'" },
+        { "kind" : "IdRef", "name" : "'c'" }
+      ]
+    },
+    {
+      "opname" : "Frexp",
+      "opcode" : 51,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'exp'" }
+      ]
+    },
+    {
+      "opname" : "FrexpStruct",
+      "opcode" : 52,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Ldexp",
+      "opcode" : 53,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'exp'" }
+      ]
+    },
+    {
+      "opname" : "PackSnorm4x8",
+      "opcode" : 54,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'v'" }
+      ]
+    },
+    {
+      "opname" : "PackUnorm4x8",
+      "opcode" : 55,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'v'" }
+      ]
+    },
+    {
+      "opname" : "PackSnorm2x16",
+      "opcode" : 56,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'v'" }
+      ]
+    },
+    {
+      "opname" : "PackUnorm2x16",
+      "opcode" : 57,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'v'" }
+      ]
+    },
+    {
+      "opname" : "PackHalf2x16",
+      "opcode" : 58,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'v'" }
+      ]
+    },
+    {
+      "opname" : "PackDouble2x32",
+      "opcode" : 59,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'v'" }
+      ],
+      "capabilities" : [ "Float64" ]
+    },
+    {
+      "opname" : "UnpackSnorm2x16",
+      "opcode" : 60,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'p'" }
+      ]
+    },
+    {
+      "opname" : "UnpackUnorm2x16",
+      "opcode" : 61,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'p'" }
+      ]
+    },
+    {
+      "opname" : "UnpackHalf2x16",
+      "opcode" : 62,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'v'" }
+      ]
+    },
+    {
+      "opname" : "UnpackSnorm4x8",
+      "opcode" : 63,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'p'" }
+      ]
+    },
+    {
+      "opname" : "UnpackUnorm4x8",
+      "opcode" : 64,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'p'" }
+      ]
+    },
+    {
+      "opname" : "UnpackDouble2x32",
+      "opcode" : 65,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'v'" }
+      ],
+      "capabilities" : [ "Float64" ]
+    },
+    {
+      "opname" : "Length",
+      "opcode" : 66,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "Distance",
+      "opcode" : 67,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'p0'" },
+        { "kind" : "IdRef", "name" : "'p1'" }
+      ]
+    },
+    {
+      "opname" : "Cross",
+      "opcode" : 68,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "Normalize",
+      "opcode" : 69,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" }
+      ]
+    },
+    {
+      "opname" : "FaceForward",
+      "opcode" : 70,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'N'" },
+        { "kind" : "IdRef", "name" : "'I'" },
+        { "kind" : "IdRef", "name" : "'Nref'" }
+      ]
+    },
+    {
+      "opname" : "Reflect",
+      "opcode" : 71,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'I'" },
+        { "kind" : "IdRef", "name" : "'N'" }
+      ]
+    },
+    {
+      "opname" : "Refract",
+      "opcode" : 72,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'I'" },
+        { "kind" : "IdRef", "name" : "'N'" },
+        { "kind" : "IdRef", "name" : "'eta'" }
+      ]
+    },
+    {
+      "opname" : "FindILsb",
+      "opcode" : 73,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Value'" }
+      ]
+    },
+    {
+      "opname" : "FindSMsb",
+      "opcode" : 74,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Value'" }
+      ]
+    },
+    {
+      "opname" : "FindUMsb",
+      "opcode" : 75,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'Value'" }
+      ]
+    },
+    {
+      "opname" : "InterpolateAtCentroid",
+      "opcode" : 76,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'interpolant'" }
+      ],
+      "capabilities" : [ "InterpolationFunction" ]
+    },
+    {
+      "opname" : "InterpolateAtSample",
+      "opcode" : 77,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'interpolant'" },
+        { "kind" : "IdRef", "name" : "'sample'" }
+      ],
+      "capabilities" : [ "InterpolationFunction" ]
+    },
+    {
+      "opname" : "InterpolateAtOffset",
+      "opcode" : 78,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'interpolant'" },
+        { "kind" : "IdRef", "name" : "'offset'" }
+      ],
+      "capabilities" : [ "InterpolationFunction" ]
+    },
+    {
+      "opname" : "NMin",
+      "opcode" : 79,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "NMax",
+      "opcode" : 80,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'y'" }
+      ]
+    },
+    {
+      "opname" : "NClamp",
+      "opcode" : 81,
+      "operands" : [
+        { "kind" : "IdRef", "name" : "'x'" },
+        { "kind" : "IdRef", "name" : "'minVal'" },
+        { "kind" : "IdRef", "name" : "'maxVal'" }
+      ]
+    }
+  ]
+}
diff --git a/gsk/gskspvenumsglslprivate.h b/gsk/gskspvenumsglslprivate.h
new file mode 100644
index 0000000..ef7df14
--- /dev/null
+++ b/gsk/gskspvenumsglslprivate.h
@@ -0,0 +1,114 @@
+/* GTK - The GIMP Toolkit
+ *   
+ * Copyright © 2017 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * !!! THIS FILE WAS AUTOGENERATED !!!
+ * 
+ * This file was created using the command
+ *   gjs spirv.js Glsl-enums extinst.glsl.std.450.grammar.json
+ * Apply any changes to those files and then regenerate using above command.
+ */
+
+#ifndef __GSK_SPV_GLSL_ENUMS_H__
+#define __GSK_SPV_GLSL_ENUMS_H__
+
+typedef enum {
+  GSK_SPV_OP_GLSL_ROUND = 1,
+  GSK_SPV_OP_GLSL_ROUND_EVEN = 2,
+  GSK_SPV_OP_GLSL_TRUNC = 3,
+  GSK_SPV_OP_GLSL_F_ABS = 4,
+  GSK_SPV_OP_GLSL_S_ABS = 5,
+  GSK_SPV_OP_GLSL_F_SIGN = 6,
+  GSK_SPV_OP_GLSL_S_SIGN = 7,
+  GSK_SPV_OP_GLSL_FLOOR = 8,
+  GSK_SPV_OP_GLSL_CEIL = 9,
+  GSK_SPV_OP_GLSL_FRACT = 10,
+  GSK_SPV_OP_GLSL_RADIANS = 11,
+  GSK_SPV_OP_GLSL_DEGREES = 12,
+  GSK_SPV_OP_GLSL_SIN = 13,
+  GSK_SPV_OP_GLSL_COS = 14,
+  GSK_SPV_OP_GLSL_TAN = 15,
+  GSK_SPV_OP_GLSL_ASIN = 16,
+  GSK_SPV_OP_GLSL_ACOS = 17,
+  GSK_SPV_OP_GLSL_ATAN = 18,
+  GSK_SPV_OP_GLSL_SINH = 19,
+  GSK_SPV_OP_GLSL_COSH = 20,
+  GSK_SPV_OP_GLSL_TANH = 21,
+  GSK_SPV_OP_GLSL_ASINH = 22,
+  GSK_SPV_OP_GLSL_ACOSH = 23,
+  GSK_SPV_OP_GLSL_ATANH = 24,
+  GSK_SPV_OP_GLSL_ATAN2 = 25,
+  GSK_SPV_OP_GLSL_POW = 26,
+  GSK_SPV_OP_GLSL_EXP = 27,
+  GSK_SPV_OP_GLSL_LOG = 28,
+  GSK_SPV_OP_GLSL_EXP2 = 29,
+  GSK_SPV_OP_GLSL_LOG2 = 30,
+  GSK_SPV_OP_GLSL_SQRT = 31,
+  GSK_SPV_OP_GLSL_INVERSE_SQRT = 32,
+  GSK_SPV_OP_GLSL_DETERMINANT = 33,
+  GSK_SPV_OP_GLSL_MATRIX_INVERSE = 34,
+  GSK_SPV_OP_GLSL_MODF = 35,
+  GSK_SPV_OP_GLSL_MODF_STRUCT = 36,
+  GSK_SPV_OP_GLSL_F_MIN = 37,
+  GSK_SPV_OP_GLSL_U_MIN = 38,
+  GSK_SPV_OP_GLSL_S_MIN = 39,
+  GSK_SPV_OP_GLSL_F_MAX = 40,
+  GSK_SPV_OP_GLSL_U_MAX = 41,
+  GSK_SPV_OP_GLSL_S_MAX = 42,
+  GSK_SPV_OP_GLSL_F_CLAMP = 43,
+  GSK_SPV_OP_GLSL_U_CLAMP = 44,
+  GSK_SPV_OP_GLSL_S_CLAMP = 45,
+  GSK_SPV_OP_GLSL_F_MIX = 46,
+  GSK_SPV_OP_GLSL_I_MIX = 47,
+  GSK_SPV_OP_GLSL_STEP = 48,
+  GSK_SPV_OP_GLSL_SMOOTH_STEP = 49,
+  GSK_SPV_OP_GLSL_FMA = 50,
+  GSK_SPV_OP_GLSL_FREXP = 51,
+  GSK_SPV_OP_GLSL_FREXP_STRUCT = 52,
+  GSK_SPV_OP_GLSL_LDEXP = 53,
+  GSK_SPV_OP_GLSL_PACK_SNORM4X8 = 54,
+  GSK_SPV_OP_GLSL_PACK_UNORM4X8 = 55,
+  GSK_SPV_OP_GLSL_PACK_SNORM2X16 = 56,
+  GSK_SPV_OP_GLSL_PACK_UNORM2X16 = 57,
+  GSK_SPV_OP_GLSL_PACK_HALF2X16 = 58,
+  GSK_SPV_OP_GLSL_PACK_DOUBLE2X32 = 59,
+  GSK_SPV_OP_GLSL_UNPACK_SNORM2X16 = 60,
+  GSK_SPV_OP_GLSL_UNPACK_UNORM2X16 = 61,
+  GSK_SPV_OP_GLSL_UNPACK_HALF2X16 = 62,
+  GSK_SPV_OP_GLSL_UNPACK_SNORM4X8 = 63,
+  GSK_SPV_OP_GLSL_UNPACK_UNORM4X8 = 64,
+  GSK_SPV_OP_GLSL_UNPACK_DOUBLE2X32 = 65,
+  GSK_SPV_OP_GLSL_LENGTH = 66,
+  GSK_SPV_OP_GLSL_DISTANCE = 67,
+  GSK_SPV_OP_GLSL_CROSS = 68,
+  GSK_SPV_OP_GLSL_NORMALIZE = 69,
+  GSK_SPV_OP_GLSL_FACE_FORWARD = 70,
+  GSK_SPV_OP_GLSL_REFLECT = 71,
+  GSK_SPV_OP_GLSL_REFRACT = 72,
+  GSK_SPV_OP_GLSL_FIND_I_LSB = 73,
+  GSK_SPV_OP_GLSL_FIND_S_MSB = 74,
+  GSK_SPV_OP_GLSL_FIND_U_MSB = 75,
+  GSK_SPV_OP_GLSL_INTERPOLATE_AT_CENTROID = 76,
+  GSK_SPV_OP_GLSL_INTERPOLATE_AT_SAMPLE = 77,
+  GSK_SPV_OP_GLSL_INTERPOLATE_AT_OFFSET = 78,
+  GSK_SPV_OP_GLSL_N_MIN = 79,
+  GSK_SPV_OP_GLSL_N_MAX = 80,
+  GSK_SPV_OP_GLSL_N_CLAMP = 81
+} GskSpvOpcodeGlsl;
+
+#endif /* __GSK_SPV_GLSL_ENUMS_H__ */
diff --git a/gsk/gskspvwriter.c b/gsk/gskspvwriter.c
index 1692a53..3bfb3de 100644
--- a/gsk/gskspvwriter.c
+++ b/gsk/gskspvwriter.c
@@ -47,6 +47,7 @@ struct _GskSpvWriter
   int ref_count;
 
   guint32 last_id;
+  guint extended_instructions_id;
   GArray *code[GSK_SPV_WRITER_N_GLOBAL_SECTIONS];
   GSList *blocks;
   GSList *pending_blocks;
@@ -275,8 +276,8 @@ gsk_spv_writer_do_write (GskSpvWriter     *writer,
   guint32 entry_point_id;
 
   gsk_spv_writer_capability (writer, GSK_SPV_CAPABILITY_SHADER);
-  gsk_spv_writer_ext_inst_import (writer,
-                                  "GLSL.std.450");
+  writer->extended_instructions_id = gsk_spv_writer_ext_inst_import (writer,
+                                                                     "GLSL.std.450");
   gsk_spv_writer_source (writer,
                          GSK_SPV_SOURCE_LANGUAGE_GLSL,
                          440,
@@ -312,6 +313,7 @@ gsk_spv_writer_clear (GskSpvWriter *writer)
 
   g_slist_free_full (writer->pending_blocks, (GDestroyNotify) gsk_spv_code_block_free);
   writer->pending_blocks = NULL;
+  writer->extended_instructions_id = 0;
 
   for (i = 0; i < GSK_SPV_WRITER_N_GLOBAL_SECTIONS; i++)
     {
@@ -369,6 +371,12 @@ gsk_spv_writer_write (GskSpvWriter     *writer,
 }
 
 guint32
+gsk_spv_writer_get_id_for_extended_instructions (GskSpvWriter *writer)
+{
+  return writer->extended_instructions_id;
+}
+
+guint32
 gsk_spv_writer_get_id_for_type (GskSpvWriter *writer,
                                 GskSlType    *type)
 {
diff --git a/gsk/gskspvwritergeneratedglslprivate.h b/gsk/gskspvwritergeneratedglslprivate.h
new file mode 100644
index 0000000..6e989ab
--- /dev/null
+++ b/gsk/gskspvwritergeneratedglslprivate.h
@@ -0,0 +1,1820 @@
+/* GTK - The GIMP Toolkit
+ *   
+ * Copyright © 2017 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * !!! THIS FILE WAS AUTOGENERATED !!!
+ * 
+ * This file was created using the command
+ *   gjs spirv.js Glsl-functions extinst.glsl.std.450.grammar.json
+ * Apply any changes to those files and then regenerate using above command.
+ */
+
+#include <string.h>
+
+#ifndef __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__
+#define __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__
+static inline void
+append_string (GArray     *bytes,
+               const char *str)
+{
+  gsize len = strlen (str);
+  guint size = bytes->len;
+  g_array_set_size (bytes, size + len / 4 + 1);
+  memcpy (&g_array_index (bytes, guint32, size), str, len);
+}
+#endif /* __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__ */
+
+static inline guint32
+gsk_spv_writer_round (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ROUND });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_round_even (GskSpvWriter *writer,
+                           GskSlType *result_type,
+                           guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ROUND_EVEN });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_trunc (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_TRUNC });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_f_abs (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_F_ABS });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_s_abs (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_S_ABS });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_f_sign (GskSpvWriter *writer,
+                       GskSlType *result_type,
+                       guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_F_SIGN });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_s_sign (GskSpvWriter *writer,
+                       GskSlType *result_type,
+                       guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_S_SIGN });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_floor (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FLOOR });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_ceil (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_CEIL });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_fract (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FRACT });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_radians (GskSpvWriter *writer,
+                        GskSlType *result_type,
+                        guint32 degrees)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_RADIANS });
+  g_array_append_val (bytes, degrees);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_degrees (GskSpvWriter *writer,
+                        GskSlType *result_type,
+                        guint32 radians)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_DEGREES });
+  g_array_append_val (bytes, radians);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_sin (GskSpvWriter *writer,
+                    GskSlType *result_type,
+                    guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_SIN });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_cos (GskSpvWriter *writer,
+                    GskSlType *result_type,
+                    guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_COS });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_tan (GskSpvWriter *writer,
+                    GskSlType *result_type,
+                    guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_TAN });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_asin (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ASIN });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_acos (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ACOS });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_atan (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 y_over_x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ATAN });
+  g_array_append_val (bytes, y_over_x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_sinh (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_SINH });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_cosh (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_COSH });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_tanh (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_TANH });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_asinh (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ASINH });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_acosh (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ACOSH });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_atanh (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ATANH });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_atan2 (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 y,
+                      guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_ATAN2 });
+  g_array_append_val (bytes, y);
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_pow (GskSpvWriter *writer,
+                    GskSlType *result_type,
+                    guint32 x,
+                    guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_POW });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_exp (GskSpvWriter *writer,
+                    GskSlType *result_type,
+                    guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_EXP });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_log (GskSpvWriter *writer,
+                    GskSlType *result_type,
+                    guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_LOG });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_exp2 (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_EXP2 });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_log2 (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_LOG2 });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_sqrt (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_SQRT });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_inverse_sqrt (GskSpvWriter *writer,
+                             GskSlType *result_type,
+                             guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_INVERSE_SQRT });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_determinant (GskSpvWriter *writer,
+                            GskSlType *result_type,
+                            guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_DETERMINANT });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_matrix_inverse (GskSpvWriter *writer,
+                               GskSlType *result_type,
+                               guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_MATRIX_INVERSE });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_modf (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 x,
+                     guint32 i)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_MODF });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, i);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_modf_struct (GskSpvWriter *writer,
+                            GskSlType *result_type,
+                            guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_MODF_STRUCT });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_f_min (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_F_MIN });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_u_min (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_U_MIN });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_s_min (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_S_MIN });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_f_max (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_F_MAX });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_u_max (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_U_MAX });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_s_max (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_S_MAX });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_f_clamp (GskSpvWriter *writer,
+                        GskSlType *result_type,
+                        guint32 x,
+                        guint32 min_val,
+                        guint32 max_val)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_F_CLAMP });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, min_val);
+  g_array_append_val (bytes, max_val);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_u_clamp (GskSpvWriter *writer,
+                        GskSlType *result_type,
+                        guint32 x,
+                        guint32 min_val,
+                        guint32 max_val)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_U_CLAMP });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, min_val);
+  g_array_append_val (bytes, max_val);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_s_clamp (GskSpvWriter *writer,
+                        GskSlType *result_type,
+                        guint32 x,
+                        guint32 min_val,
+                        guint32 max_val)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_S_CLAMP });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, min_val);
+  g_array_append_val (bytes, max_val);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_f_mix (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y,
+                      guint32 a)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_F_MIX });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_append_val (bytes, a);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_i_mix (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y,
+                      guint32 a)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_I_MIX });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_append_val (bytes, a);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_step (GskSpvWriter *writer,
+                     GskSlType *result_type,
+                     guint32 edge,
+                     guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_STEP });
+  g_array_append_val (bytes, edge);
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_smooth_step (GskSpvWriter *writer,
+                            GskSlType *result_type,
+                            guint32 edge0,
+                            guint32 edge1,
+                            guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_SMOOTH_STEP });
+  g_array_append_val (bytes, edge0);
+  g_array_append_val (bytes, edge1);
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_fma (GskSpvWriter *writer,
+                    GskSlType *result_type,
+                    guint32 a,
+                    guint32 b,
+                    guint32 c)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FMA });
+  g_array_append_val (bytes, a);
+  g_array_append_val (bytes, b);
+  g_array_append_val (bytes, c);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_frexp (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 exp)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FREXP });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, exp);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_frexp_struct (GskSpvWriter *writer,
+                             GskSlType *result_type,
+                             guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FREXP_STRUCT });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_ldexp (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 exp)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_LDEXP });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, exp);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_pack_snorm4x8 (GskSpvWriter *writer,
+                              GskSlType *result_type,
+                              guint32 v)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_PACK_SNORM4X8 });
+  g_array_append_val (bytes, v);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_pack_unorm4x8 (GskSpvWriter *writer,
+                              GskSlType *result_type,
+                              guint32 v)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_PACK_UNORM4X8 });
+  g_array_append_val (bytes, v);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_pack_snorm2x16 (GskSpvWriter *writer,
+                               GskSlType *result_type,
+                               guint32 v)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_PACK_SNORM2X16 });
+  g_array_append_val (bytes, v);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_pack_unorm2x16 (GskSpvWriter *writer,
+                               GskSlType *result_type,
+                               guint32 v)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_PACK_UNORM2X16 });
+  g_array_append_val (bytes, v);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_pack_half2x16 (GskSpvWriter *writer,
+                              GskSlType *result_type,
+                              guint32 v)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_PACK_HALF2X16 });
+  g_array_append_val (bytes, v);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_pack_double2x32 (GskSpvWriter *writer,
+                                GskSlType *result_type,
+                                guint32 v)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_PACK_DOUBLE2X32 });
+  g_array_append_val (bytes, v);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_unpack_snorm2x16 (GskSpvWriter *writer,
+                                 GskSlType *result_type,
+                                 guint32 p)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_UNPACK_SNORM2X16 });
+  g_array_append_val (bytes, p);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_unpack_unorm2x16 (GskSpvWriter *writer,
+                                 GskSlType *result_type,
+                                 guint32 p)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_UNPACK_UNORM2X16 });
+  g_array_append_val (bytes, p);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_unpack_half2x16 (GskSpvWriter *writer,
+                                GskSlType *result_type,
+                                guint32 v)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_UNPACK_HALF2X16 });
+  g_array_append_val (bytes, v);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_unpack_snorm4x8 (GskSpvWriter *writer,
+                                GskSlType *result_type,
+                                guint32 p)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_UNPACK_SNORM4X8 });
+  g_array_append_val (bytes, p);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_unpack_unorm4x8 (GskSpvWriter *writer,
+                                GskSlType *result_type,
+                                guint32 p)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_UNPACK_UNORM4X8 });
+  g_array_append_val (bytes, p);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_unpack_double2x32 (GskSpvWriter *writer,
+                                  GskSlType *result_type,
+                                  guint32 v)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_UNPACK_DOUBLE2X32 });
+  g_array_append_val (bytes, v);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_length (GskSpvWriter *writer,
+                       GskSlType *result_type,
+                       guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_LENGTH });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_distance (GskSpvWriter *writer,
+                         GskSlType *result_type,
+                         guint32 p0,
+                         guint32 p1)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_DISTANCE });
+  g_array_append_val (bytes, p0);
+  g_array_append_val (bytes, p1);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_cross (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_CROSS });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_normalize (GskSpvWriter *writer,
+                          GskSlType *result_type,
+                          guint32 x)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_NORMALIZE });
+  g_array_append_val (bytes, x);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_face_forward (GskSpvWriter *writer,
+                             GskSlType *result_type,
+                             guint32 n,
+                             guint32 i,
+                             guint32 nref)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FACE_FORWARD });
+  g_array_append_val (bytes, n);
+  g_array_append_val (bytes, i);
+  g_array_append_val (bytes, nref);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_reflect (GskSpvWriter *writer,
+                        GskSlType *result_type,
+                        guint32 i,
+                        guint32 n)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_REFLECT });
+  g_array_append_val (bytes, i);
+  g_array_append_val (bytes, n);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_refract (GskSpvWriter *writer,
+                        GskSlType *result_type,
+                        guint32 i,
+                        guint32 n,
+                        guint32 eta)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_REFRACT });
+  g_array_append_val (bytes, i);
+  g_array_append_val (bytes, n);
+  g_array_append_val (bytes, eta);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_find_i_lsb (GskSpvWriter *writer,
+                           GskSlType *result_type,
+                           guint32 value)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FIND_I_LSB });
+  g_array_append_val (bytes, value);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_find_s_msb (GskSpvWriter *writer,
+                           GskSlType *result_type,
+                           guint32 value)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FIND_S_MSB });
+  g_array_append_val (bytes, value);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_find_u_msb (GskSpvWriter *writer,
+                           GskSlType *result_type,
+                           guint32 value)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_FIND_U_MSB });
+  g_array_append_val (bytes, value);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_interpolate_at_centroid (GskSpvWriter *writer,
+                                        GskSlType *result_type,
+                                        guint32 interpolant)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_INTERPOLATE_AT_CENTROID });
+  g_array_append_val (bytes, interpolant);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_interpolate_at_sample (GskSpvWriter *writer,
+                                      GskSlType *result_type,
+                                      guint32 interpolant,
+                                      guint32 sample)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_INTERPOLATE_AT_SAMPLE });
+  g_array_append_val (bytes, interpolant);
+  g_array_append_val (bytes, sample);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_interpolate_at_offset (GskSpvWriter *writer,
+                                      GskSlType *result_type,
+                                      guint32 interpolant,
+                                      guint32 offset)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_INTERPOLATE_AT_OFFSET });
+  g_array_append_val (bytes, interpolant);
+  g_array_append_val (bytes, offset);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_n_min (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_N_MIN });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_n_max (GskSpvWriter *writer,
+                      GskSlType *result_type,
+                      guint32 x,
+                      guint32 y)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_N_MAX });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, y);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
+static inline guint32
+gsk_spv_writer_n_clamp (GskSpvWriter *writer,
+                        GskSlType *result_type,
+                        guint32 x,
+                        guint32 min_val,
+                        guint32 max_val)
+{
+  GArray *bytes = gsk_spv_writer_get_bytes (writer, GSK_SPV_WRITER_SECTION_CODE);
+  guint32 result_type_id = gsk_spv_writer_get_id_for_type (writer, result_type);
+  guint32 result_id = gsk_spv_writer_make_id (writer);
+  guint start_index = bytes->len;
+
+  g_array_append_val (bytes, (guint32) { 0 });
+  g_array_append_val (bytes, result_type_id);
+  g_array_append_val (bytes, result_id);
+  g_array_append_val (bytes, (guint32) { gsk_spv_writer_get_id_for_extended_instructions (writer) });
+  g_array_append_val (bytes, (guint32) { GSK_SPV_OP_GLSL_N_CLAMP });
+  g_array_append_val (bytes, x);
+  g_array_append_val (bytes, min_val);
+  g_array_append_val (bytes, max_val);
+  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | GSK_SPV_OP_EXT_INST;
+
+  return result_id;
+}
+
diff --git a/gsk/gskspvwritergeneratedprivate.h b/gsk/gskspvwritergeneratedprivate.h
index b9746b1..5985b01 100644
--- a/gsk/gskspvwritergeneratedprivate.h
+++ b/gsk/gskspvwritergeneratedprivate.h
@@ -26,6 +26,8 @@
 
 #include <string.h>
 
+#ifndef __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__
+#define __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__
 static inline void
 append_string (GArray     *bytes,
                const char *str)
@@ -35,6 +37,7 @@ append_string (GArray     *bytes,
   g_array_set_size (bytes, size + len / 4 + 1);
   memcpy (&g_array_index (bytes, guint32, size), str, len);
 }
+#endif /* __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__ */
 
 static inline void
 gsk_spv_writer_nop (GskSpvWriter *writer,
diff --git a/gsk/gskspvwriterprivate.h b/gsk/gskspvwriterprivate.h
index 58b276d..e7b541b 100644
--- a/gsk/gskspvwriterprivate.h
+++ b/gsk/gskspvwriterprivate.h
@@ -23,6 +23,7 @@
 
 #include "gsksltypesprivate.h"
 #include "gskspvenumsprivate.h"
+#include "gskspvenumsglslprivate.h"
 
 G_BEGIN_DECLS
 
@@ -58,6 +59,8 @@ GBytes *                gsk_spv_writer_write                    (GskSpvWriter
                                                                  GskSpvWriterFunc        initializer,
                                                                  gpointer                initializer_data);
 
+guint32                 gsk_spv_writer_get_id_for_extended_instructions
+                                                                (GskSpvWriter           *writer);
 guint32                 gsk_spv_writer_get_id_for_type          (GskSpvWriter           *writer,
                                                                  GskSlType              *type);
 guint32                 gsk_spv_writer_get_id_for_pointer_type  (GskSpvWriter           *writer,
@@ -107,6 +110,7 @@ void                    gsk_spv_access_chain_store              (GskSpvAccessCha
                                                                  guint32                 value);
 
 #include "gskspvwritergeneratedprivate.h"
+#include "gskspvwritergeneratedglslprivate.h"
 
 G_END_DECLS
 
diff --git a/gsk/spirv.js b/gsk/spirv.js
index 3ffb85d..c67451a 100644
--- a/gsk/spirv.js
+++ b/gsk/spirv.js
@@ -9,6 +9,14 @@ if (ARGV.length != 2)
     throw new SyntaxError ("Script needs 2 arguments but got " + ARGV.length);
   }
 
+var command = ARGV[0];
+var extinst = "";
+if (ARGV[0].indexOf("-") > 0)
+  {
+    extinst = ARGV[0].substr (0, ARGV[0].indexOf("-"));
+    command = ARGV[0].substr (extinst.length + 1);
+  }
+
 var contents = imports.gi.Gio.File.new_for_path(ARGV[1]).load_contents(null);
 var spirv = JSON.parse(contents[1]);
 
@@ -536,21 +544,35 @@ for (let i in spirv.instructions)
   {
     let ins = spirv.instructions[i];
     ins.result = false;
-    ins.enum_value = "GSK_SPV_OP_" + all_upper (ins.opname.substr(2));
+    ins.enum_value = "GSK_SPV_OP_" + (extinst ? all_upper(extinst) + "_" + all_upper (ins.opname) : 
all_upper (ins.opname.substr(2)));
     if (!ins.operands)
       ins.operands = [];
     if (ExtraOperands[ins.opname])
       ins.operands = ins.operands.concat (ExtraOperands[ins.opname]);
+    if (extinst)
+      {
+        ins.operands.unshift (
+          { "kind" : "IdResultType" },
+          { "kind" : "IdResult" }
+        );
+      }
     for (let o in ins.operands)
       {
         o = ins.operands[o];
         fix_operand (ins, o);
       }
-    if (Sections[ins.opname])
+    if (extinst)
+      {
+        ins.section = "code";
+        ins.section_enum = "GSK_SPV_WRITER_SECTION_CODE";
+      }
+    else if (Sections[ins.opname])
       {
         ins.section = Sections[ins.opname];
         ins.section_enum = "GSK_SPV_WRITER_SECTION_" + ins.section.toUpperCase();
       }
+    if (!extinst)
+      ins.opname = ins.opname.substr(2);
   }
 
 function header()
@@ -583,11 +605,11 @@ function header()
   print ();
 }
 
-if (ARGV[0] == "enums")
+if (command == "enums")
   {
     header ();
-    print ("#ifndef __GSK_SPV_ENUMS_H__");
-    print ("#define __GSK_SPV_ENUMS_H__");
+    print ("#ifndef __GSK_SPV_" + (extinst ? all_upper (extinst) + "_" : "") + "ENUMS_H__");
+    print ("#define __GSK_SPV_" + (extinst ? all_upper (extinst) + "_" : "") + "ENUMS_H__");
     print ();
 
     for (let kind in spirv.operand_kinds)
@@ -614,15 +636,17 @@ if (ARGV[0] == "enums")
         let ins = spirv.instructions[i];
         print ("  " + ins.enum_value + " = " + ins.opcode + (i + 1 < spirv.instructions.length ? "," : ""));
       }
-    print ("} GskSpvOpcode;");
+    print ("} GskSpvOpcode" + extinst + ";");
     print ();
-    print ("#endif /* __GSK_SPV_ENUMS_H__ */");
+    print ("#endif /* __GSK_SPV_" + (extinst ? all_upper (extinst) + "_" : "") + "ENUMS_H__ */");
   }
-else if (ARGV[0] == "functions")
+else if (command == "functions")
   {
     header ();
     print ("#include <string.h>");
     print ();
+    print ("#ifndef __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__");
+    print ("#define __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__");
     print ("static inline void");
     print ("append_string (GArray     *bytes,");
     print ("               const char *str)");
@@ -632,11 +656,12 @@ else if (ARGV[0] == "functions")
     print ("  g_array_set_size (bytes, size + len / 4 + 1);");
     print ("  memcpy (&g_array_index (bytes, guint32, size), str, len);");
     print ("}");
+    print ("#endif /* __GSK_SPV_SEEN_AUTOGENERATED_FUNCTIONS__ */");
     print ();
     for (let i in spirv.instructions)
       {
         let ins = spirv.instructions[i];
-        let prefix = "gsk_spv_writer_" + all_lower(ins.opname.substr(2)) + " (";
+        let prefix = "gsk_spv_writer_" + all_lower(ins.opname) + " (";
         let len = prefix.length;
         if (ins.result)
           print ("static inline guint32");
@@ -671,10 +696,10 @@ else if (ARGV[0] == "functions")
         else
           {
             if (ins.section)
-              print ("gsk_spv_writer_" + all_lower(ins.opname.substr(2)) + " (GskSpvWriter *writer)");
+              print ("gsk_spv_writer_" + all_lower(ins.opname) + " (GskSpvWriter *writer)");
             else
               {
-                print ("gsk_spv_writer_" + all_lower(ins.opname.substr(2)) + " (GskSpvWriter *writer,");
+                print ("gsk_spv_writer_" + all_lower(ins.opname) + " (GskSpvWriter *writer,");
                 print (Array(len+1).join(" ") + "GskSpvWriterSection section)");
               }
           }
@@ -702,8 +727,13 @@ else if (ARGV[0] == "functions")
               print (indent + o.append_many.format ("bytes", o.varname, "n_" + o.varname) + ";");
             else
               print (indent + o.append_one.format ("bytes", o.varname) + ";");
+            if (i == 1 && extinst)
+              {
+                print ("  g_array_append_val (bytes, (guint32) { 
gsk_spv_writer_get_id_for_extended_instructions (writer) });");
+                print ("  g_array_append_val (bytes, (guint32) { " + ins.enum_value + " });");
+              }
           }
-        print ("  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | " + 
ins.enum_value + ";");
+        print ("  g_array_index (bytes, guint32, start_index) = (bytes->len - start_index) << 16 | " + 
(extinst ? "GSK_SPV_OP_EXT_INST" : ins.enum_value) + ";");
         if (ins.result)
           {
             print ("");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]