Tizen 2.0 Release
[profile/ivi/osmesa.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    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
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
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
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
295 i9x5_texture_layout_cube(struct i915_texture *tex)
296 {
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;
301
302    assert(pt->width0 == pt->height0); /* cubemap images are square */
303
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;
307
308    for (level = 0; level <= pt->last_level; level++)
309       i915_texture_set_level_info(tex, level, 6);
310
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;
315
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;
321       }
322    }
323 }
324
325
326 /*
327  * i915 layout functions
328  */
329
330
331 static void
332 i915_texture_layout_2d(struct i915_texture *tex)
333 {
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;
340
341    if (util_format_is_s3tc(pt->format))
342       align_y = 1;
343
344    tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
345    tex->total_nblocksy = 0;
346
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);
350
351       tex->total_nblocksy += nblocksy;
352
353       width = u_minify(width, 1);
354       height = u_minify(height, 1);
355       nblocksy = align_nblocksy(pt->format, height, align_y);
356    }
357 }
358
359 static void
360 i915_texture_layout_3d(struct i915_texture *tex)
361 {
362    struct pipe_resource *pt = &tex->b.b;
363    unsigned level;
364
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;
370
371    /* Calculate the size of a single slice. 
372     */
373    tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
374
375    /* XXX: hardware expects/requires 9 levels at minimum.
376     */
377    for (level = 0; level <= MAX2(8, pt->last_level); level++) {
378       i915_texture_set_level_info(tex, level, depth);
379
380       stack_nblocksy += MAX2(2, nblocksy);
381
382       width = u_minify(width, 1);
383       height = u_minify(height, 1);
384       nblocksy = util_format_get_nblocksy(pt->format, height);
385    }
386
387    /* Fixup depth image_offsets: 
388     */
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);
393
394       depth = u_minify(depth, 1);
395    }
396
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.
400     */
401    tex->total_nblocksy = stack_nblocksy * pt->depth0;
402 }
403
404 static boolean
405 i915_texture_layout(struct i915_texture * tex)
406 {
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;
423    }
424
425    return TRUE;
426 }
427
428
429 /*
430  * i945 layout functions
431  */
432
433
434 static void
435 i945_texture_layout_2d(struct i915_texture *tex)
436 {
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);
446
447    if (util_format_is_s3tc(pt->format)) {
448       align_x = 1;
449       align_y = 1;
450    }
451
452    tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
453
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.
458     */
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));
463
464       if (mip1_nblocksx > nblocksx)
465          tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format);
466    }
467
468    /* Pitch must be a whole number of dwords
469     */
470    tex->stride = align(tex->stride, 64);
471    tex->total_nblocksy = 0;
472
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);
476
477       /* Because the images are packed better, the final offset
478        * might not be the maximal one:
479        */
480       tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
481
482       /* Layout_below: step right after second mipmap level.
483        */
484       if (level == 1) {
485          x += nblocksx;
486       } else {
487          y += nblocksy;
488       }
489
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);
494    }
495 }
496
497 static void
498 i945_texture_layout_3d(struct i915_texture *tex)
499 {
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;
508
509    tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
510    tex->total_nblocksy = 0;
511
512    pack_y_pitch = MAX2(nblocksy, 2);
513    pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format);
514    pack_x_nr = 1;
515
516    for (level = 0; level <= pt->last_level; level++) {
517       int x = 0;
518       int y = 0;
519       unsigned q, j;
520
521       i915_texture_set_level_info(tex, level, depth);
522
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;
527          }
528
529          x = 0;
530          y += pack_y_pitch;
531       }
532
533       tex->total_nblocksy += y;
534
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);
539       }
540
541       if (pack_y_pitch > 2) {
542          pack_y_pitch >>= 1;
543       }
544
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);
549    }
550 }
551
552 static void
553 i945_texture_layout_cube(struct i915_texture *tex)
554 {
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;
560
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 */
564
565    /*
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.
569     *
570     * 64  * 2 / 4 = 32
571     * 14 * 2 = 28
572     */
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);
577
578    /*
579     * Something similary apply for height as well.
580     */
581    if (pt->width0 >= 4)
582       tex->total_nblocksy = nblocks * 4 + 1;
583    else
584       tex->total_nblocksy = 1;
585
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);
589
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;
596
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;
603       }
604
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));
609
610          d >>= 1;
611
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;
630             }
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;
643          }
644       }
645    }
646 }
647
648 static boolean
649 i945_texture_layout(struct i915_texture * tex)
650 {
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;
670    }
671
672    return TRUE;
673 }
674
675
676
677 /*
678  * Screen texture functions
679  */
680
681
682
683 static boolean
684 i915_texture_get_handle(struct pipe_screen * screen,
685                         struct pipe_resource *texture,
686                         struct winsys_handle *whandle)
687 {
688    struct i915_screen *is = i915_screen(screen);
689    struct i915_texture *tex = i915_texture(texture);
690    struct i915_winsys *iws = is->iws;
691
692    return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride);
693 }
694
695
696 static void
697 i915_texture_destroy(struct pipe_screen *screen,
698                      struct pipe_resource *pt)
699 {
700    struct i915_texture *tex = i915_texture(pt);
701    struct i915_winsys *iws = i915_screen(screen)->iws;
702    uint i;
703
704    if (tex->buffer)
705       iws->buffer_destroy(iws, tex->buffer);
706
707    for (i = 0; i < Elements(tex->image_offset); i++)
708       if (tex->image_offset[i])
709          FREE(tex->image_offset[i]);
710
711    FREE(tex);
712 }
713
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)
720 {
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;
725
726    if (transfer == NULL)
727       return NULL;
728
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;
738
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;
749
750    use_staging_texture = FALSE;
751
752    if (use_staging_texture) {
753       /* 
754        * Allocate the untiled staging texture.
755        * If the alloc fails, transfer->staging_texture is NULL and we fallback to a map() 
756        */
757       transfer->staging_texture = i915_texture_create(pipe->screen, resource, TRUE);
758    }
759
760    return (struct pipe_transfer*)transfer;
761 }
762
763 static void
764 i915_transfer_destroy(struct pipe_context *pipe,
765                       struct pipe_transfer *transfer)
766 {
767    struct i915_context *i915 = i915_context(pipe);
768    struct i915_transfer *itransfer = (struct i915_transfer*)transfer;
769
770    if ((itransfer->staging_texture) &&
771        (transfer->usage & PIPE_TRANSFER_WRITE)) {
772       struct pipe_box sbox;
773
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);
781    }
782
783    util_slab_free(&i915->texture_transfer_pool, itransfer);
784 }
785
786 static void *
787 i915_texture_transfer_map(struct pipe_context *pipe,
788                           struct pipe_transfer *transfer)
789 {
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;
798
799    if (resource->target != PIPE_TEXTURE_3D &&
800        resource->target != PIPE_TEXTURE_CUBE)
801       assert(box->z == 0);
802
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);
809    }
810
811    offset = i915_texture_offset(tex, itransfer->b.level, box->z);
812
813    map = iws->buffer_map(iws, tex->buffer,
814                          (itransfer->b.usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE);
815    if (map == NULL) {
816       return NULL;
817    }
818
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);
822 }
823
824 static void
825 i915_texture_transfer_unmap(struct pipe_context *pipe,
826                             struct pipe_transfer *transfer)
827 {
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;
831
832    if (itransfer->staging_texture)
833       tex = i915_texture(itransfer->staging_texture);
834
835    iws->buffer_unmap(iws, tex->buffer);
836 }
837
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)
846 {
847    struct pipe_transfer *transfer = NULL;
848    struct i915_transfer *itransfer = NULL;
849    const uint8_t *src_data = data;
850    unsigned i;
851
852    transfer = pipe->get_transfer(pipe,
853                                  resource,
854                                  level,
855                                  usage,
856                                  box );
857    if (transfer == NULL)
858       goto out;
859
860    itransfer = (struct i915_transfer*)transfer;
861
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;
868
869       offset = i915_texture_offset(tex, transfer->level, transfer->box.z);
870
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);
878
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);
883
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;
889
890              for (i = 0; i < nby; i++) {
891                      iws->buffer_write(iws, tex->buffer, offset, size, transfer->data);
892                      offset += tex->stride;
893              }
894          }
895          offset += layer_stride;
896       }
897    } else {
898       uint8_t *map = pipe_transfer_map(pipe, &itransfer->b);
899       if (map == NULL)
900          goto nomap;
901
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;
914       }
915 nomap:
916       if (map)
917          pipe_transfer_unmap(pipe, &itransfer->b);
918    }
919
920 out:
921    if (itransfer)
922       pipe_transfer_destroy(pipe, &itransfer->b);
923 }
924
925
926
927 struct u_resource_vtbl i915_texture_vtbl =
928 {
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 */
937 };
938
939
940
941
942 struct pipe_resource *
943 i915_texture_create(struct pipe_screen *screen,
944                     const struct pipe_resource *template,
945                     boolean force_untiled)
946 {
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;
951
952    if (!tex)
953       return NULL;
954
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;
959
960    if (force_untiled)
961       tex->tiling = I915_TILE_NONE;
962    else
963       tex->tiling = i915_texture_tiling(is, tex);
964
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;
971    }
972
973    /* for scanouts and cursors, cursors arn't scanouts */
974
975    /* XXX: use a custom flag for cursors, don't rely on magically
976     * guessing that this is Xorg asking for a cursor
977     */
978    if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64)
979       buf_usage = I915_NEW_SCANOUT;
980    else
981       buf_usage = I915_NEW_TEXTURE;
982
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;
991
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));
996
997    return &tex->b.b;
998
999 fail:
1000    FREE(tex);
1001    return NULL;
1002 }
1003
1004 struct pipe_resource *
1005 i915_texture_from_handle(struct pipe_screen * screen,
1006                           const struct pipe_resource *template,
1007                           struct winsys_handle *whandle)
1008 {
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;
1015
1016    assert(screen);
1017
1018    buffer = iws->buffer_from_handle(iws, whandle, &tiling, &stride);
1019
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;
1026    }
1027
1028    tex = CALLOC_STRUCT(i915_texture);
1029    if (!tex)
1030       return NULL;
1031
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;
1036
1037    tex->stride = stride;
1038    tex->tiling = tiling;
1039    tex->total_nblocksy = align_nblocksy(tex->b.b.format, tex->b.b.height0, 8);
1040
1041    i915_texture_set_level_info(tex, 0, 1);
1042    i915_texture_set_image_offset(tex, 0, 0, 0, 0);
1043
1044    tex->buffer = buffer;
1045
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));
1050
1051    return &tex->b.b;
1052 }
1053