lp_texture.c revision 43b85af56efbe6eb06f4e62d23e9f6f583c5ec2e
1/**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27 /*
28  * Authors:
29  *   Keith Whitwell <keith@tungstengraphics.com>
30  *   Michel Dänzer <michel@tungstengraphics.com>
31  */
32
33#include <stdio.h>
34
35#include "pipe/p_context.h"
36#include "pipe/p_defines.h"
37
38#include "util/u_inlines.h"
39#include "util/u_format.h"
40#include "util/u_math.h"
41#include "util/u_memory.h"
42#include "util/u_transfer.h"
43
44#include "lp_context.h"
45#include "lp_flush.h"
46#include "lp_screen.h"
47#include "lp_tile_image.h"
48#include "lp_texture.h"
49#include "lp_setup.h"
50
51#include "state_tracker/sw_winsys.h"
52
53
54static INLINE boolean
55resource_is_texture(const struct pipe_resource *resource)
56{
57   switch (resource->target) {
58   case PIPE_BUFFER:
59      return FALSE;
60   case PIPE_TEXTURE_1D:
61   case PIPE_TEXTURE_2D:
62   case PIPE_TEXTURE_3D:
63   case PIPE_TEXTURE_CUBE:
64      return TRUE;
65   default:
66      assert(0);
67      return FALSE;
68   }
69}
70
71
72
73/**
74 * Allocate storage for llvmpipe_texture::layout array.
75 * The number of elements is width_in_tiles * height_in_tiles.
76 */
77static enum lp_texture_layout *
78alloc_layout_array(unsigned num_slices, unsigned width, unsigned height)
79{
80   const unsigned tx = align(width, TILE_SIZE) / TILE_SIZE;
81   const unsigned ty = align(height, TILE_SIZE) / TILE_SIZE;
82
83   assert(num_slices * tx * ty > 0);
84   assert(LP_TEX_LAYOUT_NONE == 0); /* calloc'ing LP_TEX_LAYOUT_NONE here */
85
86   return (enum lp_texture_layout *)
87      CALLOC(num_slices * tx * ty, sizeof(enum lp_texture_layout));
88}
89
90
91
92/**
93 * Conventional allocation path for non-display textures:
94 * Just compute row strides here.  Storage is allocated on demand later.
95 */
96static boolean
97llvmpipe_texture_layout(struct llvmpipe_screen *screen,
98                        struct llvmpipe_resource *lpr)
99{
100   struct pipe_resource *pt = &lpr->base;
101   unsigned level;
102   unsigned width = pt->width0;
103   unsigned height = pt->height0;
104   unsigned depth = pt->depth0;
105
106   assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
107   assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
108
109   for (level = 0; level <= pt->last_level; level++) {
110      const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
111      const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
112      unsigned nblocksx, num_slices;
113
114      if (lpr->base.target == PIPE_TEXTURE_CUBE)
115         num_slices = 6;
116      else if (lpr->base.target == PIPE_TEXTURE_3D)
117         num_slices = depth;
118      else
119         num_slices = 1;
120
121      /* Allocate storage for whole quads. This is particularly important
122       * for depth surfaces, which are currently stored in a swizzled format.
123       */
124      nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
125
126      lpr->row_stride[level] =
127         align(nblocksx * util_format_get_blocksize(pt->format), 16);
128
129      lpr->img_stride[level] = lpr->row_stride[level] * align(height, TILE_SIZE);
130
131      lpr->tiles_per_row[level] = width_t;
132      lpr->tiles_per_image[level] = width_t * height_t;
133      lpr->num_slices_faces[level] = num_slices;
134      lpr->layout[level] = alloc_layout_array(num_slices, width, height);
135
136      width = u_minify(width, 1);
137      height = u_minify(height, 1);
138      depth = u_minify(depth, 1);
139   }
140
141   return TRUE;
142}
143
144
145
146static boolean
147llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
148                              struct llvmpipe_resource *lpr)
149{
150   struct sw_winsys *winsys = screen->winsys;
151
152   /* Round up the surface size to a multiple of the tile size to
153    * avoid tile clipping.
154    */
155   const unsigned width = align(lpr->base.width0, TILE_SIZE);
156   const unsigned height = align(lpr->base.height0, TILE_SIZE);
157   const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
158   const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
159
160   lpr->tiles_per_row[0] = width_t;
161   lpr->tiles_per_image[0] = width_t * height_t;
162   lpr->num_slices_faces[0] = 1;
163   lpr->img_stride[0] = 0;
164
165   lpr->layout[0] = alloc_layout_array(1, width, height);
166   //lpr->layout[0][0] = LP_TEX_LAYOUT_LINEAR;
167
168   lpr->dt = winsys->displaytarget_create(winsys,
169                                          lpr->base.bind,
170                                          lpr->base.format,
171                                          width, height,
172                                          16,
173                                          &lpr->row_stride[0] );
174
175   return lpr->dt != NULL;
176}
177
178
179static struct pipe_resource *
180llvmpipe_resource_create(struct pipe_screen *_screen,
181                         const struct pipe_resource *templat)
182{
183   static unsigned id_counter = 0;
184   struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
185   struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
186   if (!lpr)
187      return NULL;
188
189   lpr->base = *templat;
190   pipe_reference_init(&lpr->base.reference, 1);
191   lpr->base.screen = &screen->base;
192
193   assert(lpr->base.bind);
194
195   if (resource_is_texture(&lpr->base)) {
196      if (lpr->base.bind & PIPE_BIND_DISPLAY_TARGET) {
197         /* displayable surface */
198         if (!llvmpipe_displaytarget_layout(screen, lpr))
199            goto fail;
200         assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
201      }
202      else {
203         /* texture map */
204         if (!llvmpipe_texture_layout(screen, lpr))
205            goto fail;
206         assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
207      }
208      assert(lpr->layout[0]);
209   }
210   else {
211      /* other data (vertex buffer, const buffer, etc) */
212      const enum pipe_format format = templat->format;
213      const uint w = templat->width0 / util_format_get_blockheight(format);
214      const uint h = templat->height0 / util_format_get_blockwidth(format);
215      const uint d = templat->depth0;
216      const uint bpp = util_format_get_blocksize(format);
217      const uint bytes = w * h * d * bpp;
218      lpr->data = align_malloc(bytes, 16);
219      if (!lpr->data)
220         goto fail;
221   }
222
223   lpr->id = id_counter++;
224
225   return &lpr->base;
226
227 fail:
228   FREE(lpr);
229   return NULL;
230}
231
232
233static void
234llvmpipe_resource_destroy(struct pipe_screen *pscreen,
235			  struct pipe_resource *pt)
236{
237   struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
238   struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
239
240   if (lpr->dt) {
241      /* display target */
242      struct sw_winsys *winsys = screen->winsys;
243      winsys->displaytarget_destroy(winsys, lpr->dt);
244   }
245   else if (resource_is_texture(pt)) {
246      /* regular texture */
247      uint level;
248
249      /* free linear image data */
250      for (level = 0; level < Elements(lpr->linear); level++) {
251         if (lpr->linear[level].data) {
252            align_free(lpr->linear[level].data);
253            lpr->linear[level].data = NULL;
254         }
255      }
256
257      /* free tiled image data */
258      for (level = 0; level < Elements(lpr->tiled); level++) {
259         if (lpr->tiled[level].data) {
260            align_free(lpr->tiled[level].data);
261            lpr->tiled[level].data = NULL;
262         }
263      }
264
265      /* free layout flag arrays */
266      for (level = 0; level < Elements(lpr->tiled); level++) {
267         FREE(lpr->layout[level]);
268         lpr->layout[level] = NULL;
269      }
270   }
271   else if (!lpr->userBuffer) {
272      assert(lpr->data);
273      align_free(lpr->data);
274   }
275
276   FREE(lpr);
277}
278
279
280/**
281 * Map a resource for read/write.
282 */
283void *
284llvmpipe_resource_map(struct pipe_resource *resource,
285		      unsigned face,
286		      unsigned level,
287		      unsigned zslice,
288                      enum lp_texture_usage tex_usage,
289                      enum lp_texture_layout layout)
290{
291   struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
292   uint8_t *map;
293
294   assert(face < 6);
295   assert(level < LP_MAX_TEXTURE_LEVELS);
296
297   assert(tex_usage == LP_TEX_USAGE_READ ||
298          tex_usage == LP_TEX_USAGE_READ_WRITE ||
299          tex_usage == LP_TEX_USAGE_WRITE_ALL);
300
301   assert(layout == LP_TEX_LAYOUT_NONE ||
302          layout == LP_TEX_LAYOUT_TILED ||
303          layout == LP_TEX_LAYOUT_LINEAR);
304
305   if (lpr->dt) {
306      /* display target */
307      struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen);
308      struct sw_winsys *winsys = screen->winsys;
309      unsigned dt_usage;
310      uint8_t *map2;
311
312      if (tex_usage == LP_TEX_USAGE_READ) {
313         dt_usage = PIPE_TRANSFER_READ;
314      }
315      else {
316         dt_usage = PIPE_TRANSFER_READ_WRITE;
317      }
318
319      assert(face == 0);
320      assert(level == 0);
321      assert(zslice == 0);
322
323      /* FIXME: keep map count? */
324      map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage);
325
326      /* install this linear image in texture data structure */
327      lpr->linear[level].data = map;
328
329      /* make sure tiled data gets converted to linear data */
330      map2 = llvmpipe_get_texture_image(lpr, 0, 0, tex_usage, layout);
331      if (layout == LP_TEX_LAYOUT_LINEAR)
332         assert(map == map2);
333
334      return map2;
335   }
336   else if (resource_is_texture(resource)) {
337      /* regular texture */
338      if (resource->target != PIPE_TEXTURE_CUBE) {
339         assert(face == 0);
340      }
341      if (resource->target != PIPE_TEXTURE_3D) {
342         assert(zslice == 0);
343      }
344
345      map = llvmpipe_get_texture_image(lpr, face + zslice, level,
346                                       tex_usage, layout);
347      assert(map);
348      return map;
349   }
350   else {
351      return lpr->data;
352   }
353}
354
355
356/**
357 * Unmap a resource.
358 */
359void
360llvmpipe_resource_unmap(struct pipe_resource *resource,
361                       unsigned face,
362                       unsigned level,
363                       unsigned zslice)
364{
365   struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
366
367   if (lpr->dt) {
368      /* display target */
369      struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen);
370      struct sw_winsys *winsys = lp_screen->winsys;
371
372      assert(face == 0);
373      assert(level == 0);
374      assert(zslice == 0);
375
376      /* make sure linear image is up to date */
377      (void) llvmpipe_get_texture_image(lpr, face + zslice, level,
378                                        LP_TEX_USAGE_READ,
379                                        LP_TEX_LAYOUT_LINEAR);
380
381      winsys->displaytarget_unmap(winsys, lpr->dt);
382   }
383}
384
385
386void *
387llvmpipe_resource_data(struct pipe_resource *resource)
388{
389   struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
390
391   assert(!resource_is_texture(resource));
392
393   return lpr->data;
394}
395
396
397static struct pipe_resource *
398llvmpipe_resource_from_handle(struct pipe_screen *screen,
399			      const struct pipe_resource *template,
400			      struct winsys_handle *whandle)
401{
402   struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
403   struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
404   if (!lpr)
405      return NULL;
406
407   lpr->base = *template;
408   pipe_reference_init(&lpr->base.reference, 1);
409   lpr->base.screen = screen;
410
411   lpr->dt = winsys->displaytarget_from_handle(winsys,
412                                               template,
413                                               whandle,
414                                               &lpr->row_stride[0]);
415   if (!lpr->dt)
416      goto fail;
417
418   return &lpr->base;
419
420 fail:
421   FREE(lpr);
422   return NULL;
423}
424
425
426static boolean
427llvmpipe_resource_get_handle(struct pipe_screen *screen,
428                            struct pipe_resource *pt,
429                            struct winsys_handle *whandle)
430{
431   struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
432   struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
433
434   assert(lpr->dt);
435   if (!lpr->dt)
436      return FALSE;
437
438   return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle);
439}
440
441
442static struct pipe_surface *
443llvmpipe_get_tex_surface(struct pipe_screen *screen,
444                         struct pipe_resource *pt,
445                         unsigned face, unsigned level, unsigned zslice,
446                         enum lp_texture_usage usage)
447{
448   struct pipe_surface *ps;
449
450   assert(level <= pt->last_level);
451
452   ps = CALLOC_STRUCT(pipe_surface);
453   if (ps) {
454      pipe_reference_init(&ps->reference, 1);
455      pipe_resource_reference(&ps->texture, pt);
456      ps->format = pt->format;
457      ps->width = u_minify(pt->width0, level);
458      ps->height = u_minify(pt->height0, level);
459      ps->usage = usage;
460
461      ps->face = face;
462      ps->level = level;
463      ps->zslice = zslice;
464   }
465   return ps;
466}
467
468
469static void
470llvmpipe_tex_surface_destroy(struct pipe_surface *surf)
471{
472   /* Effectively do the texture_update work here - if texture images
473    * needed post-processing to put them into hardware layout, this is
474    * where it would happen.  For llvmpipe, nothing to do.
475    */
476   assert(surf->texture);
477   pipe_resource_reference(&surf->texture, NULL);
478   FREE(surf);
479}
480
481
482static struct pipe_transfer *
483llvmpipe_get_transfer(struct pipe_context *pipe,
484		      struct pipe_resource *resource,
485		      struct pipe_subresource sr,
486		      unsigned usage,
487		      const struct pipe_box *box)
488{
489   struct llvmpipe_resource *lprex = llvmpipe_resource(resource);
490   struct llvmpipe_transfer *lpr;
491
492   assert(resource);
493   assert(sr.level <= resource->last_level);
494
495   /*
496    * Transfers, like other pipe operations, must happen in order, so flush the
497    * context if necessary.
498    */
499   if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
500      boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
501      boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
502      if (!llvmpipe_flush_resource(pipe, resource,
503                                   sr.face, sr.level,
504                                   0, /* flush_flags */
505                                   read_only,
506                                   TRUE, /* cpu_access */
507                                   do_not_block)) {
508         /*
509          * It would have blocked, but state tracker requested no to.
510          */
511         assert(do_not_block);
512         return NULL;
513      }
514   }
515
516   lpr = CALLOC_STRUCT(llvmpipe_transfer);
517   if (lpr) {
518      struct pipe_transfer *pt = &lpr->base;
519      pipe_resource_reference(&pt->resource, resource);
520      pt->box = *box;
521      pt->sr = sr;
522      pt->stride = lprex->row_stride[sr.level];
523      pt->usage = usage;
524
525      return pt;
526   }
527   return NULL;
528}
529
530
531static void
532llvmpipe_transfer_destroy(struct pipe_context *pipe,
533                              struct pipe_transfer *transfer)
534{
535   /* Effectively do the texture_update work here - if texture images
536    * needed post-processing to put them into hardware layout, this is
537    * where it would happen.  For llvmpipe, nothing to do.
538    */
539   assert (transfer->resource);
540   pipe_resource_reference(&transfer->resource, NULL);
541   FREE(transfer);
542}
543
544
545static void *
546llvmpipe_transfer_map( struct pipe_context *pipe,
547                       struct pipe_transfer *transfer )
548{
549   struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
550   ubyte *map;
551   struct llvmpipe_resource *lpr;
552   enum pipe_format format;
553   enum lp_texture_usage tex_usage;
554   const char *mode;
555
556   assert(transfer->sr.face < 6);
557   assert(transfer->sr.level < LP_MAX_TEXTURE_LEVELS);
558
559   /*
560   printf("tex_transfer_map(%d, %d  %d x %d of %d x %d,  usage %d )\n",
561          transfer->x, transfer->y, transfer->width, transfer->height,
562          transfer->texture->width0,
563          transfer->texture->height0,
564          transfer->usage);
565   */
566
567   if (transfer->usage == PIPE_TRANSFER_READ) {
568      tex_usage = LP_TEX_USAGE_READ;
569      mode = "read";
570   }
571   else {
572      tex_usage = LP_TEX_USAGE_READ_WRITE;
573      mode = "read/write";
574   }
575
576   if (0) {
577      struct llvmpipe_resource *lpr = llvmpipe_resource(transfer->resource);
578      printf("transfer map tex %u  mode %s\n", lpr->id, mode);
579   }
580
581
582   assert(transfer->resource);
583   lpr = llvmpipe_resource(transfer->resource);
584   format = lpr->base.format;
585
586   map = llvmpipe_resource_map(transfer->resource,
587			       transfer->sr.face,
588			       transfer->sr.level,
589			       transfer->box.z,
590                               tex_usage, LP_TEX_LAYOUT_LINEAR);
591
592
593   /* May want to do different things here depending on read/write nature
594    * of the map:
595    */
596   if (transfer->usage & PIPE_TRANSFER_WRITE) {
597      /* Do something to notify sharing contexts of a texture change.
598       */
599      screen->timestamp++;
600   }
601
602   map +=
603      transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
604      transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
605
606   return map;
607}
608
609
610static void
611llvmpipe_transfer_unmap(struct pipe_context *pipe,
612                        struct pipe_transfer *transfer)
613{
614   assert(transfer->resource);
615
616   llvmpipe_resource_unmap(transfer->resource,
617			   transfer->sr.face,
618			   transfer->sr.level,
619			   transfer->box.z);
620}
621
622static unsigned int
623llvmpipe_is_resource_referenced( struct pipe_context *pipe,
624				struct pipe_resource *presource,
625				unsigned face, unsigned level)
626{
627   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
628
629   if (presource->target == PIPE_BUFFER)
630      return PIPE_UNREFERENCED;
631
632   return lp_setup_is_resource_referenced(llvmpipe->setup, presource);
633}
634
635
636
637/**
638 * Create buffer which wraps user-space data.
639 */
640static struct pipe_resource *
641llvmpipe_user_buffer_create(struct pipe_screen *screen,
642                            void *ptr,
643                            unsigned bytes,
644			    unsigned bind_flags)
645{
646   struct llvmpipe_resource *buffer;
647
648   buffer = CALLOC_STRUCT(llvmpipe_resource);
649   if(!buffer)
650      return NULL;
651
652   pipe_reference_init(&buffer->base.reference, 1);
653   buffer->base.screen = screen;
654   buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
655   buffer->base.bind = bind_flags;
656   buffer->base.usage = PIPE_USAGE_IMMUTABLE;
657   buffer->base.flags = 0;
658   buffer->base.width0 = bytes;
659   buffer->base.height0 = 1;
660   buffer->base.depth0 = 1;
661   buffer->userBuffer = TRUE;
662   buffer->data = ptr;
663
664   return &buffer->base;
665}
666
667
668/**
669 * Compute size (in bytes) need to store a texture image / mipmap level,
670 * for just one cube face or one 3D texture slice
671 */
672static unsigned
673tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level,
674                    enum lp_texture_layout layout)
675{
676   const unsigned width = u_minify(lpr->base.width0, level);
677   const unsigned height = u_minify(lpr->base.height0, level);
678
679   assert(layout == LP_TEX_LAYOUT_TILED ||
680          layout == LP_TEX_LAYOUT_LINEAR);
681
682   if (layout == LP_TEX_LAYOUT_TILED) {
683      /* for tiled layout, force a 32bpp format */
684      const enum pipe_format format = PIPE_FORMAT_B8G8R8A8_UNORM;
685      const unsigned block_size = util_format_get_blocksize(format);
686      const unsigned nblocksy =
687         util_format_get_nblocksy(format, align(height, TILE_SIZE));
688      const unsigned nblocksx =
689         util_format_get_nblocksx(format, align(width, TILE_SIZE));
690      const unsigned buffer_size = block_size * nblocksy * nblocksx;
691      return buffer_size;
692   }
693   else {
694      const enum pipe_format format = lpr->base.format;
695      const unsigned nblocksy =
696         util_format_get_nblocksy(format, align(height, TILE_SIZE));
697      const unsigned buffer_size = nblocksy * lpr->row_stride[level];
698      return buffer_size;
699   }
700}
701
702
703/**
704 * Compute size (in bytes) need to store a texture image / mipmap level,
705 * including all cube faces or 3D image slices
706 */
707static unsigned
708tex_image_size(const struct llvmpipe_resource *lpr, unsigned level,
709               enum lp_texture_layout layout)
710{
711   const unsigned buf_size = tex_image_face_size(lpr, level, layout);
712   return buf_size * lpr->num_slices_faces[level];
713}
714
715
716/**
717 * This function encapsulates some complicated logic for determining
718 * how to convert a tile of image data from linear layout to tiled
719 * layout, or vice versa.
720 * \param cur_layout  the current tile layout
721 * \param target_layout  the desired tile layout
722 * \param usage  how the tile will be accessed (R/W vs. read-only, etc)
723 * \param new_layout_return  returns the new layout mode
724 * \param convert_return  returns TRUE if image conversion is needed
725 */
726static void
727layout_logic(enum lp_texture_layout cur_layout,
728             enum lp_texture_layout target_layout,
729             enum lp_texture_usage usage,
730             enum lp_texture_layout *new_layout_return,
731             boolean *convert)
732{
733   enum lp_texture_layout other_layout, new_layout;
734
735   *convert = FALSE;
736
737   new_layout = 99; /* debug check */
738
739   if (target_layout == LP_TEX_LAYOUT_LINEAR) {
740      other_layout = LP_TEX_LAYOUT_TILED;
741   }
742   else {
743      assert(target_layout == LP_TEX_LAYOUT_TILED);
744      other_layout = LP_TEX_LAYOUT_LINEAR;
745   }
746
747   new_layout = target_layout;  /* may get changed below */
748
749   if (cur_layout == LP_TEX_LAYOUT_BOTH) {
750      if (usage == LP_TEX_USAGE_READ) {
751         new_layout = LP_TEX_LAYOUT_BOTH;
752      }
753   }
754   else if (cur_layout == other_layout) {
755      if (usage != LP_TEX_USAGE_WRITE_ALL) {
756         /* need to convert tiled data to linear or vice versa */
757         *convert = TRUE;
758
759         if (usage == LP_TEX_USAGE_READ)
760            new_layout = LP_TEX_LAYOUT_BOTH;
761      }
762   }
763   else {
764      assert(cur_layout == LP_TEX_LAYOUT_NONE ||
765             cur_layout == target_layout);
766   }
767
768   assert(new_layout == LP_TEX_LAYOUT_BOTH ||
769          new_layout == target_layout);
770
771   *new_layout_return = new_layout;
772}
773
774
775/**
776 * Return pointer to a 2D texture image/face/slice.
777 * No tiled/linear conversion is done.
778 */
779ubyte *
780llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpr,
781                                   unsigned face_slice, unsigned level,
782                                   enum lp_texture_layout layout)
783{
784   struct llvmpipe_texture_image *img;
785   unsigned offset;
786
787   if (layout == LP_TEX_LAYOUT_LINEAR) {
788      img = &lpr->linear[level];
789   }
790   else {
791      assert (layout == LP_TEX_LAYOUT_TILED);
792      img = &lpr->tiled[level];
793   }
794
795   if (face_slice > 0)
796      offset = face_slice * tex_image_face_size(lpr, level, layout);
797   else
798      offset = 0;
799
800   return (ubyte *) img->data + offset;
801}
802
803
804static INLINE enum lp_texture_layout
805llvmpipe_get_texture_tile_layout(const struct llvmpipe_resource *lpr,
806                                 unsigned face_slice, unsigned level,
807                                 unsigned x, unsigned y)
808{
809   uint i;
810   assert(resource_is_texture(&lpr->base));
811   assert(x < lpr->tiles_per_row[level]);
812   i = face_slice * lpr->tiles_per_image[level]
813      + y * lpr->tiles_per_row[level] + x;
814   return lpr->layout[level][i];
815}
816
817
818static INLINE void
819llvmpipe_set_texture_tile_layout(struct llvmpipe_resource *lpr,
820                                 unsigned face_slice, unsigned level,
821                                 unsigned x, unsigned y,
822                                 enum lp_texture_layout layout)
823{
824   uint i;
825   assert(resource_is_texture(&lpr->base));
826   assert(x < lpr->tiles_per_row[level]);
827   i = face_slice * lpr->tiles_per_image[level]
828      + y * lpr->tiles_per_row[level] + x;
829   lpr->layout[level][i] = layout;
830}
831
832
833/**
834 * Set the layout mode for all tiles in a particular image.
835 */
836static INLINE void
837llvmpipe_set_texture_image_layout(struct llvmpipe_resource *lpr,
838                                  unsigned face_slice, unsigned level,
839                                  unsigned width_t, unsigned height_t,
840                                  enum lp_texture_layout layout)
841{
842   const unsigned start = face_slice * lpr->tiles_per_image[level];
843   unsigned i;
844
845   for (i = 0; i < width_t * height_t; i++) {
846      lpr->layout[level][start + i] = layout;
847   }
848}
849
850
851/**
852 * Allocate storage for a linear or tile texture image (all cube
853 * faces and all 3D slices.
854 */
855static void
856alloc_image_data(struct llvmpipe_resource *lpr, unsigned level,
857                 enum lp_texture_layout layout)
858{
859   if (lpr->dt)
860      assert(level == 0);
861
862   if (layout == LP_TEX_LAYOUT_TILED) {
863      /* tiled data is stored in regular memory */
864      uint buffer_size = tex_image_size(lpr, level, layout);
865      lpr->tiled[level].data = align_malloc(buffer_size, 16);
866   }
867   else {
868      assert(layout == LP_TEX_LAYOUT_LINEAR);
869      if (lpr->dt) {
870         /* we get the linear memory from the winsys */
871         struct llvmpipe_screen *screen = llvmpipe_screen(lpr->base.screen);
872         struct sw_winsys *winsys = screen->winsys;
873
874         lpr->linear[0].data =
875            winsys->displaytarget_map(winsys, lpr->dt,
876                                      PIPE_TRANSFER_READ_WRITE);
877      }
878      else {
879         /* not a display target - allocate regular memory */
880         uint buffer_size = tex_image_size(lpr, level, LP_TEX_LAYOUT_LINEAR);
881         lpr->linear[level].data = align_malloc(buffer_size, 16);
882      }
883   }
884}
885
886
887
888/**
889 * Return pointer to texture image data (either linear or tiled layout)
890 * for a particular cube face or 3D texture slice.
891 *
892 * \param face_slice  the cube face or 3D slice of interest
893 * \param usage  one of LP_TEX_USAGE_READ/WRITE_ALL/READ_WRITE
894 * \param layout  either LP_TEX_LAYOUT_LINEAR or _TILED or _NONE
895 */
896void *
897llvmpipe_get_texture_image(struct llvmpipe_resource *lpr,
898                           unsigned face_slice, unsigned level,
899                           enum lp_texture_usage usage,
900                           enum lp_texture_layout layout)
901{
902   /*
903    * 'target' refers to the image which we're retrieving (either in
904    * tiled or linear layout).
905    * 'other' refers to the same image but in the other layout. (it may
906    *  or may not exist.
907    */
908   struct llvmpipe_texture_image *target_img;
909   struct llvmpipe_texture_image *other_img;
910   void *target_data;
911   void *other_data;
912   const unsigned width = u_minify(lpr->base.width0, level);
913   const unsigned height = u_minify(lpr->base.height0, level);
914   const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
915   const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
916   enum lp_texture_layout other_layout;
917   boolean only_allocate;
918
919   assert(layout == LP_TEX_LAYOUT_NONE ||
920          layout == LP_TEX_LAYOUT_TILED ||
921          layout == LP_TEX_LAYOUT_LINEAR);
922
923   assert(usage == LP_TEX_USAGE_READ ||
924          usage == LP_TEX_USAGE_READ_WRITE ||
925          usage == LP_TEX_USAGE_WRITE_ALL);
926
927   /* check for the special case of layout == LP_TEX_LAYOUT_NONE */
928   if (layout == LP_TEX_LAYOUT_NONE) {
929      only_allocate = TRUE;
930      layout = LP_TEX_LAYOUT_TILED;
931   }
932   else {
933      only_allocate = FALSE;
934   }
935
936   if (lpr->dt) {
937      assert(lpr->linear[level].data);
938   }
939
940   /* which is target?  which is other? */
941   if (layout == LP_TEX_LAYOUT_LINEAR) {
942      target_img = &lpr->linear[level];
943      other_img = &lpr->tiled[level];
944      other_layout = LP_TEX_LAYOUT_TILED;
945   }
946   else {
947      target_img = &lpr->tiled[level];
948      other_img = &lpr->linear[level];
949      other_layout = LP_TEX_LAYOUT_LINEAR;
950   }
951
952   target_data = target_img->data;
953   other_data = other_img->data;
954
955   if (!target_data) {
956      /* allocate memory for the target image now */
957      alloc_image_data(lpr, level, layout);
958      target_data = target_img->data;
959   }
960
961   if (face_slice > 0) {
962      unsigned target_offset, other_offset;
963
964      target_offset = face_slice * tex_image_face_size(lpr, level, layout);
965      other_offset = face_slice * tex_image_face_size(lpr, level, other_layout);
966      if (target_data) {
967         target_data = (uint8_t *) target_data + target_offset;
968      }
969      if (other_data) {
970         other_data = (uint8_t *) other_data + other_offset;
971      }
972   }
973
974   if (only_allocate) {
975      /* Just allocating tiled memory.  Don't initialize it from the
976       * linear data if it exists.
977       */
978      return target_data;
979   }
980
981   if (other_data) {
982      /* may need to convert other data to the requested layout */
983      enum lp_texture_layout new_layout;
984      unsigned x, y;
985
986      /* loop over all image tiles, doing layout conversion where needed */
987      for (y = 0; y < height_t; y++) {
988         for (x = 0; x < width_t; x++) {
989            enum lp_texture_layout cur_layout =
990               llvmpipe_get_texture_tile_layout(lpr, face_slice, level, x, y);
991            boolean convert;
992
993            layout_logic(cur_layout, layout, usage, &new_layout, &convert);
994
995            if (convert) {
996               if (layout == LP_TEX_LAYOUT_TILED) {
997                  lp_linear_to_tiled(other_data, target_data,
998                                     x * TILE_SIZE, y * TILE_SIZE,
999                                     TILE_SIZE, TILE_SIZE,
1000                                     lpr->base.format,
1001                                     lpr->row_stride[level],
1002                                     lpr->tiles_per_row[level]);
1003               }
1004               else {
1005                  lp_tiled_to_linear(other_data, target_data,
1006                                     x * TILE_SIZE, y * TILE_SIZE,
1007                                     TILE_SIZE, TILE_SIZE,
1008                                     lpr->base.format,
1009                                     lpr->row_stride[level],
1010                                     lpr->tiles_per_row[level]);
1011               }
1012            }
1013
1014            llvmpipe_set_texture_tile_layout(lpr, face_slice, level, x, y,
1015                                             new_layout);
1016         }
1017      }
1018   }
1019   else {
1020      /* no other data */
1021      llvmpipe_set_texture_image_layout(lpr, face_slice, level,
1022                                        width_t, height_t, layout);
1023   }
1024
1025   assert(target_data);
1026
1027   return target_data;
1028}
1029
1030
1031/**
1032 * Return pointer to start of a texture image (1D, 2D, 3D, CUBE).
1033 * All cube faces and 3D slices will be converted to the requested
1034 * layout if needed.
1035 * This is typically used when we're about to sample from a texture.
1036 */
1037void *
1038llvmpipe_get_texture_image_all(struct llvmpipe_resource *lpr,
1039                               unsigned level,
1040                               enum lp_texture_usage usage,
1041                               enum lp_texture_layout layout)
1042{
1043   const int slices = lpr->num_slices_faces[level];
1044   int slice;
1045   void *map = NULL;
1046
1047   assert(slices > 0);
1048
1049   for (slice = slices - 1; slice >= 0; slice--) {
1050      map = llvmpipe_get_texture_image(lpr, slice, level, usage, layout);
1051   }
1052
1053   return map;
1054}
1055
1056
1057/**
1058 * Get pointer to a linear image (not the tile!) where the tile at (x,y)
1059 * is known to be in linear layout.
1060 * Conversion from tiled to linear will be done if necessary.
1061 * \return pointer to start of image/face (not the tile)
1062 */
1063ubyte *
1064llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpr,
1065                                 unsigned face_slice, unsigned level,
1066                                 enum lp_texture_usage usage,
1067                                 unsigned x, unsigned y)
1068{
1069   struct llvmpipe_texture_image *linear_img = &lpr->linear[level];
1070   enum lp_texture_layout cur_layout, new_layout;
1071   const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
1072   boolean convert;
1073   uint8_t *tiled_image, *linear_image;
1074
1075   assert(resource_is_texture(&lpr->base));
1076   assert(x % TILE_SIZE == 0);
1077   assert(y % TILE_SIZE == 0);
1078
1079   if (!linear_img->data) {
1080      /* allocate memory for the linear image now */
1081      alloc_image_data(lpr, level, LP_TEX_LAYOUT_LINEAR);
1082   }
1083
1084   /* compute address of the slice/face of the image that contains the tile */
1085   tiled_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1086                                                    LP_TEX_LAYOUT_TILED);
1087   linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1088                                                     LP_TEX_LAYOUT_LINEAR);
1089
1090   /* get current tile layout and determine if data conversion is needed */
1091   cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty);
1092
1093   layout_logic(cur_layout, LP_TEX_LAYOUT_LINEAR, usage,
1094                &new_layout, &convert);
1095
1096   if (convert) {
1097      lp_tiled_to_linear(tiled_image, linear_image,
1098                         x, y, TILE_SIZE, TILE_SIZE, lpr->base.format,
1099                         lpr->row_stride[level],
1100                         lpr->tiles_per_row[level]);
1101   }
1102
1103   if (new_layout != cur_layout)
1104      llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout);
1105
1106   return linear_image;
1107}
1108
1109
1110/**
1111 * Get pointer to tiled data for rendering.
1112 * \return pointer to the tiled data at the given tile position
1113 */
1114ubyte *
1115llvmpipe_get_texture_tile(struct llvmpipe_resource *lpr,
1116                          unsigned face_slice, unsigned level,
1117                          enum lp_texture_usage usage,
1118                          unsigned x, unsigned y)
1119{
1120   struct llvmpipe_texture_image *tiled_img = &lpr->tiled[level];
1121   enum lp_texture_layout cur_layout, new_layout;
1122   const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
1123   boolean convert;
1124   uint8_t *tiled_image, *linear_image;
1125   unsigned tile_offset;
1126
1127   assert(x % TILE_SIZE == 0);
1128   assert(y % TILE_SIZE == 0);
1129
1130   if (!tiled_img->data) {
1131      /* allocate memory for the tiled image now */
1132      alloc_image_data(lpr, level, LP_TEX_LAYOUT_TILED);
1133   }
1134
1135   /* compute address of the slice/face of the image that contains the tile */
1136   tiled_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1137                                                    LP_TEX_LAYOUT_TILED);
1138   linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level,
1139                                                     LP_TEX_LAYOUT_LINEAR);
1140
1141   /* get current tile layout and see if we need to convert the data */
1142   cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty);
1143
1144   layout_logic(cur_layout, LP_TEX_LAYOUT_TILED, usage, &new_layout, &convert);
1145   if (convert) {
1146      lp_linear_to_tiled(linear_image, tiled_image,
1147                         x, y, TILE_SIZE, TILE_SIZE, lpr->base.format,
1148                         lpr->row_stride[level],
1149                         lpr->tiles_per_row[level]);
1150   }
1151
1152   if (new_layout != cur_layout)
1153      llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout);
1154
1155   /* compute, return address of the 64x64 tile */
1156   tile_offset = (ty * lpr->tiles_per_row[level] + tx)
1157         * TILE_SIZE * TILE_SIZE * 4;
1158
1159   return (ubyte *) tiled_image + tile_offset;
1160}
1161
1162
1163void
1164llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
1165{
1166   screen->resource_create = llvmpipe_resource_create;
1167   screen->resource_destroy = llvmpipe_resource_destroy;
1168   screen->resource_from_handle = llvmpipe_resource_from_handle;
1169   screen->resource_get_handle = llvmpipe_resource_get_handle;
1170   screen->user_buffer_create = llvmpipe_user_buffer_create;
1171
1172   screen->get_tex_surface = llvmpipe_get_tex_surface;
1173   screen->tex_surface_destroy = llvmpipe_tex_surface_destroy;
1174}
1175
1176
1177void
1178llvmpipe_init_context_resource_funcs(struct pipe_context *pipe)
1179{
1180   pipe->get_transfer = llvmpipe_get_transfer;
1181   pipe->transfer_destroy = llvmpipe_transfer_destroy;
1182   pipe->transfer_map = llvmpipe_transfer_map;
1183   pipe->transfer_unmap = llvmpipe_transfer_unmap;
1184   pipe->is_resource_referenced = llvmpipe_is_resource_referenced;
1185
1186   pipe->transfer_flush_region = u_default_transfer_flush_region;
1187   pipe->transfer_inline_write = u_default_transfer_inline_write;
1188}
1189