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