Merge branch 'mesa_7_7_branch'
[mesa.git] / src / gallium / drivers / i915 / i915_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 "pipe/p_inlines.h"
37 #include "pipe/internal/p_winsys_screen.h"
38 #include "util/u_format.h"
39 #include "util/u_math.h"
40 #include "util/u_memory.h"
41
42 #include "i915_context.h"
43 #include "i915_texture.h"
44 #include "i915_screen.h"
45 #include "intel_winsys.h"
46
47
48 /*
49 * Helper function and arrays
50 */
51
52
53 /**
54 * Initial offset for Cube map.
55 */
56 static const int initial_offsets[6][2] = {
57 {0, 0},
58 {0, 2},
59 {1, 0},
60 {1, 2},
61 {1, 1},
62 {1, 3}
63 };
64
65 /**
66 * Step offsets for Cube map.
67 */
68 static const int step_offsets[6][2] = {
69 {0, 2},
70 {0, 2},
71 {-1, 2},
72 {-1, 2},
73 {-1, 1},
74 {-1, 1}
75 };
76
77 /* XXX really need twice the size if x is already pot?
78 Otherwise just use util_next_power_of_two?
79 */
80 static unsigned
81 power_of_two(unsigned x)
82 {
83 unsigned value = 1;
84 while (value < x)
85 value = value << 1;
86 return value;
87 }
88
89 /*
90 * More advanced helper funcs
91 */
92
93
94 static void
95 i915_miptree_set_level_info(struct i915_texture *tex,
96 unsigned level,
97 unsigned nr_images,
98 unsigned w, unsigned h, unsigned d)
99 {
100 assert(level < PIPE_MAX_TEXTURE_LEVELS);
101
102 tex->nr_images[level] = nr_images;
103
104 /*
105 DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
106 level, w, h, d, x, y, tex->level_offset[level]);
107 */
108
109 /* Not sure when this would happen, but anyway:
110 */
111 if (tex->image_offset[level]) {
112 FREE(tex->image_offset[level]);
113 tex->image_offset[level] = NULL;
114 }
115
116 assert(nr_images);
117 assert(!tex->image_offset[level]);
118
119 tex->image_offset[level] = (unsigned *) MALLOC(nr_images * sizeof(unsigned));
120 tex->image_offset[level][0] = 0;
121 }
122
123 static void
124 i915_miptree_set_image_offset(struct i915_texture *tex,
125 unsigned level, unsigned img, unsigned x, unsigned y)
126 {
127 if (img == 0 && level == 0)
128 assert(x == 0 && y == 0);
129
130 assert(img < tex->nr_images[level]);
131
132 tex->image_offset[level][img] = y * tex->stride + x * util_format_get_blocksize(tex->base.format);
133
134 /*
135 printf("%s level %d img %d pos %d,%d image_offset %x\n",
136 __FUNCTION__, level, img, x, y, tex->image_offset[level][img]);
137 */
138 }
139
140
141 /*
142 * i915 layout functions, some used by i945
143 */
144
145
146 /**
147 * Special case to deal with scanout textures.
148 */
149 static boolean
150 i915_scanout_layout(struct i915_texture *tex)
151 {
152 struct pipe_texture *pt = &tex->base;
153
154 if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
155 return FALSE;
156
157 i915_miptree_set_level_info(tex, 0, 1,
158 pt->width0,
159 pt->height0,
160 1);
161 i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
162
163 if (pt->width0 >= 240) {
164 tex->stride = power_of_two(util_format_get_stride(pt->format, pt->width0));
165 tex->total_nblocksy = align(util_format_get_nblocksy(pt->format, pt->height0), 8);
166 tex->hw_tiled = INTEL_TILE_X;
167 } else if (pt->width0 == 64 && pt->height0 == 64) {
168 tex->stride = power_of_two(util_format_get_stride(pt->format, pt->width0));
169 tex->total_nblocksy = align(util_format_get_nblocksy(pt->format, pt->height0), 8);
170 } else {
171 return FALSE;
172 }
173
174 debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
175 pt->width0, pt->height0, util_format_get_blocksize(pt->format),
176 tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
177
178 return TRUE;
179 }
180
181 /**
182 * Special case to deal with shared textures.
183 */
184 static boolean
185 i915_display_target_layout(struct i915_texture *tex)
186 {
187 struct pipe_texture *pt = &tex->base;
188
189 if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
190 return FALSE;
191
192 /* fallback to normal textures for small textures */
193 if (pt->width0 < 240)
194 return FALSE;
195
196 i915_miptree_set_level_info(tex, 0, 1,
197 pt->width0,
198 pt->height0,
199 1);
200 i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
201
202 tex->stride = power_of_two(util_format_get_stride(pt->format, pt->width0));
203 tex->total_nblocksy = align(util_format_get_nblocksy(pt->format, pt->height0), 8);
204 tex->hw_tiled = INTEL_TILE_X;
205
206 debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
207 pt->width0, pt->height0, util_format_get_blocksize(pt->format),
208 tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
209
210 return TRUE;
211 }
212
213 static void
214 i915_miptree_layout_2d(struct i915_texture *tex)
215 {
216 struct pipe_texture *pt = &tex->base;
217 unsigned level;
218 unsigned width = pt->width0;
219 unsigned height = pt->height0;
220 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
221
222 /* used for scanouts that need special layouts */
223 if (pt->tex_usage & PIPE_TEXTURE_USAGE_PRIMARY)
224 if (i915_scanout_layout(tex))
225 return;
226
227 /* for shared buffers we use some very like scanout */
228 if (pt->tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET)
229 if (i915_display_target_layout(tex))
230 return;
231
232 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
233 tex->total_nblocksy = 0;
234
235 for (level = 0; level <= pt->last_level; level++) {
236 i915_miptree_set_level_info(tex, level, 1, width, height, 1);
237 i915_miptree_set_image_offset(tex, level, 0, 0, tex->total_nblocksy);
238
239 nblocksy = align(MAX2(2, nblocksy), 2);
240
241 tex->total_nblocksy += nblocksy;
242
243 width = u_minify(width, 1);
244 height = u_minify(height, 1);
245 nblocksy = util_format_get_nblocksy(pt->format, height);
246 }
247 }
248
249 static void
250 i915_miptree_layout_3d(struct i915_texture *tex)
251 {
252 struct pipe_texture *pt = &tex->base;
253 unsigned level;
254
255 unsigned width = pt->width0;
256 unsigned height = pt->height0;
257 unsigned depth = pt->depth0;
258 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
259 unsigned stack_nblocksy = 0;
260
261 /* Calculate the size of a single slice.
262 */
263 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
264
265 /* XXX: hardware expects/requires 9 levels at minimum.
266 */
267 for (level = 0; level <= MAX2(8, pt->last_level); level++) {
268 i915_miptree_set_level_info(tex, level, depth, width, height, depth);
269
270 stack_nblocksy += MAX2(2, nblocksy);
271
272 width = u_minify(width, 1);
273 height = u_minify(height, 1);
274 nblocksy = util_format_get_nblocksy(pt->format, height);
275 }
276
277 /* Fixup depth image_offsets:
278 */
279 for (level = 0; level <= pt->last_level; level++) {
280 unsigned i;
281 for (i = 0; i < depth; i++)
282 i915_miptree_set_image_offset(tex, level, i, 0, i * stack_nblocksy);
283
284 depth = u_minify(depth, 1);
285 }
286
287 /* Multiply slice size by texture depth for total size. It's
288 * remarkable how wasteful of memory the i915 texture layouts
289 * are. They are largely fixed in the i945.
290 */
291 tex->total_nblocksy = stack_nblocksy * pt->depth0;
292 }
293
294 static void
295 i915_miptree_layout_cube(struct i915_texture *tex)
296 {
297 struct pipe_texture *pt = &tex->base;
298 unsigned width = pt->width0, height = pt->height0;
299 const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
300 unsigned level;
301 unsigned face;
302
303 assert(width == height); /* cubemap images are square */
304
305 /* double pitch for cube layouts */
306 tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
307 tex->total_nblocksy = nblocks * 4;
308
309 for (level = 0; level <= pt->last_level; level++) {
310 i915_miptree_set_level_info(tex, level, 6, width, height, 1);
311 width /= 2;
312 height /= 2;
313 }
314
315 for (face = 0; face < 6; face++) {
316 unsigned x = initial_offsets[face][0] * nblocks;
317 unsigned y = initial_offsets[face][1] * nblocks;
318 unsigned d = nblocks;
319
320 for (level = 0; level <= pt->last_level; level++) {
321 i915_miptree_set_image_offset(tex, level, face, x, y);
322 d >>= 1;
323 x += step_offsets[face][0] * d;
324 y += step_offsets[face][1] * d;
325 }
326 }
327 }
328
329 static boolean
330 i915_miptree_layout(struct i915_texture * tex)
331 {
332 struct pipe_texture *pt = &tex->base;
333
334 switch (pt->target) {
335 case PIPE_TEXTURE_1D:
336 case PIPE_TEXTURE_2D:
337 i915_miptree_layout_2d(tex);
338 break;
339 case PIPE_TEXTURE_3D:
340 i915_miptree_layout_3d(tex);
341 break;
342 case PIPE_TEXTURE_CUBE:
343 i915_miptree_layout_cube(tex);
344 break;
345 default:
346 assert(0);
347 return FALSE;
348 }
349
350 return TRUE;
351 }
352
353
354 /*
355 * i945 layout functions
356 */
357
358
359 static void
360 i945_miptree_layout_2d(struct i915_texture *tex)
361 {
362 struct pipe_texture *pt = &tex->base;
363 const int align_x = 2, align_y = 4;
364 unsigned level;
365 unsigned x = 0;
366 unsigned y = 0;
367 unsigned width = pt->width0;
368 unsigned height = pt->height0;
369 unsigned nblocksx = util_format_get_nblocksx(pt->format, pt->width0);
370 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0);
371
372 /* used for scanouts that need special layouts */
373 if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_PRIMARY)
374 if (i915_scanout_layout(tex))
375 return;
376
377 /* for shared buffers we use some very like scanout */
378 if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET)
379 if (i915_display_target_layout(tex))
380 return;
381
382 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
383
384 /* May need to adjust pitch to accomodate the placement of
385 * the 2nd mipmap level. This occurs when the alignment
386 * constraints of mipmap placement push the right edge of the
387 * 2nd mipmap level out past the width of its parent.
388 */
389 if (pt->last_level > 0) {
390 unsigned mip1_nblocksx
391 = align(util_format_get_nblocksx(pt->format, u_minify(width, 1)), align_x)
392 + util_format_get_nblocksx(pt->format, u_minify(width, 2));
393
394 if (mip1_nblocksx > nblocksx)
395 tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format);
396 }
397
398 /* Pitch must be a whole number of dwords
399 */
400 tex->stride = align(tex->stride, 64);
401 tex->total_nblocksy = 0;
402
403 for (level = 0; level <= pt->last_level; level++) {
404 i915_miptree_set_level_info(tex, level, 1, width, height, 1);
405 i915_miptree_set_image_offset(tex, level, 0, x, y);
406
407 nblocksy = align(nblocksy, align_y);
408
409 /* Because the images are packed better, the final offset
410 * might not be the maximal one:
411 */
412 tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
413
414 /* Layout_below: step right after second mipmap level.
415 */
416 if (level == 1) {
417 x += align(nblocksx, align_x);
418 }
419 else {
420 y += nblocksy;
421 }
422
423 width = u_minify(width, 1);
424 height = u_minify(height, 1);
425 nblocksx = util_format_get_nblocksx(pt->format, width);
426 nblocksy = util_format_get_nblocksy(pt->format, height);
427 }
428 }
429
430 static void
431 i945_miptree_layout_3d(struct i915_texture *tex)
432 {
433 struct pipe_texture *pt = &tex->base;
434 unsigned width = pt->width0;
435 unsigned height = pt->height0;
436 unsigned depth = pt->depth0;
437 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0);
438 unsigned pack_x_pitch, pack_x_nr;
439 unsigned pack_y_pitch;
440 unsigned level;
441
442 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4);
443 tex->total_nblocksy = 0;
444
445 pack_y_pitch = MAX2(nblocksy, 2);
446 pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format);
447 pack_x_nr = 1;
448
449 for (level = 0; level <= pt->last_level; level++) {
450 int x = 0;
451 int y = 0;
452 unsigned q, j;
453
454 i915_miptree_set_level_info(tex, level, depth, width, height, depth);
455
456 for (q = 0; q < depth;) {
457 for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
458 i915_miptree_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
459 x += pack_x_pitch;
460 }
461
462 x = 0;
463 y += pack_y_pitch;
464 }
465
466 tex->total_nblocksy += y;
467
468 if (pack_x_pitch > 4) {
469 pack_x_pitch >>= 1;
470 pack_x_nr <<= 1;
471 assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride);
472 }
473
474 if (pack_y_pitch > 2) {
475 pack_y_pitch >>= 1;
476 }
477
478 width = u_minify(width, 1);
479 height = u_minify(height, 1);
480 depth = u_minify(depth, 1);
481 nblocksy = util_format_get_nblocksy(pt->format, height);
482 }
483 }
484
485 static void
486 i945_miptree_layout_cube(struct i915_texture *tex)
487 {
488 struct pipe_texture *pt = &tex->base;
489 unsigned level;
490
491 const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0);
492 unsigned face;
493 unsigned width = pt->width0;
494 unsigned height = pt->height0;
495
496 /*
497 printf("%s %i, %i\n", __FUNCTION__, pt->width0, pt->height0);
498 */
499
500 assert(width == height); /* cubemap images are square */
501
502 /*
503 * XXX Should only be used for compressed formats. But lets
504 * keep this code active just in case.
505 *
506 * Depending on the size of the largest images, pitch can be
507 * determined either by the old-style packing of cubemap faces,
508 * or the final row of 4x4, 2x2 and 1x1 faces below this.
509 */
510 if (nblocks > 32)
511 tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
512 else
513 tex->stride = 14 * 8 * util_format_get_blocksize(pt->format);
514
515 tex->total_nblocksy = nblocks * 4;
516
517 /* Set all the levels to effectively occupy the whole rectangular region.
518 */
519 for (level = 0; level <= pt->last_level; level++) {
520 i915_miptree_set_level_info(tex, level, 6, width, height, 1);
521 width /= 2;
522 height /= 2;
523 }
524
525 for (face = 0; face < 6; face++) {
526 unsigned x = initial_offsets[face][0] * nblocks;
527 unsigned y = initial_offsets[face][1] * nblocks;
528 unsigned d = nblocks;
529
530 #if 0 /* Fix and enable this code for compressed formats */
531 if (nblocks == 4 && face >= 4) {
532 y = tex->total_height - 4;
533 x = (face - 4) * 8;
534 }
535 else if (nblocks < 4 && (face > 0)) {
536 y = tex->total_height - 4;
537 x = face * 8;
538 }
539 #endif
540
541 for (level = 0; level <= pt->last_level; level++) {
542 i915_miptree_set_image_offset(tex, level, face, x, y);
543
544 d >>= 1;
545
546 #if 0 /* Fix and enable this code for compressed formats */
547 switch (d) {
548 case 4:
549 switch (face) {
550 case PIPE_TEX_FACE_POS_X:
551 case PIPE_TEX_FACE_NEG_X:
552 x += step_offsets[face][0] * d;
553 y += step_offsets[face][1] * d;
554 break;
555 case PIPE_TEX_FACE_POS_Y:
556 case PIPE_TEX_FACE_NEG_Y:
557 y += 12;
558 x -= 8;
559 break;
560 case PIPE_TEX_FACE_POS_Z:
561 case PIPE_TEX_FACE_NEG_Z:
562 y = tex->total_height - 4;
563 x = (face - 4) * 8;
564 break;
565 }
566 case 2:
567 y = tex->total_height - 4;
568 x = 16 + face * 8;
569 break;
570
571 case 1:
572 x += 48;
573 break;
574 default:
575 #endif
576 x += step_offsets[face][0] * d;
577 y += step_offsets[face][1] * d;
578 #if 0
579 break;
580 }
581 #endif
582 }
583 }
584 }
585
586 static boolean
587 i945_miptree_layout(struct i915_texture * tex)
588 {
589 struct pipe_texture *pt = &tex->base;
590
591 switch (pt->target) {
592 case PIPE_TEXTURE_1D:
593 case PIPE_TEXTURE_2D:
594 i945_miptree_layout_2d(tex);
595 break;
596 case PIPE_TEXTURE_3D:
597 i945_miptree_layout_3d(tex);
598 break;
599 case PIPE_TEXTURE_CUBE:
600 i945_miptree_layout_cube(tex);
601 break;
602 default:
603 assert(0);
604 return FALSE;
605 }
606
607 return TRUE;
608 }
609
610
611 /*
612 * Screen texture functions
613 */
614
615
616 static struct pipe_texture *
617 i915_texture_create(struct pipe_screen *screen,
618 const struct pipe_texture *templat)
619 {
620 struct i915_screen *is = i915_screen(screen);
621 struct intel_winsys *iws = is->iws;
622 struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
623 size_t tex_size;
624 unsigned buf_usage = 0;
625
626 if (!tex)
627 return NULL;
628
629 tex->base = *templat;
630 pipe_reference_init(&tex->base.reference, 1);
631 tex->base.screen = screen;
632
633 if (is->is_i945) {
634 if (!i945_miptree_layout(tex))
635 goto fail;
636 } else {
637 if (!i915_miptree_layout(tex))
638 goto fail;
639 }
640
641 tex_size = tex->stride * tex->total_nblocksy;
642
643
644
645 /* for scanouts and cursors, cursors arn't scanouts */
646 if (templat->tex_usage & PIPE_TEXTURE_USAGE_PRIMARY && templat->width0 != 64)
647 buf_usage = INTEL_NEW_SCANOUT;
648 else
649 buf_usage = INTEL_NEW_TEXTURE;
650
651 tex->buffer = iws->buffer_create(iws, tex_size, 64, buf_usage);
652 if (!tex->buffer)
653 goto fail;
654
655 /* setup any hw fences */
656 if (tex->hw_tiled) {
657 assert(tex->sw_tiled == INTEL_TILE_NONE);
658 iws->buffer_set_fence_reg(iws, tex->buffer, tex->stride, tex->hw_tiled);
659 }
660
661
662 #if 0
663 void *ptr = ws->buffer_map(ws, tex->buffer,
664 PIPE_BUFFER_USAGE_CPU_WRITE);
665 memset(ptr, 0x80, tex_size);
666 ws->buffer_unmap(ws, tex->buffer);
667 #endif
668
669 return &tex->base;
670
671 fail:
672 FREE(tex);
673 return NULL;
674 }
675
676 static struct pipe_texture *
677 i915_texture_blanket(struct pipe_screen * screen,
678 const struct pipe_texture *base,
679 const unsigned *stride,
680 struct pipe_buffer *buffer)
681 {
682 #if 0
683 struct i915_texture *tex;
684 assert(screen);
685
686 /* Only supports one type */
687 if (base->target != PIPE_TEXTURE_2D ||
688 base->last_level != 0 ||
689 base->depth0 != 1) {
690 return NULL;
691 }
692
693 tex = CALLOC_STRUCT(i915_texture);
694 if (!tex)
695 return NULL;
696
697 tex->base = *base;
698 pipe_reference_init(&tex->base.reference, 1);
699 tex->base.screen = screen;
700
701 tex->stride = stride[0];
702
703 i915_miptree_set_level_info(tex, 0, 1, base->width0, base->height0, 1);
704 i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
705
706 pipe_buffer_reference(&tex->buffer, buffer);
707
708 return &tex->base;
709 #else
710 return NULL;
711 #endif
712 }
713
714 static void
715 i915_texture_destroy(struct pipe_texture *pt)
716 {
717 struct i915_texture *tex = (struct i915_texture *)pt;
718 struct intel_winsys *iws = i915_screen(pt->screen)->iws;
719 uint i;
720
721 /*
722 DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
723 */
724
725 iws->buffer_destroy(iws, tex->buffer);
726
727 for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++)
728 if (tex->image_offset[i])
729 FREE(tex->image_offset[i]);
730
731 FREE(tex);
732 }
733
734
735 /*
736 * Screen surface functions
737 */
738
739
740 static struct pipe_surface *
741 i915_get_tex_surface(struct pipe_screen *screen,
742 struct pipe_texture *pt,
743 unsigned face, unsigned level, unsigned zslice,
744 unsigned flags)
745 {
746 struct i915_texture *tex = (struct i915_texture *)pt;
747 struct pipe_surface *ps;
748 unsigned offset; /* in bytes */
749
750 if (pt->target == PIPE_TEXTURE_CUBE) {
751 offset = tex->image_offset[level][face];
752 }
753 else if (pt->target == PIPE_TEXTURE_3D) {
754 offset = tex->image_offset[level][zslice];
755 }
756 else {
757 offset = tex->image_offset[level][0];
758 assert(face == 0);
759 assert(zslice == 0);
760 }
761
762 ps = CALLOC_STRUCT(pipe_surface);
763 if (ps) {
764 pipe_reference_init(&ps->reference, 1);
765 pipe_texture_reference(&ps->texture, pt);
766 ps->format = pt->format;
767 ps->width = u_minify(pt->width0, level);
768 ps->height = u_minify(pt->height0, level);
769 ps->offset = offset;
770 ps->usage = flags;
771 }
772 return ps;
773 }
774
775 static void
776 i915_tex_surface_destroy(struct pipe_surface *surf)
777 {
778 pipe_texture_reference(&surf->texture, NULL);
779 FREE(surf);
780 }
781
782
783 /*
784 * Screen transfer functions
785 */
786
787
788 static struct pipe_transfer*
789 i915_get_tex_transfer(struct pipe_screen *screen,
790 struct pipe_texture *texture,
791 unsigned face, unsigned level, unsigned zslice,
792 enum pipe_transfer_usage usage, unsigned x, unsigned y,
793 unsigned w, unsigned h)
794 {
795 struct i915_texture *tex = (struct i915_texture *)texture;
796 struct i915_transfer *trans;
797 unsigned offset; /* in bytes */
798
799 if (texture->target == PIPE_TEXTURE_CUBE) {
800 offset = tex->image_offset[level][face];
801 }
802 else if (texture->target == PIPE_TEXTURE_3D) {
803 offset = tex->image_offset[level][zslice];
804 }
805 else {
806 offset = tex->image_offset[level][0];
807 assert(face == 0);
808 assert(zslice == 0);
809 }
810
811 trans = CALLOC_STRUCT(i915_transfer);
812 if (trans) {
813 pipe_texture_reference(&trans->base.texture, texture);
814 trans->base.x = x;
815 trans->base.y = y;
816 trans->base.width = w;
817 trans->base.height = h;
818 trans->base.stride = tex->stride;
819 trans->offset = offset;
820 trans->base.usage = usage;
821 }
822 return &trans->base;
823 }
824
825 static void *
826 i915_transfer_map(struct pipe_screen *screen,
827 struct pipe_transfer *transfer)
828 {
829 struct i915_texture *tex = (struct i915_texture *)transfer->texture;
830 struct intel_winsys *iws = i915_screen(tex->base.screen)->iws;
831 char *map;
832 boolean write = FALSE;
833 enum pipe_format format = tex->base.format;
834
835 if (transfer->usage & PIPE_TRANSFER_WRITE)
836 write = TRUE;
837
838 map = iws->buffer_map(iws, tex->buffer, write);
839 if (map == NULL)
840 return NULL;
841
842 return map + i915_transfer(transfer)->offset +
843 transfer->y / util_format_get_blockheight(format) * transfer->stride +
844 transfer->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
845 }
846
847 static void
848 i915_transfer_unmap(struct pipe_screen *screen,
849 struct pipe_transfer *transfer)
850 {
851 struct i915_texture *tex = (struct i915_texture *)transfer->texture;
852 struct intel_winsys *iws = i915_screen(tex->base.screen)->iws;
853 iws->buffer_unmap(iws, tex->buffer);
854 }
855
856 static void
857 i915_tex_transfer_destroy(struct pipe_transfer *trans)
858 {
859 pipe_texture_reference(&trans->texture, NULL);
860 FREE(trans);
861 }
862
863
864 /*
865 * Other texture functions
866 */
867
868
869 void
870 i915_init_screen_texture_functions(struct i915_screen *is)
871 {
872 is->base.texture_create = i915_texture_create;
873 is->base.texture_blanket = i915_texture_blanket;
874 is->base.texture_destroy = i915_texture_destroy;
875 is->base.get_tex_surface = i915_get_tex_surface;
876 is->base.tex_surface_destroy = i915_tex_surface_destroy;
877 is->base.get_tex_transfer = i915_get_tex_transfer;
878 is->base.transfer_map = i915_transfer_map;
879 is->base.transfer_unmap = i915_transfer_unmap;
880 is->base.tex_transfer_destroy = i915_tex_transfer_destroy;
881 }
882
883 struct pipe_texture *
884 i915_texture_blanket_intel(struct pipe_screen *screen,
885 struct pipe_texture *base,
886 unsigned stride,
887 struct intel_buffer *buffer)
888 {
889 struct i915_texture *tex;
890 assert(screen);
891
892 /* Only supports one type */
893 if (base->target != PIPE_TEXTURE_2D ||
894 base->last_level != 0 ||
895 base->depth0 != 1) {
896 return NULL;
897 }
898
899 tex = CALLOC_STRUCT(i915_texture);
900 if (!tex)
901 return NULL;
902
903 tex->base = *base;
904 pipe_reference_init(&tex->base.reference, 1);
905 tex->base.screen = screen;
906
907 tex->stride = stride;
908
909 i915_miptree_set_level_info(tex, 0, 1, base->width0, base->height0, 1);
910 i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
911
912 tex->buffer = buffer;
913
914 return &tex->base;
915 }
916
917 boolean
918 i915_get_texture_buffer_intel(struct pipe_texture *texture,
919 struct intel_buffer **buffer,
920 unsigned *stride)
921 {
922 struct i915_texture *tex = (struct i915_texture *)texture;
923
924 if (!texture)
925 return FALSE;
926
927 *stride = tex->stride;
928 *buffer = tex->buffer;
929
930 return TRUE;
931 }