[gtk+/wip/otte/shader: 15/26] gsksltype: Add sampler types



commit 8116c4a436109db7e896fc1b2b30f0041734df75
Author: Benjamin Otte <otte redhat com>
Date:   Wed Oct 18 05:40:40 2017 +0200

    gsksltype: Add sampler types
    
    Also add texture() and texelFetch() functions and all variants.
    
    textureGather() and textureQuery() functions are still missing

 gsk/gskslimagetype.c        |  268 +++++++++++++++++++++++++
 gsk/gskslimagetypeprivate.h |   65 ++++++
 gsk/gskslnativefunction.c   |  452 +++++++++++++++++++++++++++++++++++++++++++
 gsk/gskslstatement.c        |   40 ++++
 gsk/gsksltype.c             |  375 +++++++++++++++++++++++++++++++++++-
 gsk/gsksltypeprivate.h      |    3 +
 gsk/gsksltypesprivate.h     |   45 +++++
 gsk/gskspvwriter.c          |   38 ++++
 gsk/gskspvwriterprivate.h   |    4 +
 gsk/meson.build             |    1 +
 10 files changed, 1290 insertions(+), 1 deletions(-)
---
diff --git a/gsk/gskslimagetype.c b/gsk/gskslimagetype.c
new file mode 100644
index 0000000..2f8056c
--- /dev/null
+++ b/gsk/gskslimagetype.c
@@ -0,0 +1,268 @@
+/* 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/>.
+ */
+
+#include "config.h"
+
+#include "gskslimagetypeprivate.h"
+
+#include "gsksltypeprivate.h"
+#include "gskspvwriterprivate.h"
+
+gboolean
+gsk_sl_image_type_supports_projection (const GskSlImageType *type,
+                                       gboolean              extra_dim)
+{
+  if (type->arrayed)
+    return FALSE;
+
+  if (type->multisampled)
+    return FALSE;
+
+  if (extra_dim && type->shadow)
+    return FALSE;
+
+  switch (type->dim)
+  {
+    case GSK_SPV_DIM_1_D:
+    case GSK_SPV_DIM_2_D:
+    case GSK_SPV_DIM_RECT:
+      return TRUE;
+    case GSK_SPV_DIM_3_D:
+      return !extra_dim;
+    case GSK_SPV_DIM_CUBE:
+    case GSK_SPV_DIM_BUFFER:
+    case GSK_SPV_DIM_SUBPASS_DATA:
+    default:
+      return FALSE;
+  }
+}
+
+gboolean
+gsk_sl_image_type_supports_lod (const GskSlImageType *type)
+{
+  if (type->multisampled)
+    return FALSE;
+
+  switch (type->dim)
+  {
+    case GSK_SPV_DIM_1_D:
+      return TRUE;
+    case GSK_SPV_DIM_2_D:
+    case GSK_SPV_DIM_3_D:
+      return !type->arrayed || !type->shadow;
+    case GSK_SPV_DIM_CUBE:
+      return !type->shadow;
+    case GSK_SPV_DIM_RECT:
+    case GSK_SPV_DIM_BUFFER:
+    case GSK_SPV_DIM_SUBPASS_DATA:
+    default:
+      return FALSE;
+  }
+}
+
+gboolean
+gsk_sl_image_type_supports_bias (const GskSlImageType *type)
+{
+  if (type->multisampled)
+    return FALSE;
+
+  switch (type->dim)
+  {
+    case GSK_SPV_DIM_1_D:
+    case GSK_SPV_DIM_3_D:
+    case GSK_SPV_DIM_CUBE:
+      return TRUE;
+    case GSK_SPV_DIM_2_D:
+      return !type->arrayed || !type->shadow;
+    case GSK_SPV_DIM_RECT:
+    case GSK_SPV_DIM_BUFFER:
+    case GSK_SPV_DIM_SUBPASS_DATA:
+    default:
+      return FALSE;
+  }
+}
+
+gboolean
+gsk_sl_image_type_supports_offset (const GskSlImageType *type)
+{
+  if (type->multisampled)
+    return FALSE;
+
+  switch (type->dim)
+  {
+    case GSK_SPV_DIM_1_D:
+    case GSK_SPV_DIM_2_D:
+    case GSK_SPV_DIM_3_D:
+    case GSK_SPV_DIM_RECT:
+      return TRUE;
+    case GSK_SPV_DIM_CUBE:
+    case GSK_SPV_DIM_BUFFER:
+    case GSK_SPV_DIM_SUBPASS_DATA:
+    default:
+      return FALSE;
+  }
+}
+
+gboolean
+gsk_sl_image_type_supports_gradient (const GskSlImageType *type)
+{
+  if (type->multisampled)
+    return FALSE;
+
+  if (type->dim == GSK_SPV_DIM_BUFFER)
+    return FALSE;
+
+  return TRUE;
+}
+
+gboolean
+gsk_sl_image_type_supports_texel_fetch (const GskSlImageType *type)
+{
+  if (type->shadow)
+    return FALSE;
+
+  if (type->dim == GSK_SPV_DIM_CUBE)
+    return FALSE;
+
+  return TRUE;
+}
+
+gboolean
+gsk_sl_image_type_supports_texture (const GskSlImageType *type)
+{
+  if (type->multisampled)
+    return FALSE;
+
+  if (type->dim == GSK_SPV_DIM_BUFFER)
+    return FALSE;
+
+  return TRUE;
+}
+
+gboolean
+gsk_sl_image_type_needs_lod_argument (const GskSlImageType *type,
+                                      gboolean              texel_fetch)
+{
+  if (type->multisampled)
+    return TRUE;
+
+  return type->dim != GSK_SPV_DIM_RECT
+      && type->dim != GSK_SPV_DIM_BUFFER;
+}
+
+guint
+gsk_sl_image_type_get_dimensions (const GskSlImageType *type)
+{
+  switch (type->dim)
+  {
+    case GSK_SPV_DIM_1_D:
+    case GSK_SPV_DIM_BUFFER:
+      return 1;
+
+    case GSK_SPV_DIM_2_D:
+    case GSK_SPV_DIM_RECT:
+    case GSK_SPV_DIM_SUBPASS_DATA:
+      return 2;
+
+    case GSK_SPV_DIM_3_D:
+    case GSK_SPV_DIM_CUBE:
+      return 3;
+
+    default:
+      g_assert_not_reached ();
+      return 1;
+  }
+}
+
+guint
+gsk_sl_image_type_get_lookup_dimensions (const GskSlImageType *type,
+                                         gboolean              projection)
+{
+  guint result = gsk_sl_image_type_get_dimensions (type);
+
+  if (type->arrayed)
+    result++;
+
+  if (type->shadow)
+    {
+      /* because GLSL is GLSL */
+      result = MAX (result, 2);
+      result++;
+    }
+
+  if (projection)
+    result++;
+
+  return result;
+}
+
+GskSlType *
+gsk_sl_image_type_get_pixel_type (const GskSlImageType *type)
+{
+  if (type->shadow)
+    return gsk_sl_type_get_scalar (type->sampled_type);
+  else
+    return gsk_sl_type_get_vector (type->sampled_type, 4);
+}
+
+guint32
+gsk_sl_image_type_write_spv (const GskSlImageType *type,
+                             GskSpvWriter         *writer)
+{
+  guint32 sampled_type_id;
+
+  sampled_type_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_scalar (type->sampled_type));
+  return gsk_spv_writer_type_image (writer,
+                                    sampled_type_id,
+                                    type->dim,
+                                    type->shadow,
+                                    type->arrayed,
+                                    type->multisampled,
+                                    2 - type->sampler,
+                                    GSK_SPV_IMAGE_FORMAT_UNKNOWN,
+                                    -1);
+}
+
+guint
+gsk_sl_image_type_hash (gconstpointer type)
+{
+  const GskSlImageType *image = type;
+
+  return  image->sampled_type
+       | (image->dim << 8)
+       | (image->shadow << 16)
+       | (image->arrayed << 17)
+       | (image->multisampled << 18)
+       | (image->sampler << 19);
+}
+
+gboolean
+gsk_sl_image_type_equal (gconstpointer a,
+                         gconstpointer b)
+{
+  const GskSlImageType *ia = a;
+  const GskSlImageType *ib = b;
+
+  return ia->sampled_type == ib->sampled_type
+      && ia->dim == ib->dim
+      && ia->shadow == ib->shadow
+      && ia->arrayed == ib->arrayed
+      && ia->multisampled == ib->multisampled
+      && ia->sampler == ib->sampler;
+}
+
diff --git a/gsk/gskslimagetypeprivate.h b/gsk/gskslimagetypeprivate.h
new file mode 100644
index 0000000..0e81025
--- /dev/null
+++ b/gsk/gskslimagetypeprivate.h
@@ -0,0 +1,65 @@
+/* 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/>.
+ */
+
+#ifndef __GSK_SL_IMAGE_TYPE_PRIVATE_H__
+#define __GSK_SL_IMAGE_TYPE_PRIVATE_H__
+
+#include <glib.h>
+
+#include "gsksltypesprivate.h"
+#include "gskspvenumsprivate.h"
+
+G_BEGIN_DECLS
+
+struct _GskSlImageType 
+{
+  GskSlScalarType sampled_type;
+  GskSpvDim dim;
+  guint shadow :1;
+  guint arrayed :1;
+  guint multisampled :1;
+  guint sampler :1;
+};
+
+gboolean                gsk_sl_image_type_supports_projection           (const GskSlImageType   *type,
+                                                                         gboolean                extra_dim);
+gboolean                gsk_sl_image_type_supports_lod                  (const GskSlImageType   *type);
+gboolean                gsk_sl_image_type_supports_bias                 (const GskSlImageType   *type);
+gboolean                gsk_sl_image_type_supports_offset               (const GskSlImageType   *type);
+gboolean                gsk_sl_image_type_supports_gradient             (const GskSlImageType   *type);
+gboolean                gsk_sl_image_type_supports_texture              (const GskSlImageType   *type);
+gboolean                gsk_sl_image_type_supports_texel_fetch          (const GskSlImageType   *type);
+gboolean                gsk_sl_image_type_needs_lod_argument            (const GskSlImageType   *type,
+                                                                         gboolean                
texel_fetch);
+
+guint                   gsk_sl_image_type_get_dimensions                (const GskSlImageType   *type);
+guint                   gsk_sl_image_type_get_lookup_dimensions         (const GskSlImageType   *type,
+                                                                         gboolean                projection);
+
+GskSlType *             gsk_sl_image_type_get_pixel_type                (const GskSlImageType   *type);
+
+guint32                 gsk_sl_image_type_write_spv                     (const GskSlImageType   *type,
+                                                                         GskSpvWriter           *writer);
+
+guint                   gsk_sl_image_type_hash                          (gconstpointer           type);
+gboolean                gsk_sl_image_type_equal                         (gconstpointer           a,
+                                                                         gconstpointer           b);
+
+G_END_DECLS
+
+#endif /* __GSK_SL_IMAGE_TYPE_PRIVATE_H__ */
diff --git a/gsk/gskslnativefunction.c b/gsk/gskslnativefunction.c
index 168867d..f759c9a 100644
--- a/gsk/gskslnativefunction.c
+++ b/gsk/gskslnativefunction.c
@@ -21,6 +21,7 @@
 #include "gskslnativefunctionprivate.h"
 
 #include "gskslenvironmentprivate.h"
+#include "gskslimagetypeprivate.h"
 #include "gskslfunctionprivate.h"
 #include "gskslfunctiontypeprivate.h"
 #include "gskslscopeprivate.h"
@@ -1355,6 +1356,455 @@ gsk_sl_native_functions_add_150 (GskSlScope       *scope,
   UNIMPLEMENTED_NATIVE1 (MAT4, inverse, MAT4);
 }
 
+#define PACK_TEXTURE_CALL_INFO(types, proj, lod, bias, offset, fetch, grad) \
+  GUINT_TO_POINTER(((types) & 0xFF) | ((proj) << 16) | ((lod) << 18) | ((bias) << 19) | ((offset) << 20) | 
((fetch) << 21) | ((grad) << 22))
+#define UNPACK_TEXTURE_CALL_INFO(_info, type, proj, lod, bias, offset, fetch, grad) G_STMT_START{\
+  guint info = GPOINTER_TO_UINT(_info); \
+\
+  type = info & 0xFF; \
+  proj = (info >> 16) & 0x3; \
+  lod = (info >> 18) & 0x1; \
+  bias = (info >> 19) & 0x1; \
+  offset = (info >> 20) & 0x1; \
+  fetch = (info >> 21) & 0x1; \
+  grad = (info >> 22) & 0x1; \
+}G_STMT_END
+
+static guint32
+gsk_sl_native_texture_write_spv (GskSpvWriter *writer,
+                                 guint32      *arguments,
+                                 gpointer      user_data)
+{
+  guint types, proj, lod, bias, offset, fetch, grad, dref, min_lod;
+  const GskSlImageType *image;
+  GskSlType *type;
+  guint32 extra_args[9], n_extra_args;
+  guint32 mask;
+  guint length;
+  gboolean explicit_lod = FALSE;
+  gsize i;
+
+  UNPACK_TEXTURE_CALL_INFO(user_data, types, proj, lod, bias, offset, fetch, grad);
+  type = gsk_sl_type_get_sampler (types);
+  image = gsk_sl_type_get_image_type (type);
+  length = gsk_sl_image_type_get_lookup_dimensions (image, proj > 0);
+  mask = 0;
+  n_extra_args = 0;
+  i = 2;
+
+  if (fetch && gsk_sl_image_type_needs_lod_argument (image, fetch))
+    min_lod = i++;
+  else
+    min_lod = 0;
+
+  /* match used flags to their argument number */
+  if (lod)
+    lod = i++;
+  if (grad)
+    {
+      grad = i;
+      i += 2;
+    }
+  if (offset)
+    offset = i++;
+  if (length > 4)
+    dref = arguments[i++];
+  else if (image->shadow)
+    {
+      dref = gsk_spv_writer_composite_extract (writer,
+                                               gsk_sl_type_get_scalar (GSK_SL_FLOAT),
+                                               arguments[1],
+                                               (guint32[1]) { length - 1 - (proj ? 1 : 0) },
+                                               1);
+    }
+  else
+    dref = 0;
+  if (proj)
+    {
+      guint real_length = (proj == 2 ? 4 : MIN (4, length));
+
+      if (real_length != gsk_sl_image_type_get_dimensions (image) + 1)
+        {
+          guint32 tmp_id;
+
+          tmp_id = gsk_spv_writer_composite_extract (writer,
+                                                     gsk_sl_type_get_scalar (GSK_SL_FLOAT),
+                                                     arguments[1],
+                                                     (guint32[1]) { real_length - 1 },
+                                                     1);
+          arguments[1] = gsk_spv_writer_composite_insert (writer,
+                                                          gsk_sl_type_get_vector (GSK_SL_FLOAT, real_length),
+                                                          tmp_id,
+                                                          arguments[1],
+                                                          (guint32[1]) { gsk_sl_image_type_get_dimensions 
(image) },
+                                                          1);
+        }
+    }
+
+  if (bias)
+    bias = i++;
+
+  if (bias)
+    {
+      mask |= GSK_SPV_IMAGE_OPERANDS_BIAS;
+      extra_args[n_extra_args++] = arguments[bias];
+    }
+  if (lod)
+    {
+      mask |= GSK_SPV_IMAGE_OPERANDS_LOD;
+      extra_args[n_extra_args++] = arguments[lod];
+      explicit_lod = TRUE;
+    }
+  if (min_lod && !image->multisampled)
+    {
+      g_assert (!lod);
+      mask |= GSK_SPV_IMAGE_OPERANDS_LOD;
+      extra_args[n_extra_args++] = arguments[min_lod];
+    }
+
+  if (grad)
+    {
+      mask |= GSK_SPV_IMAGE_OPERANDS_GRAD;
+      extra_args[n_extra_args++] = arguments[grad];
+      extra_args[n_extra_args++] = arguments[grad + 1];
+      explicit_lod = TRUE;
+    }
+  if (offset)
+    {
+      if (gsk_spv_writer_get_value_for_id (writer, arguments[offset]))
+        mask |= GSK_SPV_IMAGE_OPERANDS_CONST_OFFSET;
+      else
+        mask |= GSK_SPV_IMAGE_OPERANDS_OFFSET;
+      extra_args[n_extra_args++] = arguments[offset];
+    }
+  if (min_lod && image->multisampled)
+    {
+      mask |= GSK_SPV_IMAGE_OPERANDS_SAMPLE;
+      extra_args[n_extra_args++] = arguments[min_lod];
+    }
+
+  if (fetch)
+    {
+      guint32 image_id;
+
+      image_id = gsk_spv_writer_image (writer,
+                                       gsk_spv_writer_get_id_for_image_type (writer, image),
+                                       arguments[0]);
+                                       
+      return gsk_spv_writer_image_fetch (writer,
+                                         gsk_sl_image_type_get_pixel_type (image),
+                                         image_id,
+                                         arguments[1],
+                                         mask,
+                                         extra_args,
+                                         n_extra_args);
+    }
+  else if (explicit_lod)
+    {
+      if (dref)
+        {
+          if (proj)
+            {
+              return gsk_spv_writer_image_sample_proj_dref_explicit_lod (writer,
+                                                                         gsk_sl_image_type_get_pixel_type 
(image),
+                                                                         arguments[0],
+                                                                         arguments[1],
+                                                                         dref,
+                                                                         mask,
+                                                                         extra_args,
+                                                                         n_extra_args);
+            }
+          else
+            {
+              return gsk_spv_writer_image_sample_dref_explicit_lod (writer,
+                                                                    gsk_sl_image_type_get_pixel_type (image),
+                                                                    arguments[0],
+                                                                    arguments[1],
+                                                                    dref,
+                                                                    mask,
+                                                                    extra_args,
+                                                                    n_extra_args);
+            }
+        }
+      else
+        {
+          if (proj)
+            {
+              return gsk_spv_writer_image_sample_proj_explicit_lod (writer,
+                                                                    gsk_sl_image_type_get_pixel_type (image),
+                                                                    arguments[0],
+                                                                    arguments[1],
+                                                                    mask,
+                                                                    extra_args,
+                                                                    n_extra_args);
+            }
+          else
+            {
+              return gsk_spv_writer_image_sample_explicit_lod (writer,
+                                                               gsk_sl_image_type_get_pixel_type (image),
+                                                               arguments[0],
+                                                               arguments[1],
+                                                               mask,
+                                                               extra_args,
+                                                               n_extra_args);
+            }
+        }
+    }
+  else
+    {
+      if (dref)
+        {
+          if (proj)
+            {
+              return gsk_spv_writer_image_sample_proj_dref_implicit_lod (writer,
+                                                                         gsk_sl_image_type_get_pixel_type 
(image),
+                                                                         arguments[0],
+                                                                         arguments[1],
+                                                                         dref,
+                                                                         mask,
+                                                                         extra_args,
+                                                                         n_extra_args);
+            }
+          else
+            {
+              return gsk_spv_writer_image_sample_dref_implicit_lod (writer,
+                                                                    gsk_sl_image_type_get_pixel_type (image),
+                                                                    arguments[0],
+                                                                    arguments[1],
+                                                                    dref,
+                                                                    mask,
+                                                                    extra_args,
+                                                                    n_extra_args);
+            }
+        }
+      else
+        {
+          if (proj)
+            {
+              return gsk_spv_writer_image_sample_proj_implicit_lod (writer,
+                                                                    gsk_sl_image_type_get_pixel_type (image),
+                                                                    arguments[0],
+                                                                    arguments[1],
+                                                                    mask,
+                                                                    extra_args,
+                                                                    n_extra_args);
+            }
+          else
+            {
+              return gsk_spv_writer_image_sample_implicit_lod (writer,
+                                                               gsk_sl_image_type_get_pixel_type (image),
+                                                               arguments[0],
+                                                               arguments[1],
+                                                               mask,
+                                                               extra_args,
+                                                               n_extra_args);
+            }
+        }
+    }
+}
+
+static void
+gsk_sl_native_functions_add_texture (GskSlScope       *scope,
+                                     GskSlEnvironment *environment)
+{
+  GskSlType *type;
+  const GskSlImageType *image;
+  guint types, proj, lod, bias, offset, fetch, grad;
+
+  for (types = 0; types < GSK_SL_N_SAMPLER_TYPES; types++)
+    {
+      type = gsk_sl_type_get_sampler (types);
+      image = gsk_sl_type_get_image_type (type);
+
+      for (proj = 0; proj < 3; proj++)
+        {
+          if (proj && !gsk_sl_image_type_supports_projection (image, proj == 2))
+            continue;
+
+          for (lod = 0; lod < 2; lod++)
+            {
+              if (lod && !gsk_sl_image_type_supports_lod (image))
+                continue;
+
+              for (bias = 0; bias < 2; bias++)
+                {
+                  if (bias && lod)
+                    continue;
+
+                  if (bias && gsk_sl_environment_get_stage (environment) != GSK_SL_SHADER_FRAGMENT)
+                    continue;
+
+                  if (bias && !gsk_sl_image_type_supports_bias (image))
+                    continue;
+
+                  for (offset = 0; offset < 2; offset++)
+                    {
+                      if (offset && !gsk_sl_image_type_supports_offset (image))
+                        continue;
+
+                      for (fetch = 0; fetch < 2; fetch++)
+                        {
+                          if ((proj > 0) + offset + fetch + bias + lod > 3)
+                              continue;
+                          if (fetch && (lod || bias))
+                              continue;
+                          if (fetch && !gsk_sl_image_type_supports_texel_fetch (image))
+                              continue;
+                          if (!fetch && !gsk_sl_image_type_supports_texture (image))
+                              continue;
+
+                          for (grad = 0; grad < 2; grad++) 
+                            {
+                              GskSlFunction *function;
+                              GskSlFunctionType *function_type;
+                              char *function_name;
+                              guint length;
+
+                              if ((proj > 0) + offset + fetch + grad + bias + lod > 3)
+                                continue;
+
+                              if (grad && (lod || bias))
+                                continue;
+                            
+                              if (grad && !gsk_sl_image_type_supports_gradient (image))
+                                continue;
+
+                              length = gsk_sl_image_type_get_lookup_dimensions (image, proj > 0);
+                              if (length > 4 && bias)
+                                continue;
+
+                              function_type = gsk_sl_function_type_new (gsk_sl_image_type_get_pixel_type 
(image));
+                              function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                 GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                 type);
+
+                              /* P */
+                              if (proj == 2)
+                                {
+                                  function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                     
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                     gsk_sl_type_get_vector 
(GSK_SL_FLOAT, 4));
+                                }
+                              else
+                                {
+                                  GskSlScalarType scalar;
+                                  GskSlType *arg_type;
+
+                                  scalar = fetch ? GSK_SL_INT : GSK_SL_FLOAT;
+                                  if (length == 1)
+                                    arg_type = gsk_sl_type_get_scalar (scalar);
+                                  else
+                                    arg_type = gsk_sl_type_get_vector (scalar, MIN (length, 4));
+                                  function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                     
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                     arg_type);
+                                }
+
+                              /* non-optional lod */
+                              if (fetch && gsk_sl_image_type_needs_lod_argument (image, fetch))
+                                function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                   
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                   gsk_sl_type_get_scalar 
(GSK_SL_INT));
+
+                              if (lod)
+                                function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                   
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                   gsk_sl_type_get_scalar 
(GSK_SL_FLOAT));
+
+                              if (grad)
+                                {
+                                  GskSlType *arg_type;
+                                  guint dims = gsk_sl_image_type_get_dimensions (image);
+
+                                  if (dims ==1)
+                                    arg_type = gsk_sl_type_get_scalar (GSK_SL_FLOAT);
+                                  else
+                                    arg_type = gsk_sl_type_get_vector (GSK_SL_FLOAT, dims);
+
+                                  function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                     
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                     arg_type);
+                                  function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                     
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                     arg_type);
+                                }
+
+                              if (offset)
+                                {
+                                  GskSlType *arg_type;
+                                  guint dims = gsk_sl_image_type_get_dimensions (image);
+
+                                  if (dims ==1)
+                                    arg_type = gsk_sl_type_get_scalar (GSK_SL_INT);
+                                  else
+                                    arg_type = gsk_sl_type_get_vector (GSK_SL_INT, dims);
+
+                                  function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                     
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                     arg_type);
+                                }
+
+                              /* compare */
+                              if (length > 4)
+                                function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                   
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                   gsk_sl_type_get_scalar 
(GSK_SL_FLOAT));
+
+                              if (bias)
+                                function_type = gsk_sl_function_type_add_argument (function_type,
+                                                                                   
GSK_SL_STORAGE_PARAMETER_IN,
+                                                                                   gsk_sl_type_get_scalar 
(GSK_SL_FLOAT));
+
+                              function_name = g_strconcat (fetch ? "texel" : "texture",
+                                                           proj ? "Proj" : "",
+                                                           lod ? "Lod" : "",
+                                                           grad ? "Grad" : "",
+                                                           fetch ? "Fetch" : "",
+                                                           offset ? "Offset" : "",
+                                                           NULL);
+
+                              function = gsk_sl_function_new_native (function_name,
+                                                                     function_type,
+                                                                     NULL,
+                                                                     gsk_sl_native_texture_write_spv,
+                                                                     PACK_TEXTURE_CALL_INFO (types, proj, 
lod, bias, offset, fetch, grad),
+                                                                     NULL);
+                              gsk_sl_scope_add_function (scope, function);
+#if 0
+                              g_print ("%p %p %p %p %p %p %p %u %u\n", PACK_TEXTURE_CALL_INFO (types, proj, 
lod, bias, offset, fetch, grad),
+                                                  GUINT_TO_POINTER(((types) & 0xFF) | ((proj) << 16) | 
((lod) << 18) | ((bias) < 19) | ((offset) << 20) | ((fetch) << 21)),
+                                                  GUINT_TO_POINTER(((types) & 0xFF) | ((proj) << 16) | 
((lod) << 18) | ((bias) < 19) | ((offset) << 20)),
+                                                  GUINT_TO_POINTER(((types) & 0xFF) | ((proj) << 16) | 
((lod) << 18) | ((bias) < 19)),
+                                                  GUINT_TO_POINTER(((types) & 0xFF) | ((proj) << 16) | 
((lod) << 18)),
+                                                  GUINT_TO_POINTER(((types) & 0xFF) | ((proj) << 16)),
+                                                  GUINT_TO_POINTER(((types) & 0xFF) ), types, (types) & 
0xFF);
+                              g_print ("%u %u %u %u %u %u %u\n", types, proj, lod, bias, offset, fetch, 
grad);
+                              {
+                                guint i;
+                                g_print ("%s", gsk_sl_type_get_name (gsk_sl_function_type_get_return_type 
(function_type)));
+                                g_print (" %s(", function_name);
+                                for (i = 0; i < gsk_sl_function_type_get_n_arguments (function_type); i++)
+                                  {
+                                    if (i > 0)
+                                      g_print (",");
+                                    g_print ("%s", gsk_sl_type_get_name 
(gsk_sl_function_type_get_argument_type (function_type, i)));
+                                  }
+                                g_print (");\n");
+                              }
+#endif
+
+                              g_free (function_name);
+                              gsk_sl_function_unref (function);
+                              gsk_sl_function_type_unref (function_type);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
 void
 gsk_sl_native_functions_add (GskSlScope       *scope,
                              GskSlEnvironment *environment)
@@ -1374,5 +1824,7 @@ gsk_sl_native_functions_add (GskSlScope       *scope,
   if (version < 150)
     return;
   gsk_sl_native_functions_add_150 (scope, environment);
+
+  gsk_sl_native_functions_add_texture (scope, environment);
 }
 
diff --git a/gsk/gskslstatement.c b/gsk/gskslstatement.c
index 4fdb317..27e605f 100644
--- a/gsk/gskslstatement.c
+++ b/gsk/gskslstatement.c
@@ -973,6 +973,46 @@ gsk_sl_statement_parse (GskSlScope        *scope,
     case GSK_SL_TOKEN_DMAT4X2:
     case GSK_SL_TOKEN_DMAT4X3:
     case GSK_SL_TOKEN_DMAT4X4:
+    case GSK_SL_TOKEN_SAMPLER1D:
+    case GSK_SL_TOKEN_SAMPLER2D:
+    case GSK_SL_TOKEN_SAMPLER3D:
+    case GSK_SL_TOKEN_SAMPLERCUBE:
+    case GSK_SL_TOKEN_SAMPLER1DSHADOW:
+    case GSK_SL_TOKEN_SAMPLER2DSHADOW:
+    case GSK_SL_TOKEN_SAMPLERCUBESHADOW:
+    case GSK_SL_TOKEN_SAMPLER1DARRAY:
+    case GSK_SL_TOKEN_SAMPLER2DARRAY:
+    case GSK_SL_TOKEN_SAMPLER1DARRAYSHADOW:
+    case GSK_SL_TOKEN_SAMPLER2DARRAYSHADOW:
+    case GSK_SL_TOKEN_ISAMPLER1D:
+    case GSK_SL_TOKEN_ISAMPLER2D:
+    case GSK_SL_TOKEN_ISAMPLER3D:
+    case GSK_SL_TOKEN_ISAMPLERCUBE:
+    case GSK_SL_TOKEN_ISAMPLER1DARRAY:
+    case GSK_SL_TOKEN_ISAMPLER2DARRAY:
+    case GSK_SL_TOKEN_USAMPLER1D:
+    case GSK_SL_TOKEN_USAMPLER2D:
+    case GSK_SL_TOKEN_USAMPLER3D:
+    case GSK_SL_TOKEN_USAMPLERCUBE:
+    case GSK_SL_TOKEN_USAMPLER1DARRAY:
+    case GSK_SL_TOKEN_USAMPLER2DARRAY:
+    case GSK_SL_TOKEN_SAMPLER2DRECT:
+    case GSK_SL_TOKEN_SAMPLER2DRECTSHADOW:
+    case GSK_SL_TOKEN_ISAMPLER2DRECT:
+    case GSK_SL_TOKEN_USAMPLER2DRECT:
+    case GSK_SL_TOKEN_SAMPLERBUFFER:
+    case GSK_SL_TOKEN_ISAMPLERBUFFER:
+    case GSK_SL_TOKEN_USAMPLERBUFFER:
+    case GSK_SL_TOKEN_SAMPLERCUBEARRAY:
+    case GSK_SL_TOKEN_SAMPLERCUBEARRAYSHADOW:
+    case GSK_SL_TOKEN_ISAMPLERCUBEARRAY:
+    case GSK_SL_TOKEN_USAMPLERCUBEARRAY:
+    case GSK_SL_TOKEN_SAMPLER2DMS:
+    case GSK_SL_TOKEN_ISAMPLER2DMS:
+    case GSK_SL_TOKEN_USAMPLER2DMS:
+    case GSK_SL_TOKEN_SAMPLER2DMSARRAY:
+    case GSK_SL_TOKEN_ISAMPLER2DMSARRAY:
+    case GSK_SL_TOKEN_USAMPLER2DMSARRAY:
     case GSK_SL_TOKEN_STRUCT:
       {
         GskSlType *type;
diff --git a/gsk/gsksltype.c b/gsk/gsksltype.c
index 4afd840..d16b959 100644
--- a/gsk/gsksltype.c
+++ b/gsk/gsksltype.c
@@ -21,6 +21,7 @@
 #include "gsksltypeprivate.h"
 
 #include "gskslfunctionprivate.h"
+#include "gskslimagetypeprivate.h"
 #include "gskslpreprocessorprivate.h"
 #include "gskslprinterprivate.h"
 #include "gskslscopeprivate.h"
@@ -52,6 +53,7 @@ struct _GskSlTypeClass {
   void                  (* free)                                (GskSlType           *type);
   const char *          (* get_name)                            (const GskSlType     *type);
   GskSlScalarType       (* get_scalar_type)                     (const GskSlType     *type);
+  const GskSlImageType *(* get_image_type)                      (const GskSlType     *type);
   GskSlType *           (* get_index_type)                      (const GskSlType     *type);
   gsize                 (* get_index_stride)                    (const GskSlType     *type);
   guint                 (* get_length)                          (const GskSlType     *type);
@@ -360,6 +362,12 @@ gsk_sl_type_void_get_scalar_type (const GskSlType *type)
   return GSK_SL_VOID;
 }
 
+static const GskSlImageType *
+gsk_sl_type_void_get_image_type (const GskSlType *type)
+{
+  return NULL;
+}
+
 static GskSlType *
 gsk_sl_type_void_get_index_type (const GskSlType *type)
 {
@@ -447,6 +455,7 @@ static const GskSlTypeClass GSK_SL_TYPE_VOID = {
   gsk_sl_type_void_free,
   gsk_sl_type_void_get_name,
   gsk_sl_type_void_get_scalar_type,
+  gsk_sl_type_void_get_image_type,
   gsk_sl_type_void_get_index_type,
   gsk_sl_type_void_get_index_stride,
   gsk_sl_type_void_get_length,
@@ -493,6 +502,12 @@ gsk_sl_type_scalar_get_scalar_type (const GskSlType *type)
   return scalar->scalar;
 }
 
+static const GskSlImageType *
+gsk_sl_type_scalar_get_image_type (const GskSlType *type)
+{
+  return NULL;
+}
+
 static GskSlType *
 gsk_sl_type_scalar_get_index_type (const GskSlType *type)
 {
@@ -615,6 +630,7 @@ static const GskSlTypeClass GSK_SL_TYPE_SCALAR = {
   gsk_sl_type_scalar_free,
   gsk_sl_type_scalar_get_name,
   gsk_sl_type_scalar_get_scalar_type,
+  gsk_sl_type_scalar_get_image_type,
   gsk_sl_type_scalar_get_index_type,
   gsk_sl_type_scalar_get_index_stride,
   gsk_sl_type_scalar_get_length,
@@ -663,6 +679,12 @@ gsk_sl_type_vector_get_scalar_type (const GskSlType *type)
   return vector->scalar;
 }
 
+static const GskSlImageType *
+gsk_sl_type_vector_get_image_type (const GskSlType *type)
+{
+  return NULL;
+}
+
 static GskSlType *
 gsk_sl_type_vector_get_index_type (const GskSlType *type)
 {
@@ -823,6 +845,7 @@ static const GskSlTypeClass GSK_SL_TYPE_VECTOR = {
   gsk_sl_type_vector_free,
   gsk_sl_type_vector_get_name,
   gsk_sl_type_vector_get_scalar_type,
+  gsk_sl_type_vector_get_image_type,
   gsk_sl_type_vector_get_index_type,
   gsk_sl_type_vector_get_index_stride,
   gsk_sl_type_vector_get_length,
@@ -872,6 +895,12 @@ gsk_sl_type_matrix_get_scalar_type (const GskSlType *type)
   return matrix->scalar;
 }
 
+static const GskSlImageType *
+gsk_sl_type_matrix_get_image_type (const GskSlType *type)
+{
+  return NULL;
+}
+
 static GskSlType *
 gsk_sl_type_matrix_get_index_type (const GskSlType *type)
 {
@@ -1033,6 +1062,7 @@ static const GskSlTypeClass GSK_SL_TYPE_MATRIX = {
   gsk_sl_type_matrix_free,
   gsk_sl_type_matrix_get_name,
   gsk_sl_type_matrix_get_scalar_type,
+  gsk_sl_type_matrix_get_image_type,
   gsk_sl_type_matrix_get_index_type,
   gsk_sl_type_matrix_get_index_stride,
   gsk_sl_type_matrix_get_length,
@@ -1047,6 +1077,153 @@ static const GskSlTypeClass GSK_SL_TYPE_MATRIX = {
   gsk_sl_type_matrix_write_value_spv
 };
 
+/* SAMPLER */
+
+typedef struct _GskSlTypeSampler GskSlTypeSampler;
+
+struct _GskSlTypeSampler {
+  GskSlType parent;
+
+  const char *name;
+  GskSlSamplerType sampler;
+
+  GskSlImageType image_type;
+};
+
+static void
+gsk_sl_type_sampler_free (GskSlType *type)
+{
+  g_assert_not_reached ();
+}
+
+static const char *
+gsk_sl_type_sampler_get_name (const GskSlType *type)
+{
+  const GskSlTypeSampler *sampler = (const GskSlTypeSampler *) type;
+
+  return sampler->name;
+}
+
+static GskSlScalarType
+gsk_sl_type_sampler_get_scalar_type (const GskSlType *type)
+{
+  return GSK_SL_VOID;
+}
+
+static const GskSlImageType *
+gsk_sl_type_sampler_get_image_type (const GskSlType *type)
+{
+  const GskSlTypeSampler *sampler = (const GskSlTypeSampler *) type;
+
+  return &sampler->image_type;
+}
+
+static GskSlType *
+gsk_sl_type_sampler_get_index_type (const GskSlType *type)
+{
+  return NULL;
+}
+
+static gsize
+gsk_sl_type_sampler_get_index_stride (const GskSlType *type)
+{
+  return 0;
+}
+
+static guint
+gsk_sl_type_sampler_get_length (const GskSlType *type)
+{
+  return 0;
+}
+
+static gsize
+gsk_sl_type_sampler_get_size (const GskSlType *type)
+{
+  /* XXX: setting this to 0 would make it not work in GskSlValue */
+  return sizeof (gpointer);
+}
+
+static gsize
+gsk_sl_type_sampler_get_n_components (const GskSlType *type)
+{
+  return 1;
+}
+
+static guint
+gsk_sl_type_sampler_get_n_members (const GskSlType *type)
+{
+  return 0;
+}
+
+static const GskSlTypeMember *
+gsk_sl_type_sampler_get_member (const GskSlType *type,
+                               guint            n)
+{
+  return NULL;
+}
+
+static gboolean
+gsk_sl_type_sampler_can_convert (const GskSlType *target,
+                                 const GskSlType *source)
+{
+  return gsk_sl_type_equal (target, source);
+}
+
+static guint32
+gsk_sl_type_sampler_write_spv (GskSlType    *type,
+                               GskSpvWriter *writer)
+{
+  GskSlTypeSampler *sampler = (GskSlTypeSampler *) type;
+  guint32 image_id;
+
+  image_id = gsk_spv_writer_get_id_for_image_type (writer, &sampler->image_type);
+
+  return gsk_spv_writer_type_sampled_image (writer, image_id);
+}
+
+static void
+gsk_sl_type_sampler_print_value (const GskSlType *type,
+                                 GskSlPrinter    *printer,
+                                 gconstpointer    value)
+{
+  g_assert_not_reached ();
+}
+
+static gboolean
+gsk_sl_type_sampler_value_equal (const GskSlType *type,
+                                 gconstpointer    a,
+                                 gconstpointer    b)
+{
+  return *(gconstpointer *) a == *(gconstpointer *) b;
+}
+
+static guint32
+gsk_sl_type_sampler_write_value_spv (GskSlType     *type,
+                                     GskSpvWriter  *writer,
+                                     gconstpointer  value)
+{
+  g_assert_not_reached ();
+}
+
+static const GskSlTypeClass GSK_SL_TYPE_SAMPLER = {
+  gsk_sl_type_sampler_free,
+  gsk_sl_type_sampler_get_name,
+  gsk_sl_type_sampler_get_scalar_type,
+  gsk_sl_type_sampler_get_image_type,
+  gsk_sl_type_sampler_get_index_type,
+  gsk_sl_type_sampler_get_index_stride,
+  gsk_sl_type_sampler_get_length,
+  gsk_sl_type_sampler_get_size,
+  gsk_sl_type_sampler_get_n_components,
+  gsk_sl_type_sampler_get_n_members,
+  gsk_sl_type_sampler_get_member,
+  gsk_sl_type_sampler_can_convert,
+  gsk_sl_type_sampler_write_spv,
+  gsk_sl_type_sampler_print_value,
+  gsk_sl_type_sampler_value_equal,
+  gsk_sl_type_sampler_write_value_spv
+};
+
 /* STRUCT */
 
 typedef struct _GskSlTypeStruct GskSlTypeStruct;
@@ -1093,6 +1270,12 @@ gsk_sl_type_struct_get_scalar_type (const GskSlType *type)
   return GSK_SL_VOID;
 }
 
+static const GskSlImageType *
+gsk_sl_type_struct_get_image_type (const GskSlType *type)
+{
+  return NULL;
+}
+
 static GskSlType *
 gsk_sl_type_struct_get_index_type (const GskSlType *type)
 {
@@ -1288,6 +1471,7 @@ static const GskSlTypeClass GSK_SL_TYPE_STRUCT = {
   gsk_sl_type_struct_free,
   gsk_sl_type_struct_get_name,
   gsk_sl_type_struct_get_scalar_type,
+  gsk_sl_type_struct_get_image_type,
   gsk_sl_type_struct_get_index_type,
   gsk_sl_type_struct_get_index_stride,
   gsk_sl_type_struct_get_length,
@@ -1348,6 +1532,12 @@ gsk_sl_type_block_get_scalar_type (const GskSlType *type)
   return GSK_SL_VOID;
 }
 
+static const GskSlImageType *
+gsk_sl_type_block_get_image_type (const GskSlType *type)
+{
+  return NULL;
+}
+
 static GskSlType *
 gsk_sl_type_block_get_index_type (const GskSlType *type)
 {
@@ -1507,6 +1697,7 @@ static const GskSlTypeClass GSK_SL_TYPE_BLOCK = {
   gsk_sl_type_block_free,
   gsk_sl_type_block_get_name,
   gsk_sl_type_block_get_scalar_type,
+  gsk_sl_type_block_get_image_type,
   gsk_sl_type_block_get_index_type,
   gsk_sl_type_block_get_index_stride,
   gsk_sl_type_block_get_length,
@@ -1859,6 +2050,126 @@ gsk_sl_type_new_parse (GskSlScope        *scope,
     case GSK_SL_TOKEN_DMAT4X4:
       type = gsk_sl_type_ref (gsk_sl_type_get_matrix (GSK_SL_DOUBLE, 4, 4));
       break;
+    case GSK_SL_TOKEN_SAMPLER1D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_1D));
+      break;
+    case GSK_SL_TOKEN_SAMPLER2D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D));
+      break;
+    case GSK_SL_TOKEN_SAMPLER3D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_3D));
+      break;
+    case GSK_SL_TOKEN_SAMPLERCUBE:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_CUBE));
+      break;
+    case GSK_SL_TOKEN_SAMPLER1DSHADOW:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_1D_SHADOW));
+      break;
+    case GSK_SL_TOKEN_SAMPLER2DSHADOW:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_SHADOW));
+      break;
+    case GSK_SL_TOKEN_SAMPLERCUBESHADOW:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_CUBE_SHADOW));
+      break;
+    case GSK_SL_TOKEN_SAMPLER1DARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_1D_ARRAY));
+      break;
+    case GSK_SL_TOKEN_SAMPLER2DARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_ARRAY));
+      break;
+    case GSK_SL_TOKEN_SAMPLER1DARRAYSHADOW:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_1D_ARRAY_SHADOW));
+      break;
+    case GSK_SL_TOKEN_SAMPLER2DARRAYSHADOW:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_ARRAY_SHADOW));
+      break;
+    case GSK_SL_TOKEN_ISAMPLER1D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_1D_INT));
+      break;
+    case GSK_SL_TOKEN_ISAMPLER2D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_INT));
+      break;
+    case GSK_SL_TOKEN_ISAMPLER3D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_3D_INT));
+      break;
+    case GSK_SL_TOKEN_ISAMPLERCUBE:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_CUBE_INT));
+      break;
+    case GSK_SL_TOKEN_ISAMPLER1DARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_1D_ARRAY_INT));
+      break;
+    case GSK_SL_TOKEN_ISAMPLER2DARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_ARRAY_INT));
+      break;
+    case GSK_SL_TOKEN_USAMPLER1D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_1D_UINT));
+      break;
+    case GSK_SL_TOKEN_USAMPLER2D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_UINT));
+      break;
+    case GSK_SL_TOKEN_USAMPLER3D:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_3D_UINT));
+      break;
+    case GSK_SL_TOKEN_USAMPLERCUBE:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_CUBE_UINT));
+      break;
+    case GSK_SL_TOKEN_USAMPLER1DARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_1D_ARRAY_UINT));
+      break;
+    case GSK_SL_TOKEN_USAMPLER2DARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_ARRAY_UINT));
+      break;
+    case GSK_SL_TOKEN_SAMPLER2DRECT:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_RECT));
+      break;
+    case GSK_SL_TOKEN_SAMPLER2DRECTSHADOW:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_RECT_SHADOW));
+      break;
+    case GSK_SL_TOKEN_ISAMPLER2DRECT:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_RECT_INT));
+      break;
+    case GSK_SL_TOKEN_USAMPLER2DRECT:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2D_RECT_UINT));
+      break;
+    case GSK_SL_TOKEN_SAMPLERBUFFER:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_BUFFER));
+      break;
+    case GSK_SL_TOKEN_ISAMPLERBUFFER:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_BUFFER_INT));
+      break;
+    case GSK_SL_TOKEN_USAMPLERBUFFER:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_BUFFER_UINT));
+      break;
+    case GSK_SL_TOKEN_SAMPLERCUBEARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_CUBE_ARRAY));
+      break;
+    case GSK_SL_TOKEN_SAMPLERCUBEARRAYSHADOW:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_CUBE_ARRAY_SHADOW));
+      break;
+    case GSK_SL_TOKEN_ISAMPLERCUBEARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_CUBE_ARRAY_INT));
+      break;
+    case GSK_SL_TOKEN_USAMPLERCUBEARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_CUBE_ARRAY_UINT));
+      break;
+    case GSK_SL_TOKEN_SAMPLER2DMS:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2DMS));
+      break;
+    case GSK_SL_TOKEN_ISAMPLER2DMS:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2DMS_INT));
+      break;
+    case GSK_SL_TOKEN_USAMPLER2DMS:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2DMS_UINT));
+      break;
+    case GSK_SL_TOKEN_SAMPLER2DMSARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2DMS_ARRAY));
+      break;
+    case GSK_SL_TOKEN_ISAMPLER2DMSARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2DMS_ARRAY_INT));
+      break;
+    case GSK_SL_TOKEN_USAMPLER2DMSARRAY:
+      type = gsk_sl_type_ref (gsk_sl_type_get_sampler (GSK_SL_SAMPLER_2DMS_ARRAY_UINT));
+      break;
     case GSK_SL_TOKEN_STRUCT:
       return gsk_sl_type_parse_struct (scope, preproc);
     case GSK_SL_TOKEN_IDENTIFIER:
@@ -2003,6 +2314,56 @@ gsk_sl_type_get_matrix (GskSlScalarType      scalar,
   return &builtin_matrix_types[columns - 2][rows - 2][scalar == GSK_SL_FLOAT ? 0 : 1].parent;
 }
 
+static GskSlTypeSampler
+builtin_sampler_types[] = {
+  [GSK_SL_SAMPLER_1D] =                { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler1D",              
GSK_SL_SAMPLER_1D,                { GSK_SL_FLOAT, GSK_SPV_DIM_1_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_1D_INT] =            { { &GSK_SL_TYPE_SAMPLER, 1 }, "isampler1D",             
GSK_SL_SAMPLER_1D_INT,            { GSK_SL_INT,   GSK_SPV_DIM_1_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_1D_UINT] =           { { &GSK_SL_TYPE_SAMPLER, 1 }, "usampler1D",             
GSK_SL_SAMPLER_1D_UINT,           { GSK_SL_UINT,  GSK_SPV_DIM_1_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_1D_SHADOW] =         { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler1DShadow",        
GSK_SL_SAMPLER_1D_SHADOW,         { GSK_SL_FLOAT, GSK_SPV_DIM_1_D,    1, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2D] =                { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler2D",              
GSK_SL_SAMPLER_2D,                { GSK_SL_FLOAT, GSK_SPV_DIM_2_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_INT] =            { { &GSK_SL_TYPE_SAMPLER, 1 }, "isampler2D",             
GSK_SL_SAMPLER_2D_INT,            { GSK_SL_INT,   GSK_SPV_DIM_2_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_UINT] =           { { &GSK_SL_TYPE_SAMPLER, 1 }, "usampler2D",             
GSK_SL_SAMPLER_2D_UINT,           { GSK_SL_UINT,  GSK_SPV_DIM_2_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_SHADOW] =         { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler2DShadow",        
GSK_SL_SAMPLER_2D_SHADOW,         { GSK_SL_FLOAT, GSK_SPV_DIM_2_D,    1, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_3D] =                { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler3D",              
GSK_SL_SAMPLER_3D,                { GSK_SL_FLOAT, GSK_SPV_DIM_3_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_3D_INT] =            { { &GSK_SL_TYPE_SAMPLER, 1 }, "isampler3D",             
GSK_SL_SAMPLER_3D_INT,            { GSK_SL_INT,   GSK_SPV_DIM_3_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_3D_UINT] =           { { &GSK_SL_TYPE_SAMPLER, 1 }, "usampler3D",             
GSK_SL_SAMPLER_3D_UINT,           { GSK_SL_UINT,  GSK_SPV_DIM_3_D,    0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_CUBE] =              { { &GSK_SL_TYPE_SAMPLER, 1 }, "samplerCube",            
GSK_SL_SAMPLER_CUBE,              { GSK_SL_FLOAT, GSK_SPV_DIM_CUBE,   0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_CUBE_INT] =          { { &GSK_SL_TYPE_SAMPLER, 1 }, "isamplerCube",           
GSK_SL_SAMPLER_CUBE_INT,          { GSK_SL_INT,   GSK_SPV_DIM_CUBE,   0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_CUBE_UINT] =         { { &GSK_SL_TYPE_SAMPLER, 1 }, "usamplerCube",           
GSK_SL_SAMPLER_CUBE_UINT,         { GSK_SL_UINT,  GSK_SPV_DIM_CUBE,   0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_CUBE_SHADOW] =       { { &GSK_SL_TYPE_SAMPLER, 1 }, "samplerCubeShadow",      
GSK_SL_SAMPLER_CUBE_SHADOW,       { GSK_SL_FLOAT, GSK_SPV_DIM_CUBE,   1, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_RECT] =           { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler2DRect",          
GSK_SL_SAMPLER_2D_RECT,           { GSK_SL_FLOAT, GSK_SPV_DIM_RECT,   0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_RECT_INT] =       { { &GSK_SL_TYPE_SAMPLER, 1 }, "isampler2DRect",         
GSK_SL_SAMPLER_2D_RECT_INT,       { GSK_SL_INT,   GSK_SPV_DIM_RECT,   0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_RECT_UINT] =      { { &GSK_SL_TYPE_SAMPLER, 1 }, "usampler2DRect",         
GSK_SL_SAMPLER_2D_RECT_UINT,      { GSK_SL_UINT,  GSK_SPV_DIM_RECT,   0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_RECT_SHADOW] =    { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler2DRectShadow",    
GSK_SL_SAMPLER_2D_RECT_SHADOW,    { GSK_SL_FLOAT, GSK_SPV_DIM_RECT,   1, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_1D_ARRAY] =          { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler1DArray",         
GSK_SL_SAMPLER_1D_ARRAY,          { GSK_SL_FLOAT, GSK_SPV_DIM_1_D,    0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_1D_ARRAY_INT] =      { { &GSK_SL_TYPE_SAMPLER, 1 }, "isampler1DArray",        
GSK_SL_SAMPLER_1D_ARRAY_INT,      { GSK_SL_INT,   GSK_SPV_DIM_1_D,    0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_1D_ARRAY_UINT] =     { { &GSK_SL_TYPE_SAMPLER, 1 }, "usampler1DArray",        
GSK_SL_SAMPLER_1D_ARRAY_UINT,     { GSK_SL_UINT,  GSK_SPV_DIM_1_D,    0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_1D_ARRAY_SHADOW] =   { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler1DArrayShadow",   
GSK_SL_SAMPLER_1D_ARRAY_SHADOW,   { GSK_SL_FLOAT, GSK_SPV_DIM_1_D,    1, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_ARRAY] =          { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler2DArray",         
GSK_SL_SAMPLER_2D_ARRAY,          { GSK_SL_FLOAT, GSK_SPV_DIM_2_D,    0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_ARRAY_INT] =      { { &GSK_SL_TYPE_SAMPLER, 1 }, "isampler2DArray",        
GSK_SL_SAMPLER_2D_ARRAY_INT,      { GSK_SL_INT,   GSK_SPV_DIM_2_D,    0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_ARRAY_UINT] =     { { &GSK_SL_TYPE_SAMPLER, 1 }, "usampler2DArray",        
GSK_SL_SAMPLER_2D_ARRAY_UINT,     { GSK_SL_UINT,  GSK_SPV_DIM_2_D,    0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_2D_ARRAY_SHADOW] =   { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler2DArrayShadow",   
GSK_SL_SAMPLER_2D_ARRAY_SHADOW,   { GSK_SL_FLOAT, GSK_SPV_DIM_2_D,    1, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_CUBE_ARRAY] =        { { &GSK_SL_TYPE_SAMPLER, 1 }, "samplerCubeArray",       
GSK_SL_SAMPLER_CUBE_ARRAY,        { GSK_SL_FLOAT, GSK_SPV_DIM_CUBE,   0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_CUBE_ARRAY_INT] =    { { &GSK_SL_TYPE_SAMPLER, 1 }, "isamplerCubeArray",      
GSK_SL_SAMPLER_CUBE_ARRAY_INT,    { GSK_SL_INT,   GSK_SPV_DIM_CUBE,   0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_CUBE_ARRAY_UINT] =   { { &GSK_SL_TYPE_SAMPLER, 1 }, "usamplerCubeArray",      
GSK_SL_SAMPLER_CUBE_ARRAY_UINT,   { GSK_SL_UINT,  GSK_SPV_DIM_CUBE,   0, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_CUBE_ARRAY_SHADOW] = { { &GSK_SL_TYPE_SAMPLER, 1 }, "samplerCubeArrayShadow", 
GSK_SL_SAMPLER_CUBE_ARRAY_SHADOW, { GSK_SL_FLOAT, GSK_SPV_DIM_CUBE,   1, 1, 0, 1 } },
+  [GSK_SL_SAMPLER_BUFFER] =            { { &GSK_SL_TYPE_SAMPLER, 1 }, "samplerBuffer",          
GSK_SL_SAMPLER_BUFFER,            { GSK_SL_FLOAT, GSK_SPV_DIM_BUFFER, 0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_BUFFER_INT] =        { { &GSK_SL_TYPE_SAMPLER, 1 }, "isamplerBuffer",         
GSK_SL_SAMPLER_BUFFER_INT,        { GSK_SL_INT,   GSK_SPV_DIM_BUFFER, 0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_BUFFER_UINT] =       { { &GSK_SL_TYPE_SAMPLER, 1 }, "usamplerBuffer",         
GSK_SL_SAMPLER_BUFFER_UINT,       { GSK_SL_UINT,  GSK_SPV_DIM_BUFFER, 0, 0, 0, 1 } },
+  [GSK_SL_SAMPLER_2DMS] =              { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler2DMS",            
GSK_SL_SAMPLER_2DMS,              { GSK_SL_FLOAT, GSK_SPV_DIM_2_D,    0, 0, 1, 1 } },
+  [GSK_SL_SAMPLER_2DMS_INT] =          { { &GSK_SL_TYPE_SAMPLER, 1 }, "isampler2DMS",           
GSK_SL_SAMPLER_2DMS_INT,          { GSK_SL_INT,   GSK_SPV_DIM_2_D,    0, 0, 1, 1 } },
+  [GSK_SL_SAMPLER_2DMS_UINT] =         { { &GSK_SL_TYPE_SAMPLER, 1 }, "usampler2DMS",           
GSK_SL_SAMPLER_2DMS_UINT,         { GSK_SL_UINT,  GSK_SPV_DIM_2_D,    0, 0, 1, 1 } },
+  [GSK_SL_SAMPLER_2DMS_ARRAY] =        { { &GSK_SL_TYPE_SAMPLER, 1 }, "sampler2DMSArray",       
GSK_SL_SAMPLER_2DMS_ARRAY,        { GSK_SL_FLOAT, GSK_SPV_DIM_2_D,    0, 1, 1, 1 } },
+  [GSK_SL_SAMPLER_2DMS_ARRAY_INT] =    { { &GSK_SL_TYPE_SAMPLER, 1 }, "isampler2DMSArray",      
GSK_SL_SAMPLER_2DMS_ARRAY_INT,    { GSK_SL_INT,   GSK_SPV_DIM_2_D,    0, 1, 1, 1 } },
+  [GSK_SL_SAMPLER_2DMS_ARRAY_UINT] =   { { &GSK_SL_TYPE_SAMPLER, 1 }, "usampler2DMSArray",      
GSK_SL_SAMPLER_2DMS_ARRAY_UINT,   { GSK_SL_UINT,  GSK_SPV_DIM_2_D,    0, 1, 1, 1 } }
+};
+
+GskSlType *
+gsk_sl_type_get_sampler (GskSlSamplerType sampler)
+{
+  return &builtin_sampler_types[sampler].parent;
+}
+
 GskSlType *
 gsk_sl_type_ref (GskSlType *type)
 {
@@ -2077,9 +2438,15 @@ gsk_sl_type_is_block (const GskSlType *type)
 }
 
 gboolean
+gsk_sl_type_is_sampler (const GskSlType *type)
+{
+  return type->class == &GSK_SL_TYPE_SAMPLER;
+}
+
+gboolean
 gsk_sl_type_is_opaque (const GskSlType *type)
 {
-  return FALSE;
+  return gsk_sl_type_is_sampler (type);
 }
 
 GskSlScalarType
@@ -2088,6 +2455,12 @@ gsk_sl_type_get_scalar_type (const GskSlType *type)
   return type->class->get_scalar_type (type);
 }
 
+const GskSlImageType *
+gsk_sl_type_get_image_type (const GskSlType *type)
+{
+  return type->class->get_image_type (type);
+}
+
 GskSlType *
 gsk_sl_type_get_index_type (const GskSlType *type)
 {
diff --git a/gsk/gsksltypeprivate.h b/gsk/gsksltypeprivate.h
index 567762c..0838b97 100644
--- a/gsk/gsksltypeprivate.h
+++ b/gsk/gsksltypeprivate.h
@@ -38,6 +38,7 @@ GskSlType *             gsk_sl_type_get_vector                  (GskSlScalarType
 GskSlType *             gsk_sl_type_get_matrix                  (GskSlScalarType      scalar,
                                                                  guint                columns,
                                                                  guint                rows);
+GskSlType *             gsk_sl_type_get_sampler                 (GskSlSamplerType     sampler);
 GskSlType *             gsk_sl_type_get_matching                (GskSlType           *type,
                                                                  GskSlScalarType      scalar);
 
@@ -51,10 +52,12 @@ gboolean                gsk_sl_type_is_matrix                   (const GskSlType
 gboolean                gsk_sl_type_is_basic                    (const GskSlType     *type);
 gboolean                gsk_sl_type_is_struct                   (const GskSlType     *type);
 gboolean                gsk_sl_type_is_block                    (const GskSlType     *type);
+gboolean                gsk_sl_type_is_sampler                  (const GskSlType     *type);
 gboolean                gsk_sl_type_is_opaque                   (const GskSlType     *type);
 
 const char *            gsk_sl_type_get_name                    (const GskSlType     *type);
 GskSlScalarType         gsk_sl_type_get_scalar_type             (const GskSlType     *type);
+const GskSlImageType *  gsk_sl_type_get_image_type              (const GskSlType     *type);
 GskSlType *             gsk_sl_type_get_index_type              (const GskSlType     *type);
 gsize                   gsk_sl_type_get_index_stride            (const GskSlType     *type);
 guint                   gsk_sl_type_get_length                  (const GskSlType     *type);
diff --git a/gsk/gsksltypesprivate.h b/gsk/gsksltypesprivate.h
index b8e84cf..6e26228 100644
--- a/gsk/gsksltypesprivate.h
+++ b/gsk/gsksltypesprivate.h
@@ -27,6 +27,7 @@ typedef struct _GskSlExpression         GskSlExpression;
 typedef struct _GskSlFunction           GskSlFunction;
 typedef struct _GskSlFunctionMatcher    GskSlFunctionMatcher;
 typedef struct _GskSlFunctionType       GskSlFunctionType;
+typedef struct _GskSlImageType          GskSlImageType;
 typedef struct _GskSlNativeFunction     GskSlNativeFunction;
 typedef struct _GskSlPreprocessor       GskSlPreprocessor;
 typedef struct _GskSlPointerType        GskSlPointerType;
@@ -53,6 +54,50 @@ typedef enum {
 } GskSlScalarType;
 
 typedef enum {
+  GSK_SL_SAMPLER_1D,
+  GSK_SL_SAMPLER_1D_INT,
+  GSK_SL_SAMPLER_1D_UINT,
+  GSK_SL_SAMPLER_1D_SHADOW,
+  GSK_SL_SAMPLER_2D,
+  GSK_SL_SAMPLER_2D_INT,
+  GSK_SL_SAMPLER_2D_UINT,
+  GSK_SL_SAMPLER_2D_SHADOW,
+  GSK_SL_SAMPLER_3D,
+  GSK_SL_SAMPLER_3D_INT,
+  GSK_SL_SAMPLER_3D_UINT,
+  GSK_SL_SAMPLER_CUBE,
+  GSK_SL_SAMPLER_CUBE_INT,
+  GSK_SL_SAMPLER_CUBE_UINT,
+  GSK_SL_SAMPLER_CUBE_SHADOW,
+  GSK_SL_SAMPLER_2D_RECT,
+  GSK_SL_SAMPLER_2D_RECT_INT,
+  GSK_SL_SAMPLER_2D_RECT_UINT,
+  GSK_SL_SAMPLER_2D_RECT_SHADOW,
+  GSK_SL_SAMPLER_1D_ARRAY,
+  GSK_SL_SAMPLER_1D_ARRAY_INT,
+  GSK_SL_SAMPLER_1D_ARRAY_UINT,
+  GSK_SL_SAMPLER_1D_ARRAY_SHADOW,
+  GSK_SL_SAMPLER_2D_ARRAY,
+  GSK_SL_SAMPLER_2D_ARRAY_INT,
+  GSK_SL_SAMPLER_2D_ARRAY_UINT,
+  GSK_SL_SAMPLER_2D_ARRAY_SHADOW,
+  GSK_SL_SAMPLER_CUBE_ARRAY,
+  GSK_SL_SAMPLER_CUBE_ARRAY_INT,
+  GSK_SL_SAMPLER_CUBE_ARRAY_UINT,
+  GSK_SL_SAMPLER_CUBE_ARRAY_SHADOW,
+  GSK_SL_SAMPLER_BUFFER,
+  GSK_SL_SAMPLER_BUFFER_INT,
+  GSK_SL_SAMPLER_BUFFER_UINT,
+  GSK_SL_SAMPLER_2DMS,
+  GSK_SL_SAMPLER_2DMS_INT,
+  GSK_SL_SAMPLER_2DMS_UINT,
+  GSK_SL_SAMPLER_2DMS_ARRAY,
+  GSK_SL_SAMPLER_2DMS_ARRAY_INT,
+  GSK_SL_SAMPLER_2DMS_ARRAY_UINT,
+  GSK_SL_N_SAMPLER_TYPES
+} GskSlSamplerType;
+
+typedef enum {
   GSK_SL_STORAGE_DEFAULT,
 
   GSK_SL_STORAGE_GLOBAL,
diff --git a/gsk/gskspvwriter.c b/gsk/gskspvwriter.c
index 8b82515..bda442e 100644
--- a/gsk/gskspvwriter.c
+++ b/gsk/gskspvwriter.c
@@ -22,6 +22,7 @@
 
 #include "gskslfunctionprivate.h"
 #include "gskslfunctiontypeprivate.h"
+#include "gskslimagetypeprivate.h"
 #include "gskslqualifierprivate.h"
 #include "gsksltypeprivate.h"
 #include "gskslvalueprivate.h"
@@ -58,6 +59,7 @@ struct _GskSpvWriter
   GSList *pending_blocks;
 
   GHashTable *types;
+  GHashTable *image_types;
   GHashTable *pointer_types;
   GHashTable *values;
   GHashTable *variables;
@@ -140,6 +142,8 @@ gsk_spv_writer_new (GskSlShaderStage stage)
 
   writer->types = g_hash_table_new_full (gsk_sl_type_hash, gsk_sl_type_equal,
                                          (GDestroyNotify) gsk_sl_type_unref, NULL);
+  writer->image_types = g_hash_table_new_full (gsk_sl_image_type_hash, gsk_sl_image_type_equal,
+                                               NULL, NULL);
   writer->pointer_types = g_hash_table_new_full (pointer_type_hash, pointer_type_equal,
                                                  pointer_type_free, NULL);
   writer->values = g_hash_table_new_full (gsk_sl_value_hash, gsk_sl_value_equal,
@@ -185,6 +189,7 @@ gsk_spv_writer_unref (GskSpvWriter *writer)
 
   g_hash_table_destroy (writer->pointer_types);
   g_hash_table_destroy (writer->types);
+  g_hash_table_destroy (writer->image_types);
   g_hash_table_destroy (writer->values);
   g_hash_table_destroy (writer->variables);
   g_hash_table_destroy (writer->functions);
@@ -341,6 +346,7 @@ gsk_spv_writer_clear (GskSpvWriter *writer)
 
   g_hash_table_remove_all (writer->pointer_types);
   g_hash_table_remove_all (writer->types);
+  g_hash_table_remove_all (writer->image_types);
   g_hash_table_remove_all (writer->values);
   g_hash_table_remove_all (writer->variables);
   g_hash_table_remove_all (writer->functions);
@@ -411,6 +417,21 @@ gsk_spv_writer_get_id_for_type (GskSpvWriter *writer,
 }
 
 guint32
+gsk_spv_writer_get_id_for_image_type (GskSpvWriter         *writer,
+                                      const GskSlImageType *type)
+{
+  guint32 result;
+
+  result = GPOINTER_TO_UINT (g_hash_table_lookup (writer->image_types, type));
+  if (result != 0)
+    return result;
+
+  result = gsk_sl_image_type_write_spv (type, writer);
+  g_hash_table_insert (writer->image_types, (gpointer) type, GUINT_TO_POINTER (result));
+  return result;
+}
+
+guint32
 gsk_spv_writer_get_id_for_pointer_type (GskSpvWriter       *writer,
                                         GskSlType          *type,
                                         GskSpvStorageClass  storage)
@@ -445,6 +466,23 @@ gsk_spv_writer_get_id_for_value (GskSpvWriter *writer,
   return result;
 }
 
+GskSlValue *
+gsk_spv_writer_get_value_for_id (GskSpvWriter *writer,
+                                 guint32       id)
+{
+  GHashTableIter iter;
+  gpointer value, value_id;
+
+  g_hash_table_iter_init (&iter, writer->values);
+  while (g_hash_table_iter_next (&iter, &value, &value_id))
+    {
+      if (GPOINTER_TO_UINT (value_id) == id)
+        return value;
+    }
+
+  return NULL;
+}
+
 guint32
 gsk_spv_writer_get_id_for_zero (GskSpvWriter *writer,
                                 GskSlType    *type)
diff --git a/gsk/gskspvwriterprivate.h b/gsk/gskspvwriterprivate.h
index 37342b2..4d7e1d3 100644
--- a/gsk/gskspvwriterprivate.h
+++ b/gsk/gskspvwriterprivate.h
@@ -61,11 +61,15 @@ 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_image_type    (GskSpvWriter           *writer,
+                                                                 const GskSlImageType   *type);
 guint32                 gsk_spv_writer_get_id_for_pointer_type  (GskSpvWriter           *writer,
                                                                  GskSlType              *type,
                                                                  GskSpvStorageClass      storage);
 guint32                 gsk_spv_writer_get_id_for_value         (GskSpvWriter           *writer,
                                                                  GskSlValue             *value);
+GskSlValue *            gsk_spv_writer_get_value_for_id         (GskSpvWriter           *writer,
+                                                                 guint32                 id);
 guint32                 gsk_spv_writer_get_id_for_zero          (GskSpvWriter           *writer,
                                                                  GskSlType              *type);
 guint32                 gsk_spv_writer_get_id_for_one           (GskSpvWriter           *writer,
diff --git a/gsk/meson.build b/gsk/meson.build
index 5935a35..6302062 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -42,6 +42,7 @@ gsk_private_sources = files([
   'gskslexpression.c',
   'gskslfunction.c',
   'gskslfunctiontype.c',
+  'gskslimagetype.c',
   'gskslnativefunction.c',
   'gskslpreprocessor.c',
   'gskslprinter.c',


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