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