revert between 56095 -> 55830 in arch
[AROS.git] / workbench / libs / mesa / src / gallium / drivers / i915 / i915_resource_texture.c
blob3a00d08ad57fd15f72e22fb455f54c065316e3a3
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:
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.
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.
26 **************************************************************************/
28 * Authors:
29 * Keith Whitwell <keith@tungstengraphics.com>
30 * Michel Dänzer <michel@tungstengraphics.com>
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"
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"
49 #define DEBUG_TEXTURES 0
52 * Helper function and arrays
56 /**
57 * Initial offset for Cube map.
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},
68 /**
69 * Step offsets for Cube map.
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},
80 /**
81 * For compressed level 2
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,
92 static INLINE unsigned
93 align_nblocksx(enum pipe_format format, unsigned width, unsigned align_to)
95 return align(util_format_get_nblocksx(format, width), align_to);
98 static INLINE unsigned
99 align_nblocksy(enum pipe_format format, unsigned width, unsigned align_to)
101 return align(util_format_get_nblocksy(format, width), align_to);
104 static INLINE unsigned
105 get_pot_stride(enum pipe_format format, unsigned width)
107 return util_next_power_of_two(util_format_get_stride(format, width));
110 static INLINE const char*
111 get_tiling_string(enum i915_winsys_buffer_tile tile)
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 "?";
128 * More advanced helper funcs
132 static void
133 i915_texture_set_level_info(struct i915_texture *tex,
134 unsigned level, unsigned nr_images)
136 assert(level < Elements(tex->nr_images));
137 assert(nr_images);
138 assert(!tex->image_offset[level]);
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;
146 INLINE unsigned i915_texture_offset(struct i915_texture *tex,
147 unsigned level, unsigned layer)
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;
154 return y * tex->stride + x;
157 static void
158 i915_texture_set_image_offset(struct i915_texture *tex,
159 unsigned level, unsigned img,
160 unsigned nblocksx, unsigned nblocksy)
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]);
166 tex->image_offset[level][img].nblocksx = nblocksx;
167 tex->image_offset[level][img].nblocksy = nblocksy;
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
175 static enum i915_winsys_buffer_tile
176 i915_texture_tiling(struct i915_screen *is, struct i915_texture *tex)
178 if (!is->debug.tiling)
179 return I915_TILE_NONE;
181 if (tex->b.b.target == PIPE_TEXTURE_1D)
182 return I915_TILE_NONE;
184 if (util_format_is_s3tc(tex->b.b.format))
185 return I915_TILE_X;
187 if (is->debug.use_blitter)
188 return I915_TILE_X;
189 else
190 return I915_TILE_Y;
195 * Shared layout functions
200 * Special case to deal with scanout textures.
202 static boolean
203 i9x5_scanout_layout(struct i915_texture *tex)
205 struct pipe_resource *pt = &tex->b.b;
207 if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
208 return FALSE;
210 i915_texture_set_level_info(tex, 0, 1);
211 i915_texture_set_image_offset(tex, 0, 0, 0, 0);
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;
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
231 return TRUE;
235 * Special case to deal with shared textures.
237 static boolean
238 i9x5_display_target_layout(struct i915_texture *tex)
240 struct pipe_resource *pt = &tex->b.b;
242 if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
243 return FALSE;
245 /* fallback to normal textures for small textures */
246 if (pt->width0 < 240)
247 return FALSE;
249 i915_texture_set_level_info(tex, 0, 1);
250 i915_texture_set_image_offset(tex, 0, 0, 0, 0);
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;
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
262 return TRUE;
266 * Helper function for special layouts
268 static boolean
269 i9x5_special_layout(struct i915_texture *tex)
271 struct pipe_resource *pt = &tex->b.b;
273 /* Scanouts needs special care */
274 if (pt->bind & PIPE_BIND_SCANOUT)
275 if (i9x5_scanout_layout(tex))
276 return TRUE;
278 /* Shared buffers needs to be compatible with X servers
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.
284 if (pt->bind & (PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET))
285 if (i9x5_display_target_layout(tex))
286 return TRUE;
288 return FALSE;
292 * Cube layout used on i915 and for non-compressed textures on i945.
294 static void
295 i9x5_texture_layout_cube(struct i915_texture *tex)
297 struct pipe_resource *pt = &tex->b.b;
298 const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
299 unsigned level;
300 unsigned face;
302 assert(pt->width0 == pt->height0); /* cubemap images are square */
304 /* double pitch for cube layouts */
305 tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
306 tex->total_nblocksy = nblocks * 4;
308 for (level = 0; level <= pt->last_level; level++)
309 i915_texture_set_level_info(tex, level, 6);
311 for (face = 0; face < 6; face++) {
312 unsigned x = initial_offsets[face][0] * nblocks;
313 unsigned y = initial_offsets[face][1] * nblocks;
314 unsigned d = nblocks;
316 for (level = 0; level <= pt->last_level; level++) {
317 i915_texture_set_image_offset(tex, level, face, x, y);
318 d >>= 1;
319 x += step_offsets[face][0] * d;
320 y += step_offsets[face][1] * d;
327 * i915 layout functions
331 static void
332 i915_texture_layout_2d(struct i915_texture *tex)
334 struct pipe_resource *pt = &tex->b.b;
335 unsigned level;
336 unsigned width = pt->width0;
337 unsigned height = pt->height0;
338 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
339 unsigned align_y = 2;
341 if (util_format_is_s3tc(pt->format))
342 align_y = 1;
344 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
345 tex->total_nblocksy = 0;
347 for (level = 0; level <= pt->last_level; level++) {
348 i915_texture_set_level_info(tex, level, 1);
349 i915_texture_set_image_offset(tex, level, 0, 0, tex->total_nblocksy);
351 tex->total_nblocksy += nblocksy;
353 width = u_minify(width, 1);
354 height = u_minify(height, 1);
355 nblocksy = align_nblocksy(pt->format, height, align_y);
359 static void
360 i915_texture_layout_3d(struct i915_texture *tex)
362 struct pipe_resource *pt = &tex->b.b;
363 unsigned level;
365 unsigned width = pt->width0;
366 unsigned height = pt->height0;
367 unsigned depth = pt->depth0;
368 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
369 unsigned stack_nblocksy = 0;
371 /* Calculate the size of a single slice.
373 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
375 /* XXX: hardware expects/requires 9 levels at minimum.
377 for (level = 0; level <= MAX2(8, pt->last_level); level++) {
378 i915_texture_set_level_info(tex, level, depth);
380 stack_nblocksy += MAX2(2, nblocksy);
382 width = u_minify(width, 1);
383 height = u_minify(height, 1);
384 nblocksy = util_format_get_nblocksy(pt->format, height);
387 /* Fixup depth image_offsets:
389 for (level = 0; level <= pt->last_level; level++) {
390 unsigned i;
391 for (i = 0; i < depth; i++)
392 i915_texture_set_image_offset(tex, level, i, 0, i * stack_nblocksy);
394 depth = u_minify(depth, 1);
397 /* Multiply slice size by texture depth for total size. It's
398 * remarkable how wasteful of memory the i915 texture layouts
399 * are. They are largely fixed in the i945.
401 tex->total_nblocksy = stack_nblocksy * pt->depth0;
404 static boolean
405 i915_texture_layout(struct i915_texture * tex)
407 switch (tex->b.b.target) {
408 case PIPE_TEXTURE_1D:
409 case PIPE_TEXTURE_2D:
410 case PIPE_TEXTURE_RECT:
411 if (!i9x5_special_layout(tex))
412 i915_texture_layout_2d(tex);
413 break;
414 case PIPE_TEXTURE_3D:
415 i915_texture_layout_3d(tex);
416 break;
417 case PIPE_TEXTURE_CUBE:
418 i9x5_texture_layout_cube(tex);
419 break;
420 default:
421 assert(0);
422 return FALSE;
425 return TRUE;
430 * i945 layout functions
434 static void
435 i945_texture_layout_2d(struct i915_texture *tex)
437 struct pipe_resource *pt = &tex->b.b;
438 int align_x = 4, align_y = 2;
439 unsigned level;
440 unsigned x = 0;
441 unsigned y = 0;
442 unsigned width = pt->width0;
443 unsigned height = pt->height0;
444 unsigned nblocksx = util_format_get_nblocksx(pt->format, pt->width0);
445 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
447 if (util_format_is_s3tc(pt->format)) {
448 align_x = 1;
449 align_y = 1;
452 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
454 /* May need to adjust pitch to accomodate the placement of
455 * the 2nd mipmap level. This occurs when the alignment
456 * constraints of mipmap placement push the right edge of the
457 * 2nd mipmap level out past the width of its parent.
459 if (pt->last_level > 0) {
460 unsigned mip1_nblocksx =
461 align_nblocksx(pt->format, u_minify(pt->width0, 1), align_x) +
462 util_format_get_nblocksx(pt->format, u_minify(pt->width0, 2));
464 if (mip1_nblocksx > nblocksx)
465 tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format);
468 /* Pitch must be a whole number of dwords
470 tex->stride = align(tex->stride, 64);
471 tex->total_nblocksy = 0;
473 for (level = 0; level <= pt->last_level; level++) {
474 i915_texture_set_level_info(tex, level, 1);
475 i915_texture_set_image_offset(tex, level, 0, x, y);
477 /* Because the images are packed better, the final offset
478 * might not be the maximal one:
480 tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
482 /* Layout_below: step right after second mipmap level.
484 if (level == 1) {
485 x += nblocksx;
486 } else {
487 y += nblocksy;
490 width = u_minify(width, 1);
491 height = u_minify(height, 1);
492 nblocksx = align_nblocksx(pt->format, width, align_x);
493 nblocksy = align_nblocksy(pt->format, height, align_y);
497 static void
498 i945_texture_layout_3d(struct i915_texture *tex)
500 struct pipe_resource *pt = &tex->b.b;
501 unsigned width = pt->width0;
502 unsigned height = pt->height0;
503 unsigned depth = pt->depth0;
504 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
505 unsigned pack_x_pitch, pack_x_nr;
506 unsigned pack_y_pitch;
507 unsigned level;
509 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
510 tex->total_nblocksy = 0;
512 pack_y_pitch = MAX2(nblocksy, 2);
513 pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format);
514 pack_x_nr = 1;
516 for (level = 0; level <= pt->last_level; level++) {
517 int x = 0;
518 int y = 0;
519 unsigned q, j;
521 i915_texture_set_level_info(tex, level, depth);
523 for (q = 0; q < depth;) {
524 for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
525 i915_texture_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
526 x += pack_x_pitch;
529 x = 0;
530 y += pack_y_pitch;
533 tex->total_nblocksy += y;
535 if (pack_x_pitch > 4) {
536 pack_x_pitch >>= 1;
537 pack_x_nr <<= 1;
538 assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride);
541 if (pack_y_pitch > 2) {
542 pack_y_pitch >>= 1;
545 width = u_minify(width, 1);
546 height = u_minify(height, 1);
547 depth = u_minify(depth, 1);
548 nblocksy = util_format_get_nblocksy(pt->format, height);
552 static void
553 i945_texture_layout_cube(struct i915_texture *tex)
555 struct pipe_resource *pt = &tex->b.b;
556 const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
557 const unsigned dim = pt->width0;
558 unsigned level;
559 unsigned face;
561 assert(pt->width0 == pt->height0); /* cubemap images are square */
562 assert(util_next_power_of_two(pt->width0) == pt->width0); /* npot only */
563 assert(util_format_is_s3tc(pt->format)); /* compressed only */
566 * Depending on the size of the largest images, pitch can be
567 * determined either by the old-style packing of cubemap faces,
568 * or the final row of 4x4, 2x2 and 1x1 faces below this.
570 * 64 * 2 / 4 = 32
571 * 14 * 2 = 28
573 if (pt->width0 >= 64)
574 tex->stride = nblocks * 2 * util_format_get_blocksize(pt->format);
575 else
576 tex->stride = 14 * 2 * util_format_get_blocksize(pt->format);
579 * Something similary apply for height as well.
581 if (pt->width0 >= 4)
582 tex->total_nblocksy = nblocks * 4 + 1;
583 else
584 tex->total_nblocksy = 1;
586 /* Set all the levels to effectively occupy the whole rectangular region */
587 for (level = 0; level <= pt->last_level; level++)
588 i915_texture_set_level_info(tex, level, 6);
590 for (face = 0; face < 6; face++) {
591 /* all calculations in pixels */
592 unsigned total_height = tex->total_nblocksy * 4;
593 unsigned x = initial_offsets[face][0] * dim;
594 unsigned y = initial_offsets[face][1] * dim;
595 unsigned d = dim;
597 if (dim == 4 && face >= 4) {
598 x = (face - 4) * 8;
599 y = tex->total_nblocksy * 4 - 4; /* 4 = 1 block */
600 } else if (dim < 4 && (face > 0)) {
601 x = face * 8;
602 y = total_height - 4;
605 for (level = 0; level <= pt->last_level; level++) {
606 i915_texture_set_image_offset(tex, level, face,
607 util_format_get_nblocksx(pt->format, x),
608 util_format_get_nblocksy(pt->format, y));
610 d >>= 1;
612 switch (d) {
613 case 4:
614 switch (face) {
615 case PIPE_TEX_FACE_POS_X:
616 case PIPE_TEX_FACE_NEG_X:
617 x += step_offsets[face][0] * d;
618 y += step_offsets[face][1] * d;
619 break;
620 case PIPE_TEX_FACE_POS_Y:
621 case PIPE_TEX_FACE_NEG_Y:
622 y += 12;
623 x -= 8;
624 break;
625 case PIPE_TEX_FACE_POS_Z:
626 case PIPE_TEX_FACE_NEG_Z:
627 y = total_height - 4;
628 x = (face - 4) * 8;
629 break;
631 break;
632 case 2:
633 y = total_height - 4;
634 x = bottom_offsets[face];
635 break;
636 case 1:
637 x += 48;
638 break;
639 default:
640 x += step_offsets[face][0] * d;
641 y += step_offsets[face][1] * d;
642 break;
648 static boolean
649 i945_texture_layout(struct i915_texture * tex)
651 switch (tex->b.b.target) {
652 case PIPE_TEXTURE_1D:
653 case PIPE_TEXTURE_2D:
654 case PIPE_TEXTURE_RECT:
655 if (!i9x5_special_layout(tex))
656 i945_texture_layout_2d(tex);
657 break;
658 case PIPE_TEXTURE_3D:
659 i945_texture_layout_3d(tex);
660 break;
661 case PIPE_TEXTURE_CUBE:
662 if (!util_format_is_s3tc(tex->b.b.format))
663 i9x5_texture_layout_cube(tex);
664 else
665 i945_texture_layout_cube(tex);
666 break;
667 default:
668 assert(0);
669 return FALSE;
672 return TRUE;
678 * Screen texture functions
683 static boolean
684 i915_texture_get_handle(struct pipe_screen * screen,
685 struct pipe_resource *texture,
686 struct winsys_handle *whandle)
688 struct i915_screen *is = i915_screen(screen);
689 struct i915_texture *tex = i915_texture(texture);
690 struct i915_winsys *iws = is->iws;
692 return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride);
696 static void
697 i915_texture_destroy(struct pipe_screen *screen,
698 struct pipe_resource *pt)
700 struct i915_texture *tex = i915_texture(pt);
701 struct i915_winsys *iws = i915_screen(screen)->iws;
702 uint i;
704 if (tex->buffer)
705 iws->buffer_destroy(iws, tex->buffer);
707 for (i = 0; i < Elements(tex->image_offset); i++)
708 if (tex->image_offset[i])
709 FREE(tex->image_offset[i]);
711 FREE(tex);
714 static struct pipe_transfer *
715 i915_texture_get_transfer(struct pipe_context *pipe,
716 struct pipe_resource *resource,
717 unsigned level,
718 unsigned usage,
719 const struct pipe_box *box)
721 struct i915_context *i915 = i915_context(pipe);
722 struct i915_texture *tex = i915_texture(resource);
723 struct i915_transfer *transfer = util_slab_alloc(&i915->texture_transfer_pool);
724 boolean use_staging_texture = FALSE;
726 if (transfer == NULL)
727 return NULL;
729 transfer->b.resource = resource;
730 transfer->b.level = level;
731 transfer->b.usage = usage;
732 transfer->b.box = *box;
733 transfer->b.stride = tex->stride;
734 transfer->staging_texture = NULL;
735 /* XXX: handle depth textures everyhwere*/
736 transfer->b.layer_stride = 0;
737 transfer->b.data = NULL;
739 /* only support textures we can render to, because we need that for u_blitter */
740 if (i915->blitter &&
741 i915_is_format_supported(NULL, /* screen */
742 transfer->b.resource->format,
743 0, /* target */
744 1, /* sample count */
745 PIPE_BIND_RENDER_TARGET) &&
746 (usage & PIPE_TRANSFER_WRITE) &&
747 !(usage & (PIPE_TRANSFER_READ | PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED)))
748 use_staging_texture = TRUE;
750 use_staging_texture = FALSE;
752 if (use_staging_texture) {
754 * Allocate the untiled staging texture.
755 * If the alloc fails, transfer->staging_texture is NULL and we fallback to a map()
757 transfer->staging_texture = i915_texture_create(pipe->screen, resource, TRUE);
760 return (struct pipe_transfer*)transfer;
763 static void
764 i915_transfer_destroy(struct pipe_context *pipe,
765 struct pipe_transfer *transfer)
767 struct i915_context *i915 = i915_context(pipe);
768 struct i915_transfer *itransfer = (struct i915_transfer*)transfer;
770 if ((itransfer->staging_texture) &&
771 (transfer->usage & PIPE_TRANSFER_WRITE)) {
772 struct pipe_box sbox;
774 u_box_origin_2d(itransfer->b.box.width, itransfer->b.box.height, &sbox);
775 pipe->resource_copy_region(pipe, itransfer->b.resource, itransfer->b.level,
776 itransfer->b.box.x, itransfer->b.box.y, itransfer->b.box.z,
777 itransfer->staging_texture,
778 0, &sbox);
779 pipe->flush(pipe, NULL);
780 pipe_resource_reference(&itransfer->staging_texture, NULL);
783 util_slab_free(&i915->texture_transfer_pool, itransfer);
786 static void *
787 i915_texture_transfer_map(struct pipe_context *pipe,
788 struct pipe_transfer *transfer)
790 struct i915_transfer *itransfer = (struct i915_transfer*)transfer;
791 struct pipe_resource *resource = itransfer->b.resource;
792 struct i915_texture *tex = NULL;
793 struct i915_winsys *iws = i915_screen(pipe->screen)->iws;
794 struct pipe_box *box = &itransfer->b.box;
795 enum pipe_format format = resource->format;
796 unsigned offset;
797 char *map;
799 if (resource->target != PIPE_TEXTURE_3D &&
800 resource->target != PIPE_TEXTURE_CUBE)
801 assert(box->z == 0);
803 if (itransfer->staging_texture) {
804 tex = i915_texture(itransfer->staging_texture);
805 } else {
806 /* TODO this is a sledgehammer */
807 tex = i915_texture(resource);
808 pipe->flush(pipe, NULL);
811 offset = i915_texture_offset(tex, itransfer->b.level, box->z);
813 map = iws->buffer_map(iws, tex->buffer,
814 (itransfer->b.usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE);
815 if (map == NULL) {
816 return NULL;
819 return map + offset +
820 box->y / util_format_get_blockheight(format) * itransfer->b.stride +
821 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
824 static void
825 i915_texture_transfer_unmap(struct pipe_context *pipe,
826 struct pipe_transfer *transfer)
828 struct i915_transfer *itransfer = (struct i915_transfer*)transfer;
829 struct i915_texture *tex = i915_texture(itransfer->b.resource);
830 struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws;
832 if (itransfer->staging_texture)
833 tex = i915_texture(itransfer->staging_texture);
835 iws->buffer_unmap(iws, tex->buffer);
838 static void i915_transfer_inline_write( struct pipe_context *pipe,
839 struct pipe_resource *resource,
840 unsigned level,
841 unsigned usage,
842 const struct pipe_box *box,
843 const void *data,
844 unsigned stride,
845 unsigned layer_stride)
847 struct pipe_transfer *transfer = NULL;
848 struct i915_transfer *itransfer = NULL;
849 const uint8_t *src_data = data;
850 unsigned i;
852 transfer = pipe->get_transfer(pipe,
853 resource,
854 level,
855 usage,
856 box );
857 if (transfer == NULL)
858 goto out;
860 itransfer = (struct i915_transfer*)transfer;
862 if (itransfer->staging_texture) {
863 struct i915_texture *tex = i915_texture(itransfer->staging_texture);
864 enum pipe_format format = tex->b.b.format;
865 struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws;
866 size_t offset;
867 size_t size;
869 offset = i915_texture_offset(tex, transfer->level, transfer->box.z);
871 for (i = 0; i < box->depth; i++) {
872 if (!tex->b.b.last_level &&
873 tex->b.b.width0 == transfer->box.width) {
874 unsigned nby = util_format_get_nblocksy(format, transfer->box.y);
875 assert(!offset);
876 assert(!transfer->box.x);
877 assert(tex->stride == transfer->stride);
879 offset += tex->stride * nby;
880 size = util_format_get_2d_size(format, transfer->stride,
881 transfer->box.height);
882 iws->buffer_write(iws, tex->buffer, offset, size, transfer->data);
884 } else {
885 unsigned nby = util_format_get_nblocksy(format, transfer->box.y);
886 int i;
887 offset += util_format_get_stride(format, transfer->box.x);
888 size = transfer->stride;
890 for (i = 0; i < nby; i++) {
891 iws->buffer_write(iws, tex->buffer, offset, size, transfer->data);
892 offset += tex->stride;
895 offset += layer_stride;
897 } else {
898 uint8_t *map = pipe_transfer_map(pipe, &itransfer->b);
899 if (map == NULL)
900 goto nomap;
902 for (i = 0; i < box->depth; i++) {
903 util_copy_rect(map,
904 resource->format,
905 itransfer->b.stride, /* bytes */
906 0, 0,
907 box->width,
908 box->height,
909 src_data,
910 stride, /* bytes */
911 0, 0);
912 map += itransfer->b.layer_stride;
913 src_data += layer_stride;
915 nomap:
916 if (map)
917 pipe_transfer_unmap(pipe, &itransfer->b);
920 out:
921 if (itransfer)
922 pipe_transfer_destroy(pipe, &itransfer->b);
927 struct u_resource_vtbl i915_texture_vtbl =
929 i915_texture_get_handle, /* get_handle */
930 i915_texture_destroy, /* resource_destroy */
931 i915_texture_get_transfer, /* get_transfer */
932 i915_transfer_destroy, /* transfer_destroy */
933 i915_texture_transfer_map, /* transfer_map */
934 u_default_transfer_flush_region, /* transfer_flush_region */
935 i915_texture_transfer_unmap, /* transfer_unmap */
936 i915_transfer_inline_write /* transfer_inline_write */
942 struct pipe_resource *
943 i915_texture_create(struct pipe_screen *screen,
944 const struct pipe_resource *template,
945 boolean force_untiled)
947 struct i915_screen *is = i915_screen(screen);
948 struct i915_winsys *iws = is->iws;
949 struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
950 unsigned buf_usage = 0;
952 if (!tex)
953 return NULL;
955 tex->b.b = *template;
956 tex->b.vtbl = &i915_texture_vtbl;
957 pipe_reference_init(&tex->b.b.reference, 1);
958 tex->b.b.screen = screen;
960 if (force_untiled)
961 tex->tiling = I915_TILE_NONE;
962 else
963 tex->tiling = i915_texture_tiling(is, tex);
965 if (is->is_i945) {
966 if (!i945_texture_layout(tex))
967 goto fail;
968 } else {
969 if (!i915_texture_layout(tex))
970 goto fail;
973 /* for scanouts and cursors, cursors arn't scanouts */
975 /* XXX: use a custom flag for cursors, don't rely on magically
976 * guessing that this is Xorg asking for a cursor
978 if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64)
979 buf_usage = I915_NEW_SCANOUT;
980 else
981 buf_usage = I915_NEW_TEXTURE;
983 if (tex->tiling == I915_TILE_NONE)
984 tex->buffer = iws->buffer_create(iws, tex->total_nblocksy * tex->stride,
985 buf_usage);
986 else
987 tex->buffer = iws->buffer_create_tiled(iws, &tex->stride, tex->total_nblocksy,
988 &tex->tiling, buf_usage);
989 if (!tex->buffer)
990 goto fail;
992 I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__,
993 tex, tex->stride,
994 tex->stride / util_format_get_blocksize(tex->b.b.format),
995 tex->total_nblocksy, get_tiling_string(tex->tiling));
997 return &tex->b.b;
999 fail:
1000 FREE(tex);
1001 return NULL;
1004 struct pipe_resource *
1005 i915_texture_from_handle(struct pipe_screen * screen,
1006 const struct pipe_resource *template,
1007 struct winsys_handle *whandle)
1009 struct i915_screen *is = i915_screen(screen);
1010 struct i915_texture *tex;
1011 struct i915_winsys *iws = is->iws;
1012 struct i915_winsys_buffer *buffer;
1013 unsigned stride;
1014 enum i915_winsys_buffer_tile tiling;
1016 assert(screen);
1018 buffer = iws->buffer_from_handle(iws, whandle, &tiling, &stride);
1020 /* Only supports one type */
1021 if ((template->target != PIPE_TEXTURE_2D &&
1022 template->target != PIPE_TEXTURE_RECT) ||
1023 template->last_level != 0 ||
1024 template->depth0 != 1) {
1025 return NULL;
1028 tex = CALLOC_STRUCT(i915_texture);
1029 if (!tex)
1030 return NULL;
1032 tex->b.b = *template;
1033 tex->b.vtbl = &i915_texture_vtbl;
1034 pipe_reference_init(&tex->b.b.reference, 1);
1035 tex->b.b.screen = screen;
1037 tex->stride = stride;
1038 tex->tiling = tiling;
1039 tex->total_nblocksy = align_nblocksy(tex->b.b.format, tex->b.b.height0, 8);
1041 i915_texture_set_level_info(tex, 0, 1);
1042 i915_texture_set_image_offset(tex, 0, 0, 0, 0);
1044 tex->buffer = buffer;
1046 I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__,
1047 tex, tex->stride,
1048 tex->stride / util_format_get_blocksize(tex->b.b.format),
1049 tex->total_nblocksy, get_tiling_string(tex->tiling));
1051 return &tex->b.b;