i915g: Cleanup i915_texture.c
[mesa.git] / src / gallium / drivers / i915simple / 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_math.h"
39 #include "util/u_memory.h"
40
41 #include "i915_context.h"
42 #include "i915_texture.h"
43 #include "i915_debug.h"
44 #include "i915_screen.h"
45 #include "i915_winsys.h"
46
47 /*
48 * Helper function and arrays
49 */
50
51 /**
52 * Initial offset for Cube map.
53 */
54 static const int initial_offsets[6][2] = {
55 {0, 0},
56 {0, 2},
57 {1, 0},
58 {1, 2},
59 {1, 1},
60 {1, 3}
61 };
62
63 /**
64 * Step offsets for Cube map.
65 */
66 static const int step_offsets[6][2] = {
67 {0, 2},
68 {0, 2},
69 {-1, 2},
70 {-1, 2},
71 {-1, 1},
72 {-1, 1}
73 };
74
75 static unsigned
76 power_of_two(unsigned x)
77 {
78 unsigned value = 1;
79 while (value < x)
80 value = value << 1;
81 return value;
82 }
83
84 static unsigned
85 round_up(unsigned n, unsigned multiple)
86 {
87 return (n + multiple - 1) & ~(multiple - 1);
88 }
89
90
91 /*
92 * More advanced helper funcs
93 */
94
95
96 static void
97 i915_miptree_set_level_info(struct i915_texture *tex,
98 unsigned level,
99 unsigned nr_images,
100 unsigned w, unsigned h, unsigned d)
101 {
102 struct pipe_texture *pt = &tex->base;
103
104 assert(level < PIPE_MAX_TEXTURE_LEVELS);
105
106 pt->width[level] = w;
107 pt->height[level] = h;
108 pt->depth[level] = d;
109
110 pt->nblocksx[level] = pf_get_nblocksx(&pt->block, w);
111 pt->nblocksy[level] = pf_get_nblocksy(&pt->block, h);
112
113 tex->nr_images[level] = nr_images;
114
115 /*
116 DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
117 level, w, h, d, x, y, tex->level_offset[level]);
118 */
119
120 /* Not sure when this would happen, but anyway:
121 */
122 if (tex->image_offset[level]) {
123 FREE(tex->image_offset[level]);
124 tex->image_offset[level] = NULL;
125 }
126
127 assert(nr_images);
128 assert(!tex->image_offset[level]);
129
130 tex->image_offset[level] = (unsigned *) MALLOC(nr_images * sizeof(unsigned));
131 tex->image_offset[level][0] = 0;
132 }
133
134 static void
135 i915_miptree_set_image_offset(struct i915_texture *tex,
136 unsigned level, unsigned img, unsigned x, unsigned y)
137 {
138 if (img == 0 && level == 0)
139 assert(x == 0 && y == 0);
140
141 assert(img < tex->nr_images[level]);
142
143 tex->image_offset[level][img] = y * tex->stride + x * tex->base.block.size;
144
145 /*
146 printf("%s level %d img %d pos %d,%d image_offset %x\n",
147 __FUNCTION__, level, img, x, y, tex->image_offset[level][img]);
148 */
149 }
150
151
152 /*
153 * Layout functions
154 */
155
156
157 /**
158 * Special case to deal with scanout textures.
159 */
160 static boolean
161 i915_scanout_layout(struct i915_texture *tex)
162 {
163 struct pipe_texture *pt = &tex->base;
164
165 if (pt->last_level > 0 || pt->block.size != 4)
166 return 0;
167
168 i915_miptree_set_level_info(tex, 0, 1,
169 tex->base.width[0],
170 tex->base.height[0],
171 1);
172 i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
173
174 #if 0 /* TODO use this code when backend is smarter */
175 if (tex->base.width[0] >= 240) {
176 tex->stride = power_of_two(tex->base.nblocksx[0] * pt->block.size);
177 tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
178 #else
179 if (tex->base.width[0] >= 240) {
180 tex->stride = 2048 * 4;
181 tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
182 #endif
183 } else if (tex->base.width[0] == 64 && tex->base.height[0] == 64) {
184 tex->stride = power_of_two(tex->base.nblocksx[0] * pt->block.size);
185 tex->total_nblocksy = round_up(tex->base.nblocksy[0], 8);
186 } else {
187 return 0;
188 }
189
190 debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
191 tex->base.width[0], tex->base.height[0], pt->block.size,
192 tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
193
194 return 1;
195 }
196
197 static void
198 i945_miptree_layout_2d(struct i915_texture *tex)
199 {
200 struct pipe_texture *pt = &tex->base;
201 const int align_x = 2, align_y = 4;
202 unsigned level;
203 unsigned x = 0;
204 unsigned y = 0;
205 unsigned width = pt->width[0];
206 unsigned height = pt->height[0];
207 unsigned nblocksx = pt->nblocksx[0];
208 unsigned nblocksy = pt->nblocksy[0];
209
210 /* used for scanouts that need special layouts */
211 if (tex->base.tex_usage & PIPE_TEXTURE_USAGE_PRIMARY)
212 if (i915_scanout_layout(tex))
213 return;
214
215 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
216
217 /* May need to adjust pitch to accomodate the placement of
218 * the 2nd mipmap level. This occurs when the alignment
219 * constraints of mipmap placement push the right edge of the
220 * 2nd mipmap level out past the width of its parent.
221 */
222 if (pt->last_level > 0) {
223 unsigned mip1_nblocksx
224 = align(pf_get_nblocksx(&pt->block, minify(width)), align_x)
225 + pf_get_nblocksx(&pt->block, minify(minify(width)));
226
227 if (mip1_nblocksx > nblocksx)
228 tex->stride = mip1_nblocksx * pt->block.size;
229 }
230
231 /* Pitch must be a whole number of dwords
232 */
233 tex->stride = align(tex->stride, 64);
234 tex->total_nblocksy = 0;
235
236 for (level = 0; level <= pt->last_level; level++) {
237 i915_miptree_set_level_info(tex, level, 1, width, height, 1);
238 i915_miptree_set_image_offset(tex, level, 0, x, y);
239
240 nblocksy = align(nblocksy, align_y);
241
242 /* Because the images are packed better, the final offset
243 * might not be the maximal one:
244 */
245 tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
246
247 /* Layout_below: step right after second mipmap level.
248 */
249 if (level == 1) {
250 x += align(nblocksx, align_x);
251 }
252 else {
253 y += nblocksy;
254 }
255
256 width = minify(width);
257 height = minify(height);
258 nblocksx = pf_get_nblocksx(&pt->block, width);
259 nblocksy = pf_get_nblocksy(&pt->block, height);
260 }
261 }
262
263 static void
264 i945_miptree_layout_cube(struct i915_texture *tex)
265 {
266 struct pipe_texture *pt = &tex->base;
267 unsigned level;
268
269 const unsigned nblocks = pt->nblocksx[0];
270 unsigned face;
271 unsigned width = pt->width[0];
272 unsigned height = pt->height[0];
273
274 /*
275 printf("%s %i, %i\n", __FUNCTION__, pt->width[0], pt->height[0]);
276 */
277
278 assert(width == height); /* cubemap images are square */
279
280 /*
281 * XXX Should only be used for compressed formats. But lets
282 * keep this code active just in case.
283 *
284 * Depending on the size of the largest images, pitch can be
285 * determined either by the old-style packing of cubemap faces,
286 * or the final row of 4x4, 2x2 and 1x1 faces below this.
287 */
288 if (nblocks > 32)
289 tex->stride = round_up(nblocks * pt->block.size * 2, 4);
290 else
291 tex->stride = 14 * 8 * pt->block.size;
292
293 tex->total_nblocksy = nblocks * 4;
294
295 /* Set all the levels to effectively occupy the whole rectangular region.
296 */
297 for (level = 0; level <= pt->last_level; level++) {
298 i915_miptree_set_level_info(tex, level, 6, width, height, 1);
299 width /= 2;
300 height /= 2;
301 }
302
303 for (face = 0; face < 6; face++) {
304 unsigned x = initial_offsets[face][0] * nblocks;
305 unsigned y = initial_offsets[face][1] * nblocks;
306 unsigned d = nblocks;
307
308 #if 0 /* Fix and enable this code for compressed formats */
309 if (nblocks == 4 && face >= 4) {
310 y = tex->total_height - 4;
311 x = (face - 4) * 8;
312 }
313 else if (nblocks < 4 && (face > 0)) {
314 y = tex->total_height - 4;
315 x = face * 8;
316 }
317 #endif
318
319 for (level = 0; level <= pt->last_level; level++) {
320 i915_miptree_set_image_offset(tex, level, face, x, y);
321
322 d >>= 1;
323
324 #if 0 /* Fix and enable this code for compressed formats */
325 switch (d) {
326 case 4:
327 switch (face) {
328 case PIPE_TEX_FACE_POS_X:
329 case PIPE_TEX_FACE_NEG_X:
330 x += step_offsets[face][0] * d;
331 y += step_offsets[face][1] * d;
332 break;
333 case PIPE_TEX_FACE_POS_Y:
334 case PIPE_TEX_FACE_NEG_Y:
335 y += 12;
336 x -= 8;
337 break;
338 case PIPE_TEX_FACE_POS_Z:
339 case PIPE_TEX_FACE_NEG_Z:
340 y = tex->total_height - 4;
341 x = (face - 4) * 8;
342 break;
343 }
344 case 2:
345 y = tex->total_height - 4;
346 x = 16 + face * 8;
347 break;
348
349 case 1:
350 x += 48;
351 break;
352 default:
353 #endif
354 x += step_offsets[face][0] * d;
355 y += step_offsets[face][1] * d;
356 #if 0
357 break;
358 }
359 #endif
360 }
361 }
362 }
363
364 static boolean
365 i915_miptree_layout(struct i915_texture * tex)
366 {
367 struct pipe_texture *pt = &tex->base;
368 unsigned level;
369
370 switch (pt->target) {
371 case PIPE_TEXTURE_CUBE: {
372 const unsigned nblocks = pt->nblocksx[0];
373 unsigned face;
374 unsigned width = pt->width[0], height = pt->height[0];
375
376 assert(width == height); /* cubemap images are square */
377
378 /* double pitch for cube layouts */
379 tex->stride = round_up(nblocks * pt->block.size * 2, 4);
380 tex->total_nblocksy = nblocks * 4;
381
382 for (level = 0; level <= pt->last_level; level++) {
383 i915_miptree_set_level_info(tex, level, 6,
384 width, height,
385 1);
386 width /= 2;
387 height /= 2;
388 }
389
390 for (face = 0; face < 6; face++) {
391 unsigned x = initial_offsets[face][0] * nblocks;
392 unsigned y = initial_offsets[face][1] * nblocks;
393 unsigned d = nblocks;
394
395 for (level = 0; level <= pt->last_level; level++) {
396 i915_miptree_set_image_offset(tex, level, face, x, y);
397 d >>= 1;
398 x += step_offsets[face][0] * d;
399 y += step_offsets[face][1] * d;
400 }
401 }
402 break;
403 }
404 case PIPE_TEXTURE_3D:{
405 unsigned width = pt->width[0];
406 unsigned height = pt->height[0];
407 unsigned depth = pt->depth[0];
408 unsigned nblocksx = pt->nblocksx[0];
409 unsigned nblocksy = pt->nblocksy[0];
410 unsigned stack_nblocksy = 0;
411
412 /* Calculate the size of a single slice.
413 */
414 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
415
416 /* XXX: hardware expects/requires 9 levels at minimum.
417 */
418 for (level = 0; level <= MAX2(8, pt->last_level);
419 level++) {
420 i915_miptree_set_level_info(tex, level, depth,
421 width, height, depth);
422
423
424 stack_nblocksy += MAX2(2, nblocksy);
425
426 width = minify(width);
427 height = minify(height);
428 depth = minify(depth);
429 nblocksx = pf_get_nblocksx(&pt->block, width);
430 nblocksy = pf_get_nblocksy(&pt->block, height);
431 }
432
433 /* Fixup depth image_offsets:
434 */
435 depth = pt->depth[0];
436 for (level = 0; level <= pt->last_level; level++) {
437 unsigned i;
438 for (i = 0; i < depth; i++)
439 i915_miptree_set_image_offset(tex, level, i,
440 0, i * stack_nblocksy);
441
442 depth = minify(depth);
443 }
444
445
446 /* Multiply slice size by texture depth for total size. It's
447 * remarkable how wasteful of memory the i915 texture layouts
448 * are. They are largely fixed in the i945.
449 */
450 tex->total_nblocksy = stack_nblocksy * pt->depth[0];
451 break;
452 }
453
454 default:{
455 unsigned width = pt->width[0];
456 unsigned height = pt->height[0];
457 unsigned nblocksx = pt->nblocksx[0];
458 unsigned nblocksy = pt->nblocksy[0];
459
460 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
461 tex->total_nblocksy = 0;
462
463 for (level = 0; level <= pt->last_level; level++) {
464 i915_miptree_set_level_info(tex, level, 1,
465 width, height, 1);
466 i915_miptree_set_image_offset(tex, level, 0,
467 0, tex->total_nblocksy);
468
469 nblocksy = round_up(MAX2(2, nblocksy), 2);
470
471 tex->total_nblocksy += nblocksy;
472
473 width = minify(width);
474 height = minify(height);
475 nblocksx = pf_get_nblocksx(&pt->block, width);
476 nblocksy = pf_get_nblocksy(&pt->block, height);
477 }
478 break;
479 }
480 }
481 /*
482 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
483 tex->pitch,
484 tex->total_nblocksy, pt->block.size, tex->stride * tex->total_nblocksy);
485 */
486
487 return TRUE;
488 }
489
490
491 static boolean
492 i945_miptree_layout(struct i915_texture * tex)
493 {
494 struct pipe_texture *pt = &tex->base;
495 unsigned level;
496
497 switch (pt->target) {
498 case PIPE_TEXTURE_CUBE:
499 i945_miptree_layout_cube(tex);
500 break;
501 case PIPE_TEXTURE_3D:{
502 unsigned width = pt->width[0];
503 unsigned height = pt->height[0];
504 unsigned depth = pt->depth[0];
505 unsigned nblocksx = pt->nblocksx[0];
506 unsigned nblocksy = pt->nblocksy[0];
507 unsigned pack_x_pitch, pack_x_nr;
508 unsigned pack_y_pitch;
509
510 tex->stride = round_up(pt->nblocksx[0] * pt->block.size, 4);
511 tex->total_nblocksy = 0;
512
513 pack_y_pitch = MAX2(pt->nblocksy[0], 2);
514 pack_x_pitch = tex->stride / pt->block.size;
515 pack_x_nr = 1;
516
517 for (level = 0; level <= pt->last_level; level++) {
518 unsigned nr_images = pt->target == PIPE_TEXTURE_3D ? depth : 6;
519 int x = 0;
520 int y = 0;
521 unsigned q, j;
522
523 i915_miptree_set_level_info(tex, level, nr_images,
524 width, height, depth);
525
526 for (q = 0; q < nr_images;) {
527 for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
528 i915_miptree_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
529 x += pack_x_pitch;
530 }
531
532 x = 0;
533 y += pack_y_pitch;
534 }
535
536
537 tex->total_nblocksy += y;
538
539 if (pack_x_pitch > 4) {
540 pack_x_pitch >>= 1;
541 pack_x_nr <<= 1;
542 assert(pack_x_pitch * pack_x_nr * pt->block.size <= tex->stride);
543 }
544
545 if (pack_y_pitch > 2) {
546 pack_y_pitch >>= 1;
547 }
548
549 width = minify(width);
550 height = minify(height);
551 depth = minify(depth);
552 nblocksx = pf_get_nblocksx(&pt->block, width);
553 nblocksy = pf_get_nblocksy(&pt->block, height);
554 }
555 break;
556 }
557
558 case PIPE_TEXTURE_1D:
559 case PIPE_TEXTURE_2D:
560 // case PIPE_TEXTURE_RECTANGLE:
561 i945_miptree_layout_2d(tex);
562 break;
563 default:
564 assert(0);
565 return FALSE;
566 }
567
568 /*
569 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
570 tex->pitch,
571 tex->total_nblocksy, pt->block.size, tex->stride * tex->total_nblocksy);
572 */
573
574 return TRUE;
575 }
576
577
578 static struct pipe_texture *
579 i915_texture_create(struct pipe_screen *screen,
580 const struct pipe_texture *templat)
581 {
582 struct i915_screen *i915screen = i915_screen(screen);
583 struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
584 size_t tex_size;
585 unsigned buf_usage = 0;
586
587 if (!tex)
588 return NULL;
589
590 tex->base = *templat;
591 pipe_reference_init(&tex->base.reference, 1);
592 tex->base.screen = screen;
593
594 tex->base.nblocksx[0] = pf_get_nblocksx(&tex->base.block, tex->base.width[0]);
595 tex->base.nblocksy[0] = pf_get_nblocksy(&tex->base.block, tex->base.height[0]);
596
597 if (i915screen->is_i945) {
598 if (!i945_miptree_layout(tex))
599 goto fail;
600 } else {
601 if (!i915_miptree_layout(tex))
602 goto fail;
603 }
604
605 tex_size = tex->stride * tex->total_nblocksy;
606
607 buf_usage = PIPE_BUFFER_USAGE_PIXEL;
608
609 /* for scanouts and cursors, cursors don't have the scanout tag */
610 if (templat->tex_usage & PIPE_TEXTURE_USAGE_PRIMARY && templat->width[0] != 64)
611 buf_usage |= I915_BUFFER_USAGE_SCANOUT;
612
613 tex->buffer = screen->buffer_create(screen, 64, buf_usage, tex_size);
614
615 if (!tex->buffer)
616 goto fail;
617
618 #if 0
619 void *ptr = ws->buffer_map(ws, tex->buffer,
620 PIPE_BUFFER_USAGE_CPU_WRITE);
621 memset(ptr, 0x80, tex_size);
622 ws->buffer_unmap(ws, tex->buffer);
623 #endif
624
625 return &tex->base;
626
627 fail:
628 FREE(tex);
629 return NULL;
630 }
631
632
633 static void
634 i915_texture_destroy(struct pipe_texture *pt)
635 {
636 struct i915_texture *tex = (struct i915_texture *)pt;
637 uint i;
638
639 /*
640 DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
641 */
642
643 pipe_buffer_reference(&tex->buffer, NULL);
644
645 for (i = 0; i < PIPE_MAX_TEXTURE_LEVELS; i++)
646 if (tex->image_offset[i])
647 FREE(tex->image_offset[i]);
648
649 FREE(tex);
650 }
651
652 static struct pipe_surface *
653 i915_get_tex_surface(struct pipe_screen *screen,
654 struct pipe_texture *pt,
655 unsigned face, unsigned level, unsigned zslice,
656 unsigned flags)
657 {
658 struct i915_texture *tex = (struct i915_texture *)pt;
659 struct pipe_surface *ps;
660 unsigned offset; /* in bytes */
661
662 if (pt->target == PIPE_TEXTURE_CUBE) {
663 offset = tex->image_offset[level][face];
664 }
665 else if (pt->target == PIPE_TEXTURE_3D) {
666 offset = tex->image_offset[level][zslice];
667 }
668 else {
669 offset = tex->image_offset[level][0];
670 assert(face == 0);
671 assert(zslice == 0);
672 }
673
674 ps = CALLOC_STRUCT(pipe_surface);
675 if (ps) {
676 pipe_reference_init(&ps->reference, 1);
677 pipe_texture_reference(&ps->texture, pt);
678 ps->format = pt->format;
679 ps->width = pt->width[level];
680 ps->height = pt->height[level];
681 ps->offset = offset;
682 ps->usage = flags;
683 }
684 return ps;
685 }
686
687 static struct pipe_texture *
688 i915_texture_blanket(struct pipe_screen * screen,
689 const struct pipe_texture *base,
690 const unsigned *stride,
691 struct pipe_buffer *buffer)
692 {
693 struct i915_texture *tex;
694 assert(screen);
695
696 /* Only supports one type */
697 if (base->target != PIPE_TEXTURE_2D ||
698 base->last_level != 0 ||
699 base->depth[0] != 1) {
700 return NULL;
701 }
702
703 tex = CALLOC_STRUCT(i915_texture);
704 if (!tex)
705 return NULL;
706
707 tex->base = *base;
708 pipe_reference_init(&tex->base.reference, 1);
709 tex->base.screen = screen;
710
711 tex->stride = stride[0];
712
713 i915_miptree_set_level_info(tex, 0, 1, base->width[0], base->height[0], 1);
714 i915_miptree_set_image_offset(tex, 0, 0, 0, 0);
715
716 pipe_buffer_reference(&tex->buffer, buffer);
717
718 return &tex->base;
719 }
720
721 static void
722 i915_tex_surface_destroy(struct pipe_surface *surf)
723 {
724 pipe_texture_reference(&surf->texture, NULL);
725 FREE(surf);
726 }
727
728 void
729 i915_init_screen_texture_functions(struct i915_screen *is)
730 {
731 is->base.texture_create = i915_texture_create;
732 is->base.texture_destroy = i915_texture_destroy;
733 is->base.get_tex_surface = i915_get_tex_surface;
734 is->base.texture_blanket = i915_texture_blanket;
735 is->base.tex_surface_destroy = i915_tex_surface_destroy;
736 }
737
738 boolean i915_get_texture_buffer(struct pipe_texture *texture,
739 struct pipe_buffer **buf,
740 unsigned *stride)
741 {
742 struct i915_texture *tex = (struct i915_texture *)texture;
743
744 if (!tex)
745 return FALSE;
746
747 pipe_buffer_reference(buf, tex->buffer);
748
749 if (stride)
750 *stride = tex->stride;
751
752 return TRUE;
753 }