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