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