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