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