Merge remote branch 'origin/7.8'
[mesa.git] / src / gallium / drivers / cell / ppu / cell_texture.c
index ae4c61efb3bee91e072a545578a6de91ae13c442..d08334d892b7592d95a4d1a8c17c27ec9db81e11 100644 (file)
 
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
-#include "pipe/p_inlines.h"
-#include "pipe/internal/p_winsys_screen.h"
+#include "util/u_inlines.h"
+
+#include "util/u_format.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 
 #include "cell_context.h"
+#include "cell_screen.h"
 #include "cell_state.h"
-#include "cell_texture.h"
+#include "cell_resource.h"
 
+#include "state_tracker/sw_winsys.h"
 
 
-static void
-cell_texture_layout(struct cell_texture *ct)
+
+static boolean
+cell_resource_layout(struct pipe_screen *screen, 
+                    struct cell_resource *ct)
 {
-   struct pipe_texture *pt = &ct->base;
+   struct pipe_resource *pt = &ct->base;
    unsigned level;
-   unsigned width = pt->width[0];
-   unsigned height = pt->height[0];
-   unsigned depth = pt->depth[0];
+   unsigned width = pt->width0;
+   unsigned height = pt->height0;
+   unsigned depth = pt->depth0;
 
    ct->buffer_size = 0;
 
@@ -65,17 +70,11 @@ cell_texture_layout(struct cell_texture *ct)
       w_tile = align(width, TILE_SIZE);
       h_tile = align(height, TILE_SIZE);
 
-      pt->width[level] = width;
-      pt->height[level] = height;
-      pt->depth[level] = depth;
-      pt->nblocksx[level] = pf_get_nblocksx(&pt->block, w_tile);  
-      pt->nblocksy[level] = pf_get_nblocksy(&pt->block, h_tile);  
-
-      ct->stride[level] = pt->nblocksx[level] * pt->block.size;
+      ct->stride[level] = util_format_get_stride(pt->format, w_tile);
 
       ct->level_offset[level] = ct->buffer_size;
 
-      size = pt->nblocksx[level] * pt->nblocksy[level] * pt->block.size;
+      size = ct->stride[level] * util_format_get_nblocksy(pt->format, h_tile);
       if (pt->target == PIPE_TEXTURE_CUBE)
          size *= 6;
       else
@@ -83,18 +82,44 @@ cell_texture_layout(struct cell_texture *ct)
 
       ct->buffer_size += size;
 
-      width = minify(width);
-      height = minify(height);
-      depth = minify(depth);
+      width = u_minify(width, 1);
+      height = u_minify(height, 1);
+      depth = u_minify(depth, 1);
    }
+
+   ct->data = align_malloc(ct->buffer_size, 16);
+   return ct->data != NULL;
 }
 
 
-static struct pipe_texture *
-cell_texture_create(struct pipe_screen *screen,
-                    const struct pipe_texture *templat)
+/**
+ * Texture layout for simple color buffers.
+ */
+static boolean
+cell_displaytarget_layout(struct pipe_screen *screen,
+                          struct cell_resource * ct)
+{
+   struct sw_winsys *winsys = cell_screen(screen)->winsys;
+
+   /* Round up the surface size to a multiple of the tile size?
+    */
+   ct->dt = winsys->displaytarget_create(winsys,
+                                          ct->base.bind,
+                                          ct->base.format,
+                                          ct->base.width0, 
+                                          ct->base.height0,
+                                          16,
+                                          &ct->dt_stride );
+
+   return ct->dt != NULL;
+}
+
+static struct pipe_resource *
+cell_resource_create(struct pipe_screen *screen,
+                    const struct pipe_resource *templat)
 {
-   struct cell_texture *ct = CALLOC_STRUCT(cell_texture);
+   struct cell_resource *ct = CALLOC_STRUCT(cell_resource);
    if (!ct)
       return NULL;
 
@@ -102,31 +127,47 @@ cell_texture_create(struct pipe_screen *screen,
    pipe_reference_init(&ct->base.reference, 1);
    ct->base.screen = screen;
 
-   cell_texture_layout(ct);
+   /* Create both a displaytarget (linear) and regular texture
+    * (twiddled).  Convert twiddled->linear at flush_frontbuffer time.
+    */
+   if (ct->base.bind & (PIPE_BIND_DISPLAY_TARGET |
+                        PIPE_BIND_SCANOUT |
+                        PIPE_BIND_SHARED)) {
+      if (!cell_displaytarget_layout(screen, ct))
+         goto fail;
+   }
 
-   ct->buffer = screen->buffer_create(screen, 32, PIPE_BUFFER_USAGE_PIXEL,
-                                   ct->buffer_size);
+   if (!cell_resource_layout(screen, ct))
+      goto fail;
 
-   if (!ct->buffer) {
-      FREE(ct);
-      return NULL;
+   return &ct->base;
+
+fail:
+   if (ct->dt) {
+      struct sw_winsys *winsys = cell_screen(screen)->winsys;
+      winsys->displaytarget_destroy(winsys, ct->dt);
    }
 
-   return &ct->base;
+   FREE(ct);
+
+   return NULL;
 }
 
 
 static void
-cell_texture_destroy(struct pipe_texture *pt)
+cell_resource_destroy(struct pipe_resource *pt)
 {
-   struct cell_texture *ct = cell_texture(pt);
+   struct cell_screen *screen = cell_screen(pt->screen);
+   struct sw_winsys *winsys = screen->winsys;
+   struct cell_resource *ct = cell_resource(pt);
 
-   if (ct->mapped) {
-      pipe_buffer_unmap(ct->buffer->screen, ct->buffer);
-      ct->mapped = NULL;
+   if (ct->dt) {
+      /* display target */
+      winsys->displaytarget_destroy(winsys, ct->dt);
+   }
+   else if (!ct->userBuffer) {
+      align_free(ct->data);
    }
-
-   pipe_buffer_reference(&ct->buffer, NULL);
 
    FREE(ct);
 }
@@ -264,20 +305,20 @@ untwiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
 
 static struct pipe_surface *
 cell_get_tex_surface(struct pipe_screen *screen,
-                     struct pipe_texture *pt,
+                     struct pipe_resource *pt,
                      unsigned face, unsigned level, unsigned zslice,
                      unsigned usage)
 {
-   struct cell_texture *ct = cell_texture(pt);
+   struct cell_resource *ct = cell_resource(pt);
    struct pipe_surface *ps;
 
    ps = CALLOC_STRUCT(pipe_surface);
    if (ps) {
       pipe_reference_init(&ps->reference, 1);
-      pipe_texture_reference(&ps->texture, pt);
+      pipe_resource_reference(&ps->texture, pt);
       ps->format = pt->format;
-      ps->width = pt->width[level];
-      ps->height = pt->height[level];
+      ps->width = u_minify(pt->width0, level);
+      ps->height = u_minify(pt->height0, level);
       ps->offset = ct->level_offset[level];
       /* XXX may need to override usage flags (see sp_texture.c) */
       ps->usage = usage;
@@ -286,10 +327,12 @@ cell_get_tex_surface(struct pipe_screen *screen,
       ps->zslice = zslice;
 
       if (pt->target == PIPE_TEXTURE_CUBE) {
-         ps->offset += face * pt->nblocksy[level] * ct->stride[level];
+         unsigned h_tile = align(ps->height, TILE_SIZE);
+         ps->offset += face * util_format_get_nblocksy(ps->format, h_tile) * ct->stride[level];
       }
       else if (pt->target == PIPE_TEXTURE_3D) {
-         ps->offset += zslice * pt->nblocksy[level] * ct->stride[level];
+         unsigned h_tile = align(ps->height, TILE_SIZE);
+         ps->offset += zslice * util_format_get_nblocksy(ps->format, h_tile) * ct->stride[level];
       }
       else {
          assert(face == 0);
@@ -303,7 +346,7 @@ cell_get_tex_surface(struct pipe_screen *screen,
 static void 
 cell_tex_surface_destroy(struct pipe_surface *surf)
 {
-   pipe_texture_reference(&surf->texture, NULL);
+   pipe_resource_reference(&surf->texture, NULL);
    FREE(surf);
 }
 
@@ -314,48 +357,48 @@ cell_tex_surface_destroy(struct pipe_surface *surf)
  * back out for glGetTexImage).
  */
 static struct pipe_transfer *
-cell_get_tex_transfer(struct pipe_screen *screen,
-                      struct pipe_texture *texture,
-                      unsigned face, unsigned level, unsigned zslice,
-                      enum pipe_transfer_usage usage,
-                      unsigned x, unsigned y, unsigned w, unsigned h)
+cell_get_transfer(struct pipe_context *ctx,
+                 struct pipe_resource *resource,
+                 struct pipe_subresource sr,
+                 unsigned usage,
+                 const struct pipe_box *box)
 {
-   struct cell_texture *ct = cell_texture(texture);
+   struct cell_resource *ct = cell_resource(resource);
    struct cell_transfer *ctrans;
+   enum pipe_format *format = resource->format;
 
-   assert(texture);
-   assert(level <= texture->last_level);
+   assert(resource);
+   assert(level <= resource->last_level);
+
+   /* make sure the requested region is in the image bounds */
+   assert(box->x + box->width <= u_minify(resource->width0, sr.level));
+   assert(box->y + box->height <= u_minify(resource->height0, sr.level));
+   assert(box->z + box->depth <= u_minify(resource->depth0, sr.level));
 
    ctrans = CALLOC_STRUCT(cell_transfer);
    if (ctrans) {
       struct pipe_transfer *pt = &ctrans->base;
-      pipe_texture_reference(&pt->texture, texture);
-      pt->format = texture->format;
-      pt->block = texture->block;
-      pt->x = x;
-      pt->y = y;
-      pt->width = w;
-      pt->height = h;
-      pt->nblocksx = texture->nblocksx[level];
-      pt->nblocksy = texture->nblocksy[level];
-      pt->stride = ct->stride[level];
+      pipe_resource_reference(&pt->resource, resource);
+      pt->sr = sr;
       pt->usage = usage;
-      pt->face = face;
-      pt->level = level;
-      pt->zslice = zslice;
+      pt->box = *box;
+      pt->stride = ct->stride[sr.level];
 
-      ctrans->offset = ct->level_offset[level];
+      ctrans->offset = ct->level_offset[sr.level];
 
-      if (texture->target == PIPE_TEXTURE_CUBE) {
-         ctrans->offset += face * pt->nblocksy * pt->stride;
+      if (resource->target == PIPE_TEXTURE_CUBE) {
+         unsigned h_tile = align(u_minify(resource->height0, sr.level), TILE_SIZE);
+         ctrans->offset += sr.face * util_format_get_nblocksy(format, h_tile) * pt->stride;
       }
-      else if (texture->target == PIPE_TEXTURE_3D) {
-         ctrans->offset += zslice * pt->nblocksy * pt->stride;
+      else if (resource->target == PIPE_TEXTURE_3D) {
+         unsigned h_tile = align(u_minify(resource->height0, sr.level), TILE_SIZE);
+         ctrans->offset += box->z * util_format_get_nblocksy(format, h_tile) * pt->stride;
       }
       else {
-         assert(face == 0);
-         assert(zslice == 0);
+         assert(sr.face == 0);
+         assert(box->z == 0);
       }
+
       return pt;
    }
    return NULL;
@@ -363,15 +406,15 @@ cell_get_tex_transfer(struct pipe_screen *screen,
 
 
 static void 
-cell_tex_transfer_destroy(struct pipe_transfer *t)
+cell_transfer_destroy(struct pipe_context *ctx, struct pipe_transfer *t)
 {
    struct cell_transfer *transfer = cell_transfer(t);
    /* Effectively do the texture_update work here - if texture images
     * needed post-processing to put them into hardware layout, this is
     * where it would happen.  For cell, nothing to do.
     */
-   assert (transfer->base.texture);
-   pipe_texture_reference(&transfer->base.texture, NULL);
+   assert (transfer->base.resource);
+   pipe_resource_reference(&transfer->base.resource, NULL);
    FREE(transfer);
 }
 
@@ -380,48 +423,66 @@ cell_tex_transfer_destroy(struct pipe_transfer *t)
  * Return pointer to texture image data in linear layout.
  */
 static void *
-cell_transfer_map(struct pipe_screen *screen, struct pipe_transfer *transfer)
+cell_transfer_map(struct pipe_context *ctx, struct pipe_transfer *transfer)
 {
    struct cell_transfer *ctrans = cell_transfer(transfer);
-   struct pipe_texture *pt = transfer->texture;
-   struct cell_texture *ct = cell_texture(pt);
-   const uint level = ctrans->base.level;
-   const uint texWidth = pt->width[level];
-   const uint texHeight = pt->height[level];
-   const uint stride = ct->stride[level];
-   unsigned size;
+   struct pipe_resource *pt = transfer->resource;
+   struct cell_resource *ct = cell_resource(pt);
 
-   assert(transfer->texture);
+   assert(transfer->resource);
 
-   if (!ct->mapped) {
-      /* map now */
-      ct->mapped = pipe_buffer_map(screen, ct->buffer,
-                                   pipe_transfer_buffer_flags(transfer));
+   if (ct->mapped == NULL) {
+      ct->mapped = ct->data;
    }
 
-   /*
-    * Create a buffer of ordinary memory for the linear texture.
-    * This is the memory that the user will read/write.
+
+   /* Better test would be resource->is_linear
     */
-   size = pt->nblocksx[level] * pt->nblocksy[level] * pt->block.size;
-
-   ctrans->map = align_malloc(size, 16);
-   if (!ctrans->map)
-      return NULL; /* out of memory */
-
-   if (transfer->usage & PIPE_TRANSFER_READ) {
-      /* need to untwiddle the texture to make a linear version */
-      const uint bpp = pf_get_size(ct->base.format);
-      if (bpp == 4) {
-         const uint *src = (uint *) (ct->mapped + ctrans->offset);
-         uint *dst = ctrans->map;
-         untwiddle_image_uint(texWidth, texHeight, TILE_SIZE,
-                              dst, stride, src);
-      }
-      else {
-         // xxx fix
+   if (transfer->resource->target != PIPE_BUFFER) {
+      const uint level = ctrans->base.sr.level;
+      const uint texWidth = u_minify(pt->width0, level);
+      const uint texHeight = u_minify(pt->height0, level);
+      unsigned size;
+
+
+      /*
+       * Create a buffer of ordinary memory for the linear texture.
+       * This is the memory that the user will read/write.
+       */
+      size = (util_format_get_stride(pt->format, align(texWidth, TILE_SIZE)) *
+             util_format_get_nblocksy(pt->format, align(texHeight, TILE_SIZE)));
+
+      ctrans->map = align_malloc(size, 16);
+      if (!ctrans->map)
+        return NULL; /* out of memory */
+
+      if (transfer->usage & PIPE_TRANSFER_READ) {
+        /* Textures always stored twiddled, need to untwiddle the
+         * texture to make a linear version.
+         */
+        const uint bpp = util_format_get_blocksize(ct->base.format);
+        if (bpp == 4) {
+           const uint *src = (uint *) (ct->mapped + ctrans->offset);
+           uint *dst = ctrans->map;
+           untwiddle_image_uint(texWidth, texHeight, TILE_SIZE,
+                                dst, transfer->stride, src);
+        }
+        else {
+           // xxx fix
+        }
       }
    }
+   else {
+      unsigned stride = transfer->stride;
+      enum pipe_format format = pt->format;
+      unsigned blocksize = util_format_get_blocksize(format);
+
+      ctrans->map = (ct->mapped + 
+                    ctrans->offset +
+                    ctrans->base.box.y / util_format_get_blockheight(format) * stride +
+                    ctrans->base.box.x / util_format_get_blockwidth(format) * blocksize);
+   }
+
 
    return ctrans->map;
 }
@@ -433,55 +494,149 @@ cell_transfer_map(struct pipe_screen *screen, struct pipe_transfer *transfer)
  * to tiled data.
  */
 static void
-cell_transfer_unmap(struct pipe_screen *screen,
+cell_transfer_unmap(struct pipe_context *ctx,
                     struct pipe_transfer *transfer)
 {
    struct cell_transfer *ctrans = cell_transfer(transfer);
-   struct pipe_texture *pt = transfer->texture;
-   struct cell_texture *ct = cell_texture(pt);
-   const uint level = ctrans->base.level;
-   const uint texWidth = pt->width[level];
-   const uint texHeight = pt->height[level];
+   struct pipe_resource *pt = transfer->resource;
+   struct cell_resource *ct = cell_resource(pt);
+   const uint level = ctrans->base.sr.level;
+   const uint texWidth = u_minify(pt->width0, level);
+   const uint texHeight = u_minify(pt->height0, level);
    const uint stride = ct->stride[level];
 
    if (!ct->mapped) {
-      /* map now */
-      ct->mapped = pipe_buffer_map(screen, ct->buffer,
-                                   PIPE_BUFFER_USAGE_CPU_READ);
+      assert(0);
+      return;
    }
 
-   if (transfer->usage & PIPE_TRANSFER_WRITE) {
-      /* The user wrote new texture data into the mapped buffer.
-       * We need to convert the new linear data into the twiddled/tiled format.
-       */
-      const uint bpp = pf_get_size(ct->base.format);
-      if (bpp == 4) {
-         const uint *src = ctrans->map;
-         uint *dst = (uint *) (ct->mapped + ctrans->offset);
-         twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst, stride, src);
-      }
-      else {
-         // xxx fix
+   if (pt->target != PIPE_BUFFER) {
+      if (transfer->usage & PIPE_TRANSFER_WRITE) {
+        /* The user wrote new texture data into the mapped buffer.
+         * We need to convert the new linear data into the twiddled/tiled format.
+         */
+        const uint bpp = util_format_get_blocksize(ct->base.format);
+        if (bpp == 4) {
+           const uint *src = ctrans->map;
+           uint *dst = (uint *) (ct->mapped + ctrans->offset);
+           twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst, stride, src);
+        }
+        else {
+           // xxx fix
+        }
       }
+      
+      align_free(ctrans->map);
+   }
+   else {
+      /* nothing to do */
    }
 
-   align_free(ctrans->map);
    ctrans->map = NULL;
 }
 
 
+
+/* This used to be overriden by the co-state tracker, but really needs
+ * to be active with sw_winsys.
+ *
+ * Contrasting with llvmpipe and softpipe, this is the only place
+ * where we use the ct->dt display target in any real sense.
+ *
+ * Basically just untwiddle our local data into the linear
+ * displaytarget.
+ */
+static void
+cell_flush_frontbuffer(struct pipe_screen *_screen,
+                       struct pipe_surface *surface,
+                       void *context_private)
+{
+   struct cell_screen *screen = cell_screen(_screen);
+   struct sw_winsys *winsys = screen->winsys;
+   struct cell_resource *ct = cell_resource(surface->texture);
+
+   if (!ct->dt)
+      return;
+
+   /* Need to untwiddle from our internal representation here:
+    */
+   {
+      unsigned *map = winsys->displaytarget_map(winsys, ct->dt,
+                                                (PIPE_TRANSFER_READ |
+                                                 PIPE_TRANSFER_WRITE));
+      unsigned *src = (unsigned *)(ct->data + ct->level_offset[surface->level]);
+
+      untwiddle_image_uint(surface->width,
+                           surface->height,
+                           TILE_SIZE,
+                           map,
+                           ct->dt_stride,
+                           src);
+
+      winsys->displaytarget_unmap(winsys, ct->dt);
+   }
+
+   winsys->displaytarget_display(winsys, ct->dt, context_private);
+}
+
+
+
+/**
+ * Create buffer which wraps user-space data.
+ */
+static struct pipe_resource *
+cell_user_buffer_create(struct pipe_screen *screen,
+                            void *ptr,
+                            unsigned bytes,
+                           unsigned bind_flags)
+{
+   struct cell_resource *buffer;
+
+   buffer = CALLOC_STRUCT(cell_resource);
+   if(!buffer)
+      return NULL;
+
+   pipe_reference_init(&buffer->base.reference, 1);
+   buffer->base.screen = screen;
+   buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
+   buffer->base.bind = PIPE_BIND_TRANSFER_READ | bind_flags;
+   buffer->base.usage = PIPE_USAGE_IMMUTABLE;
+   buffer->base.flags = 0;
+   buffer->base.width0 = bytes;
+   buffer->base.height0 = 1;
+   buffer->base.depth0 = 1;
+   buffer->userBuffer = TRUE;
+   buffer->data = ptr;
+
+   return &buffer->base;
+}
+
+
+
+
 void
 cell_init_screen_texture_funcs(struct pipe_screen *screen)
 {
-   screen->texture_create = cell_texture_create;
-   screen->texture_destroy = cell_texture_destroy;
+   screen->resource_create = cell_resource_create;
+   screen->resource_destroy = cell_resource_destroy;
+   screen->resource_from_handle = cell_resource_from_handle;
+   screen->resource_get_handle = cell_resource_get_handle;
+   screen->user_buffer_create = cell_user_buffer_create;
 
    screen->get_tex_surface = cell_get_tex_surface;
    screen->tex_surface_destroy = cell_tex_surface_destroy;
 
-   screen->get_tex_transfer = cell_get_tex_transfer;
-   screen->tex_transfer_destroy = cell_tex_transfer_destroy;
+   screen->flush_frontbuffer = cell_flush_frontbuffer;
+}
+
+void
+cell_init_transfer_funcs(struct cell_context *cell)
+{
+   cell->pipe.get_transfer = cell_get_transfer;
+   cell->pipe.transfer_destroy = cell_transfer_destroy;
+   cell->pipe.transfer_map = cell_transfer_map;
+   cell->pipe.transfer_unmap = cell_transfer_unmap;
 
-   screen->transfer_map = cell_transfer_map;
-   screen->transfer_unmap = cell_transfer_unmap;
+   cell->pipe.transfer_flush_region = u_default_transfer_flush_region;
+   cell->pipe.transfer_inline_write = u_default_transfer_inline_write;
 }