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