util: Move gallium's PIPE_FORMAT utils to /util/format/
[mesa.git] / src / gallium / drivers / llvmpipe / lp_texture.c
index d60d10158de1124d2fc76e801daafc735be6ce1b..0d5c4ac544d112aa54bcfa711d2fcd1508894f73 100644 (file)
 
 #include "util/u_inlines.h"
 #include "util/u_cpu_detect.h"
-#include "util/u_format.h"
+#include "util/format/u_format.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
-#include "util/u_simple_list.h"
+#include "util/simple_list.h"
 #include "util/u_transfer.h"
 
 #include "lp_context.h"
@@ -62,11 +62,12 @@ static unsigned id_counter = 0;
 
 /**
  * Conventional allocation path for non-display textures:
- * Just compute row strides here.  Storage is allocated on demand later.
+ * Compute strides and allocate data (unless asked not to).
  */
 static boolean
 llvmpipe_texture_layout(struct llvmpipe_screen *screen,
-                        struct llvmpipe_resource *lpr)
+                        struct llvmpipe_resource *lpr,
+                        boolean allocate)
 {
    struct pipe_resource *pt = &lpr->base;
    unsigned level;
@@ -75,80 +76,86 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
    unsigned depth = pt->depth0;
    uint64_t total_size = 0;
    unsigned layers = pt->array_size;
+   /* XXX:
+    * This alignment here (same for displaytarget) was added for the purpose of
+    * ARB_map_buffer_alignment. I am not convinced it's needed for non-buffer
+    * resources. Otherwise we'd want the max of cacheline size and 16 (max size
+    * of a block for all formats) though this should not be strictly necessary
+    * neither. In any case it can only affect compressed or 1d textures.
+    */
+   unsigned mip_align = MAX2(64, util_cpu_caps.cacheline);
 
    assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
    assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
 
    for (level = 0; level <= pt->last_level; level++) {
+      uint64_t mipsize;
+      unsigned align_x, align_y, nblocksx, nblocksy, block_size, num_slices;
 
       /* Row stride and image stride */
-      {
-         unsigned align_x, align_y, nblocksx, nblocksy, block_size;
-
-         /* For non-compressed formats we need 4x4 pixel alignment
-          * so we can read/write LP_RASTER_BLOCK_SIZE when rendering to them.
-          * We also want cache line size in x direction,
-          * otherwise same cache line could end up in multiple threads.
-          * For explicit 1d resources however we reduce this to 4x1 and
-          * handle specially in render output code (as we need to do special
-          * handling there for buffers in any case).
-          */
-         if (util_format_is_compressed(pt->format))
-            align_x = align_y = 1;
-         else {
-            align_x = LP_RASTER_BLOCK_SIZE;
-            if (llvmpipe_resource_is_1d(&lpr->base))
-               align_y = 1;
-            else
-               align_y = LP_RASTER_BLOCK_SIZE;
-         }
-
-         nblocksx = util_format_get_nblocksx(pt->format,
-                                             align(width, align_x));
-         nblocksy = util_format_get_nblocksy(pt->format,
-                                             align(height, align_y));
-         block_size = util_format_get_blocksize(pt->format);
 
-         if (util_format_is_compressed(pt->format))
-            lpr->row_stride[level] = nblocksx * block_size;
+      /* For non-compressed formats we need 4x4 pixel alignment
+       * so we can read/write LP_RASTER_BLOCK_SIZE when rendering to them.
+       * We also want cache line size in x direction,
+       * otherwise same cache line could end up in multiple threads.
+       * For explicit 1d resources however we reduce this to 4x1 and
+       * handle specially in render output code (as we need to do special
+       * handling there for buffers in any case).
+       */
+      if (util_format_is_compressed(pt->format))
+         align_x = align_y = 1;
+      else {
+         align_x = LP_RASTER_BLOCK_SIZE;
+         if (llvmpipe_resource_is_1d(&lpr->base))
+            align_y = 1;
          else
-            lpr->row_stride[level] = align(nblocksx * block_size, util_cpu_caps.cacheline);
+            align_y = LP_RASTER_BLOCK_SIZE;
+      }
 
-         /* if row_stride * height > LP_MAX_TEXTURE_SIZE */
-         if ((uint64_t)lpr->row_stride[level] * nblocksy > LP_MAX_TEXTURE_SIZE) {
-            /* image too large */
-            goto fail;
-         }
+      nblocksx = util_format_get_nblocksx(pt->format,
+                                          align(width, align_x));
+      nblocksy = util_format_get_nblocksy(pt->format,
+                                          align(height, align_y));
+      block_size = util_format_get_blocksize(pt->format);
+
+      if (util_format_is_compressed(pt->format))
+         lpr->row_stride[level] = nblocksx * block_size;
+      else
+         lpr->row_stride[level] = align(nblocksx * block_size, util_cpu_caps.cacheline);
 
-         lpr->img_stride[level] = lpr->row_stride[level] * nblocksy;
+      /* if row_stride * height > LP_MAX_TEXTURE_SIZE */
+      if ((uint64_t)lpr->row_stride[level] * nblocksy > LP_MAX_TEXTURE_SIZE) {
+         /* image too large */
+         goto fail;
       }
 
-      /* Number of 3D image slices, cube faces or texture array layers */
-      {
-         unsigned num_slices;
-
-         if (lpr->base.target == PIPE_TEXTURE_CUBE)
-            num_slices = 6;
-         else if (lpr->base.target == PIPE_TEXTURE_3D)
-            num_slices = depth;
-         else if (lpr->base.target == PIPE_TEXTURE_1D_ARRAY ||
-                  lpr->base.target == PIPE_TEXTURE_2D_ARRAY)
-            num_slices = layers;
-         else
-            num_slices = 1;
+      lpr->img_stride[level] = lpr->row_stride[level] * nblocksy;
 
-         lpr->num_slices_faces[level] = num_slices;
+      /* Number of 3D image slices, cube faces or texture array layers */
+      if (lpr->base.target == PIPE_TEXTURE_CUBE) {
+         assert(layers == 6);
       }
 
+      if (lpr->base.target == PIPE_TEXTURE_3D)
+         num_slices = depth;
+      else if (lpr->base.target == PIPE_TEXTURE_1D_ARRAY ||
+               lpr->base.target == PIPE_TEXTURE_2D_ARRAY ||
+               lpr->base.target == PIPE_TEXTURE_CUBE ||
+               lpr->base.target == PIPE_TEXTURE_CUBE_ARRAY)
+         num_slices = layers;
+      else
+         num_slices = 1;
+
       /* if img_stride * num_slices_faces > LP_MAX_TEXTURE_SIZE */
-      if (lpr->img_stride[level] >
-          LP_MAX_TEXTURE_SIZE / lpr->num_slices_faces[level]) {
+      mipsize = (uint64_t)lpr->img_stride[level] * num_slices;
+      if (mipsize > LP_MAX_TEXTURE_SIZE) {
          /* volume too large */
          goto fail;
       }
 
-      total_size += (uint64_t) lpr->num_slices_faces[level]
-                  * (uint64_t) lpr->img_stride[level];
+      lpr->mip_offsets[level] = total_size;
+
+      total_size += align((unsigned)mipsize, mip_align);
       if (total_size > LP_MAX_TEXTURE_SIZE) {
          goto fail;
       }
@@ -159,6 +166,16 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
       depth = u_minify(depth, 1);
    }
 
+   if (allocate) {
+      lpr->tex_data = align_malloc(total_size, mip_align);
+      if (!lpr->tex_data) {
+         return FALSE;
+      }
+      else {
+         memset(lpr->tex_data, 0, total_size);
+      }
+   }
+
    return TRUE;
 
 fail:
@@ -170,20 +187,21 @@ fail:
  * Check the size of the texture specified by 'res'.
  * \return TRUE if OK, FALSE if too large.
  */
-static boolean
+static bool
 llvmpipe_can_create_resource(struct pipe_screen *screen,
                              const struct pipe_resource *res)
 {
    struct llvmpipe_resource lpr;
    memset(&lpr, 0, sizeof(lpr));
    lpr.base = *res;
-   return llvmpipe_texture_layout(llvmpipe_screen(screen), &lpr);
+   return llvmpipe_texture_layout(llvmpipe_screen(screen), &lpr, false);
 }
 
 
 static boolean
 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
-                              struct llvmpipe_resource *lpr)
+                              struct llvmpipe_resource *lpr,
+                              const void *map_front_private)
 {
    struct sw_winsys *winsys = screen->winsys;
 
@@ -193,20 +211,18 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
    const unsigned width = MAX2(1, align(lpr->base.width0, TILE_SIZE));
    const unsigned height = MAX2(1, align(lpr->base.height0, TILE_SIZE));
 
-   lpr->num_slices_faces[0] = 1;
-   lpr->img_stride[0] = 0;
-
    lpr->dt = winsys->displaytarget_create(winsys,
                                           lpr->base.bind,
                                           lpr->base.format,
                                           width, height,
                                           64,
+                                          map_front_private,
                                           &lpr->row_stride[0] );
 
    if (lpr->dt == NULL)
       return FALSE;
 
-   {
+   if (!map_front_private) {
       void *map = winsys->displaytarget_map(winsys, lpr->dt,
                                             PIPE_TRANSFER_WRITE);
 
@@ -221,8 +237,9 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
 
 
 static struct pipe_resource *
-llvmpipe_resource_create(struct pipe_screen *_screen,
-                         const struct pipe_resource *templat)
+llvmpipe_resource_create_front(struct pipe_screen *_screen,
+                               const struct pipe_resource *templat,
+                               const void *map_front_private)
 {
    struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
    struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
@@ -240,12 +257,12 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
                             PIPE_BIND_SCANOUT |
                             PIPE_BIND_SHARED)) {
          /* displayable surface */
-         if (!llvmpipe_displaytarget_layout(screen, lpr))
+         if (!llvmpipe_displaytarget_layout(screen, lpr, map_front_private))
             goto fail;
       }
       else {
          /* texture map */
-         if (!llvmpipe_texture_layout(screen, lpr))
+         if (!llvmpipe_texture_layout(screen, lpr, true))
             goto fail;
       }
    }
@@ -262,6 +279,7 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
        * offset doesn't need to be aligned to LP_RASTER_BLOCK_SIZE.
        */
       lpr->data = align_malloc(bytes + (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float), 64);
+
       /*
        * buffers don't really have stride but it's probably safer
        * (for code doing same calculations for buffers and textures)
@@ -287,6 +305,14 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
 }
 
 
+static struct pipe_resource *
+llvmpipe_resource_create(struct pipe_screen *_screen,
+                         const struct pipe_resource *templat)
+{
+   return llvmpipe_resource_create_front(_screen, templat, NULL);
+}
+
+
 static void
 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
                           struct pipe_resource *pt)
@@ -301,9 +327,9 @@ llvmpipe_resource_destroy(struct pipe_screen *pscreen,
    }
    else if (llvmpipe_resource_is_texture(pt)) {
       /* free linear image data */
-      if (lpr->linear_img.data) {
-         align_free(lpr->linear_img.data);
-         lpr->linear_img.data = NULL;
+      if (lpr->tex_data) {
+         align_free(lpr->tex_data);
+         lpr->tex_data = NULL;
       }
    }
    else if (!lpr->userBuffer) {
@@ -359,13 +385,13 @@ llvmpipe_resource_map(struct pipe_resource *resource,
       map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage);
 
       /* install this linear image in texture data structure */
-      lpr->linear_img.data = map;
+      lpr->tex_data = map;
 
       return map;
    }
    else if (llvmpipe_resource_is_texture(resource)) {
 
-      map = llvmpipe_get_texture_image(lpr, layer, level, tex_usage);
+      map = llvmpipe_get_texture_image_address(lpr, layer, level);
       return map;
    }
    else {
@@ -411,7 +437,8 @@ llvmpipe_resource_data(struct pipe_resource *resource)
 static struct pipe_resource *
 llvmpipe_resource_from_handle(struct pipe_screen *screen,
                               const struct pipe_resource *template,
-                              struct winsys_handle *whandle)
+                              struct winsys_handle *whandle,
+                              unsigned usage)
 {
    struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
    struct llvmpipe_resource *lpr;
@@ -436,9 +463,6 @@ llvmpipe_resource_from_handle(struct pipe_screen *screen,
    assert(lpr->base.height0 == height);
 #endif
 
-   lpr->num_slices_faces[0] = 1;
-   lpr->img_stride[0] = 0;
-
    lpr->dt = winsys->displaytarget_from_handle(winsys,
                                                template,
                                                whandle,
@@ -462,17 +486,19 @@ no_lpr:
 }
 
 
-static boolean
+static bool
 llvmpipe_resource_get_handle(struct pipe_screen *screen,
+                             struct pipe_context *ctx,
                             struct pipe_resource *pt,
-                            struct winsys_handle *whandle)
+                            struct winsys_handle *whandle,
+                             unsigned usage)
 {
    struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
    struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
 
    assert(lpr->dt);
    if (!lpr->dt)
-      return FALSE;
+      return false;
 
    return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle);
 }
@@ -520,14 +546,14 @@ llvmpipe_transfer_map( struct pipe_context *pipe,
       }
    }
 
-   /* Check if we're mapping the current constant buffer */
+   /* Check if we're mapping a current constant buffer */
    if ((usage & PIPE_TRANSFER_WRITE) &&
        (resource->bind & PIPE_BIND_CONSTANT_BUFFER)) {
       unsigned i;
-      for (i = 0; i < Elements(llvmpipe->constants[PIPE_SHADER_FRAGMENT]); ++i) {
+      for (i = 0; i < ARRAY_SIZE(llvmpipe->constants[PIPE_SHADER_FRAGMENT]); ++i) {
          if (resource == llvmpipe->constants[PIPE_SHADER_FRAGMENT][i].buffer) {
             /* constants may have changed */
-            llvmpipe->dirty |= LP_NEW_CONSTANTS;
+            llvmpipe->dirty |= LP_NEW_FS_CONSTANTS;
             break;
          }
       }
@@ -618,16 +644,11 @@ llvmpipe_is_resource_referenced( struct pipe_context *pipe,
                                  unsigned level)
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
-
-   /*
-    * XXX checking only resources with the right bind flags
-    * is unsafe since with opengl state tracker we can end up
-    * with resources bound to places they weren't supposed to be
-    * (buffers bound as sampler views is one possibility here).
-    */
    if (!(presource->bind & (PIPE_BIND_DEPTH_STENCIL |
                             PIPE_BIND_RENDER_TARGET |
-                            PIPE_BIND_SAMPLER_VIEW)))
+                            PIPE_BIND_SAMPLER_VIEW |
+                            PIPE_BIND_SHADER_BUFFER |
+                            PIPE_BIND_SHADER_IMAGE)))
       return LP_UNREFERENCED;
 
    return lp_setup_is_resource_referenced(llvmpipe->setup, presource);
@@ -651,7 +672,7 @@ llvmpipe_get_format_alignment( enum pipe_format format )
 
    bytes = size / 8;
 
-   if (!util_is_power_of_two(bytes)) {
+   if (!util_is_power_of_two_or_zero(bytes)) {
       bytes /= desc->nr_channels;
    }
 
@@ -665,17 +686,18 @@ llvmpipe_get_format_alignment( enum pipe_format format )
 
 /**
  * Create buffer which wraps user-space data.
+ * XXX unreachable.
  */
 struct pipe_resource *
 llvmpipe_user_buffer_create(struct pipe_screen *screen,
                             void *ptr,
                             unsigned bytes,
-                           unsigned bind_flags)
+                            unsigned bind_flags)
 {
    struct llvmpipe_resource *buffer;
 
    buffer = CALLOC_STRUCT(llvmpipe_resource);
-   if(!buffer)
+   if (!buffer)
       return NULL;
 
    pipe_reference_init(&buffer->base.reference, 1);
@@ -706,18 +728,6 @@ tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level)
 }
 
 
-/**
- * Compute size (in bytes) need to store a texture image / mipmap level,
- * including all cube faces or 3D image slices
- */
-static unsigned
-tex_image_size(const struct llvmpipe_resource *lpr, unsigned level)
-{
-   const unsigned buf_size = tex_image_face_size(lpr, level);
-   return buf_size * lpr->num_slices_faces[level];
-}
-
-
 /**
  * Return pointer to a 2D texture image/face/slice.
  * No tiled/linear conversion is done.
@@ -726,163 +736,16 @@ ubyte *
 llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpr,
                                    unsigned face_slice, unsigned level)
 {
-   struct llvmpipe_texture_image *img;
    unsigned offset;
 
-   img = &lpr->linear_img;
+   assert(llvmpipe_resource_is_texture(&lpr->base));
+
    offset = lpr->mip_offsets[level];
 
    if (face_slice > 0)
       offset += face_slice * tex_image_face_size(lpr, level);
 
-   return (ubyte *) img->data + offset;
-}
-
-
-/**
- * Allocate storage for a linear image
- * (all cube faces and all 3D slices, all levels).
- */
-static void
-alloc_image_data(struct llvmpipe_resource *lpr)
-{
-   uint alignment = MAX2(64, util_cpu_caps.cacheline);
-   uint level;
-   uint offset = 0;
-
-   if (lpr->dt) {
-      /* we get the linear memory from the winsys, and it has
-       * already been zeroed
-       */
-      struct llvmpipe_screen *screen = llvmpipe_screen(lpr->base.screen);
-      struct sw_winsys *winsys = screen->winsys;
-
-      assert(lpr->base.last_level == 0);
-
-      lpr->linear_img.data =
-         winsys->displaytarget_map(winsys, lpr->dt,
-                                   PIPE_TRANSFER_READ_WRITE);
-   }
-   else {
-      /* not a display target - allocate regular memory */
-      /*
-       * Offset calculation for start of a specific mip/layer is always
-       * offset = lpr->linear_mip_offsets[level] + lpr->img_stride[level] * layer
-       */
-      for (level = 0; level <= lpr->base.last_level; level++) {
-         uint buffer_size = tex_image_size(lpr, level);
-         lpr->mip_offsets[level] = offset;
-         offset += align(buffer_size, alignment);
-      }
-      lpr->linear_img.data = align_malloc(offset, alignment);
-      if (lpr->linear_img.data) {
-         memset(lpr->linear_img.data, 0, offset);
-      }
-   }
-}
-
-
-
-/**
- * Return pointer to texture image data
- * for a particular cube face or 3D texture slice.
- *
- * \param face_slice  the cube face or 3D slice of interest
- * \param usage  one of LP_TEX_USAGE_READ/WRITE_ALL/READ_WRITE
- */
-void *
-llvmpipe_get_texture_image(struct llvmpipe_resource *lpr,
-                           unsigned face_slice, unsigned level,
-                           enum lp_texture_usage usage)
-{
-   struct llvmpipe_texture_image *target_img;
-   void *target_data;
-   unsigned target_offset;
-   unsigned *target_off_ptr;
-
-   assert(usage == LP_TEX_USAGE_READ ||
-          usage == LP_TEX_USAGE_READ_WRITE ||
-          usage == LP_TEX_USAGE_WRITE_ALL);
-
-   if (lpr->dt) {
-      assert(lpr->linear_img.data);
-   }
-
-   target_img = &lpr->linear_img;
-   target_off_ptr = lpr->mip_offsets;
-   target_data = target_img->data;
-
-   if (!target_data) {
-      /* allocate memory for the target image now */
-      alloc_image_data(lpr);
-      target_data = target_img->data;
-   }
-
-   target_offset = target_off_ptr[level];
-
-   if (face_slice > 0) {
-      target_offset += face_slice * tex_image_face_size(lpr, level);
-   }
-
-   if (target_data) {
-      target_data = (uint8_t *) target_data + target_offset;
-   }
-
-   return target_data;
-}
-
-
-/**
- * Return pointer to start of a texture image (1D, 2D, 3D, CUBE).
- * This is typically used when we're about to sample from a texture.
- */
-void *
-llvmpipe_get_texture_image_all(struct llvmpipe_resource *lpr,
-                               unsigned level,
-                               enum lp_texture_usage usage)
-{
-   const int slices = lpr->num_slices_faces[level];
-   int slice;
-   void *map = NULL;
-
-   assert(slices > 0);
-
-   for (slice = slices - 1; slice >= 0; slice--) {
-      map = llvmpipe_get_texture_image(lpr, slice, level, usage);
-   }
-
-   return map;
-}
-
-
-/**
- * Get pointer to a linear image (not the tile!) at tile (x,y).
- * \return pointer to start of image/face (not the tile)
- */
-ubyte *
-llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpr,
-                                 unsigned face_slice, unsigned level,
-                                 enum lp_texture_usage usage,
-                                 unsigned x, unsigned y)
-{
-   struct llvmpipe_texture_image *linear_img = &lpr->linear_img;
-   uint8_t *linear_image;
-
-   assert(llvmpipe_resource_is_texture(&lpr->base));
-   assert(x % TILE_SIZE == 0);
-   assert(y % TILE_SIZE == 0);
-
-   if (!linear_img->data) {
-      /* allocate memory for the linear image now */
-      /* XXX should probably not do that here? */
-      alloc_image_data(lpr);
-   }
-   assert(linear_img->data);
-
-   /* compute address of the slice/face of the image that contains the tile */
-   linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level);
-
-   return linear_image;
+   return (ubyte *) lpr->tex_data + offset;
 }
 
 
@@ -893,21 +756,25 @@ unsigned
 llvmpipe_resource_size(const struct pipe_resource *resource)
 {
    const struct llvmpipe_resource *lpr = llvmpipe_resource_const(resource);
-   unsigned lvl, size = 0;
+   unsigned size = 0;
 
    if (llvmpipe_resource_is_texture(resource)) {
-      for (lvl = 0; lvl <= lpr->base.last_level; lvl++) {
-         if (lpr->linear_img.data)
-            size += tex_image_size(lpr, lvl);
-      }
+      /* Note this will always return 0 for displaytarget resources */
+      size = lpr->total_alloc_size;
    }
    else {
       size = resource->width0;
    }
-
    return size;
 }
 
+static void
+llvmpipe_memory_barrier(struct pipe_context *pipe,
+                       unsigned flags)
+{
+   /* this may be an overly large hammer for this nut. */
+   llvmpipe_finish(pipe, "barrier");
+}
 
 #ifdef DEBUG
 void
@@ -947,6 +814,7 @@ llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
 #endif
 
    screen->resource_create = llvmpipe_resource_create;
+/*   screen->resource_create_front = llvmpipe_resource_create_front; */
    screen->resource_destroy = llvmpipe_resource_destroy;
    screen->resource_from_handle = llvmpipe_resource_from_handle;
    screen->resource_get_handle = llvmpipe_resource_get_handle;
@@ -961,5 +829,8 @@ llvmpipe_init_context_resource_funcs(struct pipe_context *pipe)
    pipe->transfer_unmap = llvmpipe_transfer_unmap;
 
    pipe->transfer_flush_region = u_default_transfer_flush_region;
-   pipe->transfer_inline_write = u_default_transfer_inline_write;
+   pipe->buffer_subdata = u_default_buffer_subdata;
+   pipe->texture_subdata = u_default_texture_subdata;
+
+   pipe->memory_barrier = llvmpipe_memory_barrier;
 }