i915_resource_texture.c revision 84645fa61390475e6efb080685e0dec059622a39
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 "pipe/p_state.h"
34#include "pipe/p_context.h"
35#include "pipe/p_defines.h"
36#include "util/u_inlines.h"
37#include "util/u_format.h"
38#include "util/u_math.h"
39#include "util/u_memory.h"
40#include "util/u_rect.h"
41
42#include "i915_context.h"
43#include "i915_resource.h"
44#include "i915_screen.h"
45#include "i915_winsys.h"
46#include "i915_debug.h"
47
48
49#define DEBUG_TEXTURES 0
50
51/*
52 * Helper function and arrays
53 */
54
55
56/**
57 * Initial offset for Cube map.
58 */
59static const int initial_offsets[6][2] = {
60   [PIPE_TEX_FACE_POS_X] = {0, 0},
61   [PIPE_TEX_FACE_POS_Y] = {1, 0},
62   [PIPE_TEX_FACE_POS_Z] = {1, 1},
63   [PIPE_TEX_FACE_NEG_X] = {0, 2},
64   [PIPE_TEX_FACE_NEG_Y] = {1, 2},
65   [PIPE_TEX_FACE_NEG_Z] = {1, 3},
66};
67
68/**
69 * Step offsets for Cube map.
70 */
71static const int step_offsets[6][2] = {
72   [PIPE_TEX_FACE_POS_X] = { 0, 2},
73   [PIPE_TEX_FACE_POS_Y] = {-1, 2},
74   [PIPE_TEX_FACE_POS_Z] = {-1, 1},
75   [PIPE_TEX_FACE_NEG_X] = { 0, 2},
76   [PIPE_TEX_FACE_NEG_Y] = {-1, 2},
77   [PIPE_TEX_FACE_NEG_Z] = {-1, 1},
78};
79
80/**
81 * For compressed level 2
82 */
83static const int bottom_offsets[6] = {
84   [PIPE_TEX_FACE_POS_X] = 16 + 0 * 8,
85   [PIPE_TEX_FACE_POS_Y] = 16 + 1 * 8,
86   [PIPE_TEX_FACE_POS_Z] = 16 + 2 * 8,
87   [PIPE_TEX_FACE_NEG_X] = 16 + 3 * 8,
88   [PIPE_TEX_FACE_NEG_Y] = 16 + 4 * 8,
89   [PIPE_TEX_FACE_NEG_Z] = 16 + 5 * 8,
90};
91
92static INLINE unsigned
93align_nblocksx(enum pipe_format format, unsigned width, unsigned align_to)
94{
95   return align(util_format_get_nblocksx(format, width), align_to);
96}
97
98static INLINE unsigned
99align_nblocksy(enum pipe_format format, unsigned width, unsigned align_to)
100{
101   return align(util_format_get_nblocksy(format, width), align_to);
102}
103
104static INLINE unsigned
105get_pot_stride(enum pipe_format format, unsigned width)
106{
107   return util_next_power_of_two(util_format_get_stride(format, width));
108}
109
110static INLINE const char*
111get_tiling_string(enum i915_winsys_buffer_tile tile)
112{
113   switch(tile) {
114   case I915_TILE_NONE:
115      return "none";
116   case I915_TILE_X:
117      return "x";
118   case I915_TILE_Y:
119      return "y";
120   default:
121      assert(FALSE);
122      return "?";
123   }
124}
125
126
127/*
128 * More advanced helper funcs
129 */
130
131
132static void
133i915_texture_set_level_info(struct i915_texture *tex,
134                            unsigned level, unsigned nr_images)
135{
136   assert(level < Elements(tex->nr_images));
137   assert(nr_images);
138   assert(!tex->image_offset[level]);
139
140   tex->nr_images[level] = nr_images;
141   tex->image_offset[level] = MALLOC(nr_images * sizeof(struct offset_pair));
142   tex->image_offset[level][0].nblocksx = 0;
143   tex->image_offset[level][0].nblocksy = 0;
144}
145
146INLINE unsigned i915_texture_offset(struct i915_texture *tex,
147                                    unsigned level, unsigned layer)
148{
149   unsigned x, y;
150   x = tex->image_offset[level][layer].nblocksx
151      * util_format_get_blocksize(tex->b.b.format);
152   y = tex->image_offset[level][layer].nblocksy;
153
154   return y * tex->stride + x;
155}
156
157static void
158i915_texture_set_image_offset(struct i915_texture *tex,
159                              unsigned level, unsigned img,
160                              unsigned nblocksx, unsigned nblocksy)
161{
162   /* for the first image and level make sure offset is zero */
163   assert(!(img == 0 && level == 0) || (nblocksx == 0 && nblocksy == 0));
164   assert(img < tex->nr_images[level]);
165
166   tex->image_offset[level][img].nblocksx = nblocksx;
167   tex->image_offset[level][img].nblocksy = nblocksy;
168
169#if DEBUG_TEXTURES
170   debug_printf("%s: %p level %u, img %u (%u, %u)\n", __FUNCTION__,
171                tex, level, img, x, y);
172#endif
173}
174
175static enum i915_winsys_buffer_tile
176i915_texture_tiling(struct i915_screen *is, struct i915_texture *tex)
177{
178   if (!is->debug.tiling)
179      return I915_TILE_NONE;
180
181   if (tex->b.b.target == PIPE_TEXTURE_1D)
182      return I915_TILE_NONE;
183
184   if (util_format_is_s3tc(tex->b.b.format))
185      return I915_TILE_X;
186
187   if (is->debug.use_blitter)
188      return I915_TILE_X;
189   else
190      return I915_TILE_Y;
191}
192
193
194/*
195 * Shared layout functions
196 */
197
198
199/**
200 * Special case to deal with scanout textures.
201 */
202static boolean
203i9x5_scanout_layout(struct i915_texture *tex)
204{
205   struct pipe_resource *pt = &tex->b.b;
206
207   if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
208      return FALSE;
209
210   i915_texture_set_level_info(tex, 0, 1);
211   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
212
213   if (pt->width0 >= 240) {
214      tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64);
215      tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
216      tex->tiling = I915_TILE_X;
217   /* special case for cursors */
218   } else if (pt->width0 == 64 && pt->height0 == 64) {
219      tex->stride = get_pot_stride(pt->format, pt->width0);
220      tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
221   } else {
222      return FALSE;
223   }
224
225#if DEBUG_TEXTURE
226   debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
227      pt->width0, pt->height0, util_format_get_blocksize(pt->format),
228      tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
229#endif
230
231   return TRUE;
232}
233
234/**
235 * Special case to deal with shared textures.
236 */
237static boolean
238i9x5_display_target_layout(struct i915_texture *tex)
239{
240   struct pipe_resource *pt = &tex->b.b;
241
242   if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
243      return FALSE;
244
245   /* fallback to normal textures for small textures */
246   if (pt->width0 < 240)
247      return FALSE;
248
249   i915_texture_set_level_info(tex, 0, 1);
250   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
251
252   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64);
253   tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
254   tex->tiling = I915_TILE_X;
255
256#if DEBUG_TEXTURE
257   debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
258      pt->width0, pt->height0, util_format_get_blocksize(pt->format),
259      tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
260#endif
261
262   return TRUE;
263}
264
265/**
266 * Helper function for special layouts
267 */
268static boolean
269i9x5_special_layout(struct i915_texture *tex)
270{
271   struct pipe_resource *pt = &tex->b.b;
272
273   /* Scanouts needs special care */
274   if (pt->bind & PIPE_BIND_SCANOUT)
275      if (i9x5_scanout_layout(tex))
276         return TRUE;
277
278   /* Shared buffers needs to be compatible with X servers
279    *
280    * XXX: need a better name than shared for this if it is to be part
281    * of core gallium, and probably move the flag to resource.flags,
282    * rather than bindings.
283    */
284   if (pt->bind & (PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET))
285      if (i9x5_display_target_layout(tex))
286         return TRUE;
287
288   return FALSE;
289}
290
291/**
292 * Cube layout used on i915 and for non-compressed textures on i945.
293 */
294static void
295i9x5_texture_layout_cube(struct i915_texture *tex)
296{
297   struct pipe_resource *pt = &tex->b.b;
298   const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
299   unsigned level;
300   unsigned face;
301
302   assert(pt->width0 == pt->height0); /* cubemap images are square */
303
304   /* double pitch for cube layouts */
305   tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
306   tex->total_nblocksy = nblocks * 4;
307
308   for (level = 0; level <= pt->last_level; level++)
309      i915_texture_set_level_info(tex, level, 6);
310
311   for (face = 0; face < 6; face++) {
312      unsigned x = initial_offsets[face][0] * nblocks;
313      unsigned y = initial_offsets[face][1] * nblocks;
314      unsigned d = nblocks;
315
316      for (level = 0; level <= pt->last_level; level++) {
317         i915_texture_set_image_offset(tex, level, face, x, y);
318         d >>= 1;
319         x += step_offsets[face][0] * d;
320         y += step_offsets[face][1] * d;
321      }
322   }
323}
324
325
326/*
327 * i915 layout functions
328 */
329
330
331static void
332i915_texture_layout_2d(struct i915_texture *tex)
333{
334   struct pipe_resource *pt = &tex->b.b;
335   unsigned level;
336   unsigned width = pt->width0;
337   unsigned height = pt->height0;
338   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
339   unsigned align_y = 2;
340
341   if (util_format_is_s3tc(pt->format))
342      align_y = 1;
343
344   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
345   tex->total_nblocksy = 0;
346
347   for (level = 0; level <= pt->last_level; level++) {
348      i915_texture_set_level_info(tex, level, 1);
349      i915_texture_set_image_offset(tex, level, 0, 0, tex->total_nblocksy);
350
351      tex->total_nblocksy += nblocksy;
352
353      width = u_minify(width, 1);
354      height = u_minify(height, 1);
355      nblocksy = align_nblocksy(pt->format, height, align_y);
356   }
357}
358
359static void
360i915_texture_layout_3d(struct i915_texture *tex)
361{
362   struct pipe_resource *pt = &tex->b.b;
363   unsigned level;
364
365   unsigned width = pt->width0;
366   unsigned height = pt->height0;
367   unsigned depth = pt->depth0;
368   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
369   unsigned stack_nblocksy = 0;
370
371   /* Calculate the size of a single slice.
372    */
373   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
374
375   /* XXX: hardware expects/requires 9 levels at minimum.
376    */
377   for (level = 0; level <= MAX2(8, pt->last_level); level++) {
378      i915_texture_set_level_info(tex, level, depth);
379
380      stack_nblocksy += MAX2(2, nblocksy);
381
382      width = u_minify(width, 1);
383      height = u_minify(height, 1);
384      nblocksy = util_format_get_nblocksy(pt->format, height);
385   }
386
387   /* Fixup depth image_offsets:
388    */
389   for (level = 0; level <= pt->last_level; level++) {
390      unsigned i;
391      for (i = 0; i < depth; i++)
392         i915_texture_set_image_offset(tex, level, i, 0, i * stack_nblocksy);
393
394      depth = u_minify(depth, 1);
395   }
396
397   /* Multiply slice size by texture depth for total size.  It's
398    * remarkable how wasteful of memory the i915 texture layouts
399    * are.  They are largely fixed in the i945.
400    */
401   tex->total_nblocksy = stack_nblocksy * pt->depth0;
402}
403
404static boolean
405i915_texture_layout(struct i915_texture * tex)
406{
407   switch (tex->b.b.target) {
408   case PIPE_TEXTURE_1D:
409   case PIPE_TEXTURE_2D:
410   case PIPE_TEXTURE_RECT:
411      if (!i9x5_special_layout(tex))
412         i915_texture_layout_2d(tex);
413      break;
414   case PIPE_TEXTURE_3D:
415      i915_texture_layout_3d(tex);
416      break;
417   case PIPE_TEXTURE_CUBE:
418      i9x5_texture_layout_cube(tex);
419      break;
420   default:
421      assert(0);
422      return FALSE;
423   }
424
425   return TRUE;
426}
427
428
429/*
430 * i945 layout functions
431 */
432
433
434static void
435i945_texture_layout_2d(struct i915_texture *tex)
436{
437   struct pipe_resource *pt = &tex->b.b;
438   int align_x = 4, align_y = 2;
439   unsigned level;
440   unsigned x = 0;
441   unsigned y = 0;
442   unsigned width = pt->width0;
443   unsigned height = pt->height0;
444   unsigned nblocksx = util_format_get_nblocksx(pt->format, pt->width0);
445   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
446
447   if (util_format_is_s3tc(pt->format)) {
448      align_x = 1;
449      align_y = 1;
450   }
451
452   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
453
454   /* May need to adjust pitch to accomodate the placement of
455    * the 2nd mipmap level.  This occurs when the alignment
456    * constraints of mipmap placement push the right edge of the
457    * 2nd mipmap level out past the width of its parent.
458    */
459   if (pt->last_level > 0) {
460      unsigned mip1_nblocksx =
461         align_nblocksx(pt->format, u_minify(pt->width0, 1), align_x) +
462         util_format_get_nblocksx(pt->format, u_minify(pt->width0, 2));
463
464      if (mip1_nblocksx > nblocksx)
465         tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format);
466   }
467
468   /* Pitch must be a whole number of dwords
469    */
470   tex->stride = align(tex->stride, 64);
471   tex->total_nblocksy = 0;
472
473   for (level = 0; level <= pt->last_level; level++) {
474      i915_texture_set_level_info(tex, level, 1);
475      i915_texture_set_image_offset(tex, level, 0, x, y);
476
477      /* Because the images are packed better, the final offset
478       * might not be the maximal one:
479       */
480      tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
481
482      /* Layout_below: step right after second mipmap level.
483       */
484      if (level == 1) {
485         x += nblocksx;
486      } else {
487         y += nblocksy;
488      }
489
490      width  = u_minify(width, 1);
491      height = u_minify(height, 1);
492      nblocksx = align_nblocksx(pt->format, width, align_x);
493      nblocksy = align_nblocksy(pt->format, height, align_y);
494   }
495}
496
497static void
498i945_texture_layout_3d(struct i915_texture *tex)
499{
500   struct pipe_resource *pt = &tex->b.b;
501   unsigned width = pt->width0;
502   unsigned height = pt->height0;
503   unsigned depth = pt->depth0;
504   unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
505   unsigned pack_x_pitch, pack_x_nr;
506   unsigned pack_y_pitch;
507   unsigned level;
508
509   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
510   tex->total_nblocksy = 0;
511
512   pack_y_pitch = MAX2(nblocksy, 2);
513   pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format);
514   pack_x_nr = 1;
515
516   for (level = 0; level <= pt->last_level; level++) {
517      int x = 0;
518      int y = 0;
519      unsigned q, j;
520
521      i915_texture_set_level_info(tex, level, depth);
522
523      for (q = 0; q < depth;) {
524         for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
525            i915_texture_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
526            x += pack_x_pitch;
527         }
528
529         x = 0;
530         y += pack_y_pitch;
531      }
532
533      tex->total_nblocksy += y;
534
535      if (pack_x_pitch > 4) {
536         pack_x_pitch >>= 1;
537         pack_x_nr <<= 1;
538         assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride);
539      }
540
541      if (pack_y_pitch > 2) {
542         pack_y_pitch >>= 1;
543      }
544
545      width = u_minify(width, 1);
546      height = u_minify(height, 1);
547      depth = u_minify(depth, 1);
548      nblocksy = util_format_get_nblocksy(pt->format, height);
549   }
550}
551
552static void
553i945_texture_layout_cube(struct i915_texture *tex)
554{
555   struct pipe_resource *pt = &tex->b.b;
556   const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
557   const unsigned dim = pt->width0;
558   unsigned level;
559   unsigned face;
560
561   assert(pt->width0 == pt->height0); /* cubemap images are square */
562   assert(util_next_power_of_two(pt->width0) == pt->width0); /* npot only */
563   assert(util_format_is_s3tc(pt->format)); /* compressed only */
564
565   /*
566    * Depending on the size of the largest images, pitch can be
567    * determined either by the old-style packing of cubemap faces,
568    * or the final row of 4x4, 2x2 and 1x1 faces below this.
569    *
570    * 64  * 2 / 4 = 32
571    * 14 * 2 = 28
572    */
573   if (pt->width0 >= 64)
574      tex->stride = nblocks * 2 * util_format_get_blocksize(pt->format);
575   else
576      tex->stride = 14 * 2 * util_format_get_blocksize(pt->format);
577
578   /*
579    * Something similary apply for height as well.
580    */
581   if (pt->width0 >= 4)
582      tex->total_nblocksy = nblocks * 4 + 1;
583   else
584      tex->total_nblocksy = 1;
585
586   /* Set all the levels to effectively occupy the whole rectangular region */
587   for (level = 0; level <= pt->last_level; level++)
588      i915_texture_set_level_info(tex, level, 6);
589
590   for (face = 0; face < 6; face++) {
591      /* all calculations in pixels */
592      unsigned total_height = tex->total_nblocksy * 4;
593      unsigned x = initial_offsets[face][0] * dim;
594      unsigned y = initial_offsets[face][1] * dim;
595      unsigned d = dim;
596
597      if (dim == 4 && face >= 4) {
598         x = (face - 4) * 8;
599         y = tex->total_nblocksy * 4 - 4; /* 4 = 1 block */
600      } else if (dim < 4 && (face > 0)) {
601         x = face * 8;
602         y = total_height - 4;
603      }
604
605      for (level = 0; level <= pt->last_level; level++) {
606         i915_texture_set_image_offset(tex, level, face,
607                                       util_format_get_nblocksx(pt->format, x),
608                                       util_format_get_nblocksy(pt->format, y));
609
610         d >>= 1;
611
612         switch (d) {
613         case 4:
614            switch (face) {
615            case PIPE_TEX_FACE_POS_X:
616            case PIPE_TEX_FACE_NEG_X:
617               x += step_offsets[face][0] * d;
618               y += step_offsets[face][1] * d;
619               break;
620            case PIPE_TEX_FACE_POS_Y:
621            case PIPE_TEX_FACE_NEG_Y:
622               y += 12;
623               x -= 8;
624               break;
625            case PIPE_TEX_FACE_POS_Z:
626            case PIPE_TEX_FACE_NEG_Z:
627               y = total_height - 4;
628               x = (face - 4) * 8;
629               break;
630            }
631            break;
632         case 2:
633            y = total_height - 4;
634            x = bottom_offsets[face];
635            break;
636         case 1:
637            x += 48;
638            break;
639         default:
640            x += step_offsets[face][0] * d;
641            y += step_offsets[face][1] * d;
642            break;
643         }
644      }
645   }
646}
647
648static boolean
649i945_texture_layout(struct i915_texture * tex)
650{
651   switch (tex->b.b.target) {
652   case PIPE_TEXTURE_1D:
653   case PIPE_TEXTURE_2D:
654   case PIPE_TEXTURE_RECT:
655      if (!i9x5_special_layout(tex))
656         i945_texture_layout_2d(tex);
657      break;
658   case PIPE_TEXTURE_3D:
659      i945_texture_layout_3d(tex);
660      break;
661   case PIPE_TEXTURE_CUBE:
662      if (!util_format_is_s3tc(tex->b.b.format))
663         i9x5_texture_layout_cube(tex);
664      else
665         i945_texture_layout_cube(tex);
666      break;
667   default:
668      assert(0);
669      return FALSE;
670   }
671
672   return TRUE;
673}
674
675
676
677/*
678 * Screen texture functions
679 */
680
681
682
683static boolean
684i915_texture_get_handle(struct pipe_screen * screen,
685                        struct pipe_resource *texture,
686                        struct winsys_handle *whandle)
687{
688   struct i915_screen *is = i915_screen(screen);
689   struct i915_texture *tex = i915_texture(texture);
690   struct i915_winsys *iws = is->iws;
691
692   return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride);
693}
694
695
696static void
697i915_texture_destroy(struct pipe_screen *screen,
698                     struct pipe_resource *pt)
699{
700   struct i915_texture *tex = i915_texture(pt);
701   struct i915_winsys *iws = i915_screen(screen)->iws;
702   uint i;
703
704   if (tex->buffer)
705      iws->buffer_destroy(iws, tex->buffer);
706
707   for (i = 0; i < Elements(tex->image_offset); i++)
708      if (tex->image_offset[i])
709         FREE(tex->image_offset[i]);
710
711   FREE(tex);
712}
713
714static struct pipe_transfer *
715i915_texture_get_transfer(struct pipe_context *pipe,
716                          struct pipe_resource *resource,
717                          unsigned level,
718                          unsigned usage,
719                          const struct pipe_box *box)
720{
721   struct i915_context *i915 = i915_context(pipe);
722   struct i915_texture *tex = i915_texture(resource);
723   struct i915_transfer *transfer = util_slab_alloc(&i915->texture_transfer_pool);
724   boolean use_staging_texture = FALSE;
725
726   if (transfer == NULL)
727      return NULL;
728
729   transfer->b.resource = resource;
730   transfer->b.level = level;
731   transfer->b.usage = usage;
732   transfer->b.box = *box;
733   transfer->b.stride = tex->stride;
734   transfer->staging_texture = NULL;
735   /* XXX: handle depth textures everyhwere*/
736   transfer->b.layer_stride = 0;
737   transfer->b.data = NULL;
738
739   /* if we use staging transfers, only support textures we can render to,
740    * because we need that for u_blitter */
741   if (i915->blitter &&
742       util_blitter_is_copy_supported(i915->blitter, resource, resource,
743				      PIPE_MASK_RGBAZS) &&
744       (usage & PIPE_TRANSFER_WRITE) &&
745       !(usage & (PIPE_TRANSFER_READ | PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED)))
746      use_staging_texture = TRUE;
747
748   use_staging_texture = FALSE;
749
750   if (use_staging_texture) {
751      /*
752       * Allocate the untiled staging texture.
753       * If the alloc fails, transfer->staging_texture is NULL and we fallback to a map()
754       */
755      transfer->staging_texture = i915_texture_create(pipe->screen, resource, TRUE);
756   }
757
758   return (struct pipe_transfer*)transfer;
759}
760
761static void
762i915_transfer_destroy(struct pipe_context *pipe,
763                      struct pipe_transfer *transfer)
764{
765   struct i915_context *i915 = i915_context(pipe);
766   struct i915_transfer *itransfer = (struct i915_transfer*)transfer;
767
768   if ((itransfer->staging_texture) &&
769       (transfer->usage & PIPE_TRANSFER_WRITE)) {
770      struct pipe_box sbox;
771
772      u_box_origin_2d(itransfer->b.box.width, itransfer->b.box.height, &sbox);
773      pipe->resource_copy_region(pipe, itransfer->b.resource, itransfer->b.level,
774                                   itransfer->b.box.x, itransfer->b.box.y, itransfer->b.box.z,
775                                   itransfer->staging_texture,
776                                   0, &sbox);
777      pipe->flush(pipe, NULL);
778      pipe_resource_reference(&itransfer->staging_texture, NULL);
779   }
780
781   util_slab_free(&i915->texture_transfer_pool, itransfer);
782}
783
784static void *
785i915_texture_transfer_map(struct pipe_context *pipe,
786                          struct pipe_transfer *transfer)
787{
788   struct i915_transfer *itransfer = (struct i915_transfer*)transfer;
789   struct pipe_resource *resource = itransfer->b.resource;
790   struct i915_texture *tex = NULL;
791   struct i915_winsys *iws = i915_screen(pipe->screen)->iws;
792   struct pipe_box *box = &itransfer->b.box;
793   enum pipe_format format = resource->format;
794   unsigned offset;
795   char *map;
796
797   if (resource->target != PIPE_TEXTURE_3D &&
798       resource->target != PIPE_TEXTURE_CUBE)
799      assert(box->z == 0);
800
801   if (itransfer->staging_texture) {
802      tex = i915_texture(itransfer->staging_texture);
803   } else {
804      /* TODO this is a sledgehammer */
805      tex = i915_texture(resource);
806      pipe->flush(pipe, NULL);
807   }
808
809   offset = i915_texture_offset(tex, itransfer->b.level, box->z);
810
811   map = iws->buffer_map(iws, tex->buffer,
812                         (itransfer->b.usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE);
813   if (map == NULL) {
814      return NULL;
815   }
816
817   return map + offset +
818      box->y / util_format_get_blockheight(format) * itransfer->b.stride +
819      box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
820}
821
822static void
823i915_texture_transfer_unmap(struct pipe_context *pipe,
824			    struct pipe_transfer *transfer)
825{
826   struct i915_transfer *itransfer = (struct i915_transfer*)transfer;
827   struct i915_texture *tex = i915_texture(itransfer->b.resource);
828   struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws;
829
830   if (itransfer->staging_texture)
831      tex = i915_texture(itransfer->staging_texture);
832
833   iws->buffer_unmap(iws, tex->buffer);
834}
835
836static void i915_transfer_inline_write( struct pipe_context *pipe,
837                                 struct pipe_resource *resource,
838                                 unsigned level,
839                                 unsigned usage,
840                                 const struct pipe_box *box,
841                                 const void *data,
842                                 unsigned stride,
843                                 unsigned layer_stride)
844{
845   struct pipe_transfer *transfer = NULL;
846   struct i915_transfer *itransfer = NULL;
847   const uint8_t *src_data = data;
848   unsigned i;
849
850   transfer = pipe->get_transfer(pipe,
851                                 resource,
852                                 level,
853                                 usage,
854                                 box );
855   if (transfer == NULL)
856      goto out;
857
858   itransfer = (struct i915_transfer*)transfer;
859
860   if (itransfer->staging_texture) {
861      struct i915_texture *tex = i915_texture(itransfer->staging_texture);
862      enum pipe_format format = tex->b.b.format;
863      struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws;
864      size_t offset;
865      size_t size;
866
867      offset = i915_texture_offset(tex, transfer->level, transfer->box.z);
868
869      for (i = 0; i < box->depth; i++) {
870         if (!tex->b.b.last_level &&
871                     tex->b.b.width0 == transfer->box.width) {
872             unsigned nby = util_format_get_nblocksy(format, transfer->box.y);
873             assert(!offset);
874             assert(!transfer->box.x);
875             assert(tex->stride == transfer->stride);
876
877             offset += tex->stride * nby;
878             size = util_format_get_2d_size(format, transfer->stride,
879                             transfer->box.height);
880             iws->buffer_write(iws, tex->buffer, offset, size, transfer->data);
881
882         } else {
883             unsigned nby = util_format_get_nblocksy(format, transfer->box.y);
884             int i;
885             offset += util_format_get_stride(format, transfer->box.x);
886             size = transfer->stride;
887
888             for (i = 0; i < nby; i++) {
889                     iws->buffer_write(iws, tex->buffer, offset, size, transfer->data);
890                     offset += tex->stride;
891             }
892         }
893         offset += layer_stride;
894      }
895   } else {
896      uint8_t *map = pipe_transfer_map(pipe, &itransfer->b);
897      if (map == NULL)
898         goto nomap;
899
900      for (i = 0; i < box->depth; i++) {
901         util_copy_rect(map,
902                        resource->format,
903                        itransfer->b.stride, /* bytes */
904                        0, 0,
905                        box->width,
906                        box->height,
907                        src_data,
908                        stride,       /* bytes */
909                        0, 0);
910         map += itransfer->b.layer_stride;
911         src_data += layer_stride;
912      }
913nomap:
914      if (map)
915         pipe_transfer_unmap(pipe, &itransfer->b);
916   }
917
918out:
919   if (itransfer)
920      pipe_transfer_destroy(pipe, &itransfer->b);
921}
922
923
924
925struct u_resource_vtbl i915_texture_vtbl =
926{
927   i915_texture_get_handle,	      /* get_handle */
928   i915_texture_destroy,	      /* resource_destroy */
929   i915_texture_get_transfer,	      /* get_transfer */
930   i915_transfer_destroy,	      /* transfer_destroy */
931   i915_texture_transfer_map,	      /* transfer_map */
932   u_default_transfer_flush_region,   /* transfer_flush_region */
933   i915_texture_transfer_unmap,	      /* transfer_unmap */
934   i915_transfer_inline_write         /* transfer_inline_write */
935};
936
937
938
939
940struct pipe_resource *
941i915_texture_create(struct pipe_screen *screen,
942                    const struct pipe_resource *template,
943                    boolean force_untiled)
944{
945   struct i915_screen *is = i915_screen(screen);
946   struct i915_winsys *iws = is->iws;
947   struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
948   unsigned buf_usage = 0;
949
950   if (!tex)
951      return NULL;
952
953   tex->b.b = *template;
954   tex->b.vtbl = &i915_texture_vtbl;
955   pipe_reference_init(&tex->b.b.reference, 1);
956   tex->b.b.screen = screen;
957
958   if ( (force_untiled) || (template->usage == PIPE_USAGE_STREAM) )
959      tex->tiling = I915_TILE_NONE;
960   else
961      tex->tiling = i915_texture_tiling(is, tex);
962
963   if (is->is_i945) {
964      if (!i945_texture_layout(tex))
965         goto fail;
966   } else {
967      if (!i915_texture_layout(tex))
968         goto fail;
969   }
970
971   /* for scanouts and cursors, cursors arn't scanouts */
972
973   /* XXX: use a custom flag for cursors, don't rely on magically
974    * guessing that this is Xorg asking for a cursor
975    */
976   if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64)
977      buf_usage = I915_NEW_SCANOUT;
978   else
979      buf_usage = I915_NEW_TEXTURE;
980
981   tex->buffer = iws->buffer_create_tiled(iws, &tex->stride, tex->total_nblocksy,
982                                             &tex->tiling, buf_usage);
983   if (!tex->buffer)
984      goto fail;
985
986   I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__,
987            tex, tex->stride,
988            tex->stride / util_format_get_blocksize(tex->b.b.format),
989            tex->total_nblocksy, get_tiling_string(tex->tiling));
990
991   return &tex->b.b;
992
993fail:
994   FREE(tex);
995   return NULL;
996}
997
998struct pipe_resource *
999i915_texture_from_handle(struct pipe_screen * screen,
1000			  const struct pipe_resource *template,
1001			  struct winsys_handle *whandle)
1002{
1003   struct i915_screen *is = i915_screen(screen);
1004   struct i915_texture *tex;
1005   struct i915_winsys *iws = is->iws;
1006   struct i915_winsys_buffer *buffer;
1007   unsigned stride;
1008   enum i915_winsys_buffer_tile tiling;
1009
1010   assert(screen);
1011
1012   buffer = iws->buffer_from_handle(iws, whandle, &tiling, &stride);
1013
1014   /* Only supports one type */
1015   if ((template->target != PIPE_TEXTURE_2D &&
1016       template->target != PIPE_TEXTURE_RECT) ||
1017       template->last_level != 0 ||
1018       template->depth0 != 1) {
1019      return NULL;
1020   }
1021
1022   tex = CALLOC_STRUCT(i915_texture);
1023   if (!tex)
1024      return NULL;
1025
1026   tex->b.b = *template;
1027   tex->b.vtbl = &i915_texture_vtbl;
1028   pipe_reference_init(&tex->b.b.reference, 1);
1029   tex->b.b.screen = screen;
1030
1031   tex->stride = stride;
1032   tex->tiling = tiling;
1033   tex->total_nblocksy = align_nblocksy(tex->b.b.format, tex->b.b.height0, 8);
1034
1035   i915_texture_set_level_info(tex, 0, 1);
1036   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
1037
1038   tex->buffer = buffer;
1039
1040   I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__,
1041            tex, tex->stride,
1042            tex->stride / util_format_get_blocksize(tex->b.b.format),
1043            tex->total_nblocksy, get_tiling_string(tex->tiling));
1044
1045   return &tex->b.b;
1046}
1047
1048