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  */
57 static 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  */
66 static 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  */
75 static 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 
81 static inline unsigned
align_nblocksx(enum pipe_format format,unsigned width,unsigned align_to)82 align_nblocksx(enum pipe_format format, unsigned width, unsigned align_to)
83 {
84    return align(util_format_get_nblocksx(format, width), align_to);
85 }
86 
87 static inline unsigned
align_nblocksy(enum pipe_format format,unsigned width,unsigned align_to)88 align_nblocksy(enum pipe_format format, unsigned width, unsigned align_to)
89 {
90    return align(util_format_get_nblocksy(format, width), align_to);
91 }
92 
93 static inline unsigned
get_pot_stride(enum pipe_format format,unsigned width)94 get_pot_stride(enum pipe_format format, unsigned width)
95 {
96    return util_next_power_of_two(util_format_get_stride(format, width));
97 }
98 
99 static inline const char *
get_tiling_string(enum i915_winsys_buffer_tile tile)100 get_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 
119 static void
i915_texture_set_level_info(struct i915_texture * tex,unsigned level,unsigned nr_images)120 i915_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 
133 unsigned
i915_texture_offset(const struct i915_texture * tex,unsigned level,unsigned layer)134 i915_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 
145 static void
i915_texture_set_image_offset(struct i915_texture * tex,unsigned level,unsigned img,unsigned nblocksx,unsigned nblocksy)146 i915_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 
163 static enum i915_winsys_buffer_tile
i915_texture_tiling(struct i915_screen * is,struct i915_texture * tex)164 i915_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  */
188 static bool
i9x5_scanout_layout(struct i915_texture * tex)189 i9x5_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  */
225 static bool
i9x5_display_target_layout(struct i915_texture * tex)226 i9x5_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  */
257 static bool
i9x5_special_layout(struct i915_texture * tex)258 i9x5_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  */
324 static void
i9x5_texture_layout_cube(struct i915_texture * tex)325 i9x5_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 
360 static void
i915_texture_layout_2d(struct i915_texture * tex)361 i915_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 
388 static void
i915_texture_layout_3d(struct i915_texture * tex)389 i915_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 
433 static bool
i915_texture_layout(struct i915_texture * tex)434 i915_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 
461 static void
i945_texture_layout_2d(struct i915_texture * tex)462 i945_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 
524 static void
i945_texture_layout_3d(struct i915_texture * tex)525 i945_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  */
641 static void
i945_texture_layout_cube(struct i915_texture * tex)642 i945_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 
737 static bool
i945_texture_layout(struct i915_texture * tex)738 i945_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 
768 bool
i915_resource_get_handle(struct pipe_screen * screen,struct pipe_context * context,struct pipe_resource * texture,struct winsys_handle * whandle,unsigned usage)769 i915_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 
784 void *
i915_texture_transfer_map(struct pipe_context * pipe,struct pipe_resource * resource,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** ptransfer)785 i915_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 
864 void
i915_texture_transfer_unmap(struct pipe_context * pipe,struct pipe_transfer * transfer)865 i915_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 
893 void
i915_texture_subdata(struct pipe_context * pipe,struct pipe_resource * resource,unsigned level,unsigned usage,const struct pipe_box * box,const void * data,unsigned stride,unsigned layer_stride)894 i915_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 
912 struct pipe_resource *
i915_texture_create(struct pipe_screen * screen,const struct pipe_resource * template,bool force_untiled)913 i915_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 
963 fail:
964    FREE(tex);
965    return NULL;
966 }
967 
968 struct pipe_resource *
i915_texture_from_handle(struct pipe_screen * screen,const struct pipe_resource * template,struct winsys_handle * whandle)969 i915_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