Checkpoint lifting of intel_mipmap_tree (intel_mipmap_tree -> pipe_mipmap_tree and...
[mesa.git] / src / mesa / drivers / dri / intel / intel_tex_layout.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 "macros.h"
34 #include "pipe/p_state.h"
35 #include "intel_mipmap_tree.h"
36
37
38 static GLuint minify( GLuint d )
39 {
40 return MAX2(1, d>>1);
41 }
42
43 static int align(int value, int alignment)
44 {
45 return (value + alignment - 1) & ~(alignment - 1);
46 }
47
48
49 static void
50 mipmaptree_set_level_info(struct pipe_mipmap_tree *mt,
51 GLuint level,
52 GLuint nr_images,
53 GLuint x, GLuint y, GLuint w, GLuint h, GLuint d)
54 {
55 assert(level < MAX_TEXTURE_LEVELS);
56
57 mt->level[level].width = w;
58 mt->level[level].height = h;
59 mt->level[level].depth = d;
60 mt->level[level].level_offset = (x + y * mt->pitch) * mt->cpp;
61 mt->level[level].nr_images = nr_images;
62
63 /*
64 DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
65 level, w, h, d, x, y, mt->level[level].level_offset);
66 */
67
68 /* Not sure when this would happen, but anyway:
69 */
70 if (mt->level[level].image_offset) {
71 free(mt->level[level].image_offset);
72 mt->level[level].image_offset = NULL;
73 }
74
75 assert(nr_images);
76
77 mt->level[level].image_offset = malloc(nr_images * sizeof(GLuint));
78 mt->level[level].image_offset[0] = 0;
79 }
80
81
82 static void
83 i945_miptree_layout_2d( struct pipe_mipmap_tree *mt )
84 {
85 GLint align_h = 2, align_w = 4;
86 GLuint level;
87 GLuint x = 0;
88 GLuint y = 0;
89 GLuint width = mt->width0;
90 GLuint height = mt->height0;
91
92 mt->pitch = mt->width0;
93
94 /* May need to adjust pitch to accomodate the placement of
95 * the 2nd mipmap. This occurs when the alignment
96 * constraints of mipmap placement push the right edge of the
97 * 2nd mipmap out past the width of its parent.
98 */
99 if (mt->first_level != mt->last_level) {
100 GLuint mip1_width = align(minify(mt->width0), align_w)
101 + minify(minify(mt->width0));
102
103 if (mip1_width > mt->width0)
104 mt->pitch = mip1_width;
105 }
106
107 /* Pitch must be a whole number of dwords, even though we
108 * express it in texels.
109 */
110 mt->pitch = align(mt->pitch * mt->cpp, 4) / mt->cpp;
111 mt->total_height = 0;
112
113 for ( level = mt->first_level ; level <= mt->last_level ; level++ ) {
114 GLuint img_height;
115
116 mipmaptree_set_level_info(mt, level, 1, x, y, width, height, 1);
117
118 if (mt->compressed)
119 img_height = MAX2(1, height/4);
120 else
121 img_height = align(height, align_h);
122
123
124 /* Because the images are packed better, the final offset
125 * might not be the maximal one:
126 */
127 mt->total_height = MAX2(mt->total_height, y + img_height);
128
129 /* Layout_below: step right after second mipmap.
130 */
131 if (level == mt->first_level + 1) {
132 x += align(width, align_w);
133 }
134 else {
135 y += img_height;
136 }
137
138 width = minify(width);
139 height = minify(height);
140 }
141 }
142
143
144 static const GLint initial_offsets[6][2] = {
145 {0, 0},
146 {0, 2},
147 {1, 0},
148 {1, 2},
149 {1, 1},
150 {1, 3}
151 };
152
153 static const GLint step_offsets[6][2] = {
154 {0, 2},
155 {0, 2},
156 {-1, 2},
157 {-1, 2},
158 {-1, 1},
159 {-1, 1}
160 };
161
162
163 GLboolean
164 i915_miptree_layout(struct pipe_context *pipe, struct pipe_mipmap_tree * mt)
165 {
166 GLint level;
167
168 switch (mt->target) {
169 case GL_TEXTURE_CUBE_MAP:{
170 const GLuint dim = mt->width0;
171 GLuint face;
172 GLuint lvlWidth = mt->width0, lvlHeight = mt->height0;
173
174 assert(lvlWidth == lvlHeight); /* cubemap images are square */
175
176 /* double pitch for cube layouts */
177 mt->pitch = ((dim * mt->cpp * 2 + 3) & ~3) / mt->cpp;
178 mt->total_height = dim * 4;
179
180 for (level = mt->first_level; level <= mt->last_level; level++) {
181 intel_miptree_set_level_info(mt, level, 6,
182 0, 0,
183 /*OLD: mt->pitch, mt->total_height,*/
184 lvlWidth, lvlHeight,
185 1);
186 lvlWidth /= 2;
187 lvlHeight /= 2;
188 }
189
190 for (face = 0; face < 6; face++) {
191 GLuint x = initial_offsets[face][0] * dim;
192 GLuint y = initial_offsets[face][1] * dim;
193 GLuint d = dim;
194
195 for (level = mt->first_level; level <= mt->last_level; level++) {
196 intel_miptree_set_image_offset(mt, level, face, x, y);
197
198 if (d == 0)
199 _mesa_printf("cube mipmap %d/%d (%d..%d) is 0x0\n",
200 face, level, mt->first_level, mt->last_level);
201
202 d >>= 1;
203 x += step_offsets[face][0] * d;
204 y += step_offsets[face][1] * d;
205 }
206 }
207 break;
208 }
209 case GL_TEXTURE_3D:{
210 GLuint width = mt->width0;
211 GLuint height = mt->height0;
212 GLuint depth = mt->depth0;
213 GLuint stack_height = 0;
214
215 /* Calculate the size of a single slice.
216 */
217 mt->pitch = ((mt->width0 * mt->cpp + 3) & ~3) / mt->cpp;
218
219 /* XXX: hardware expects/requires 9 levels at minimum.
220 */
221 for (level = mt->first_level; level <= MAX2(8, mt->last_level);
222 level++) {
223 intel_miptree_set_level_info(mt, level, depth, 0, mt->total_height,
224 width, height, depth);
225
226
227 stack_height += MAX2(2, height);
228
229 width = minify(width);
230 height = minify(height);
231 depth = minify(depth);
232 }
233
234 /* Fixup depth image_offsets:
235 */
236 depth = mt->depth0;
237 for (level = mt->first_level; level <= mt->last_level; level++) {
238 GLuint i;
239 for (i = 0; i < depth; i++)
240 intel_miptree_set_image_offset(mt, level, i,
241 0, i * stack_height);
242
243 depth = minify(depth);
244 }
245
246
247 /* Multiply slice size by texture depth for total size. It's
248 * remarkable how wasteful of memory the i915 texture layouts
249 * are. They are largely fixed in the i945.
250 */
251 mt->total_height = stack_height * mt->depth0;
252 break;
253 }
254
255 default:{
256 GLuint width = mt->width0;
257 GLuint height = mt->height0;
258 GLuint img_height;
259
260 mt->pitch = ((mt->width0 * mt->cpp + 3) & ~3) / mt->cpp;
261 mt->total_height = 0;
262
263 for (level = mt->first_level; level <= mt->last_level; level++) {
264 intel_miptree_set_level_info(mt, level, 1,
265 0, mt->total_height,
266 width, height, 1);
267
268 if (mt->compressed)
269 img_height = MAX2(1, height / 4);
270 else
271 img_height = (MAX2(2, height) + 1) & ~1;
272
273 mt->total_height += img_height;
274
275 width = minify(width);
276 height = minify(height);
277 }
278 break;
279 }
280 }
281 /*
282 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
283 mt->pitch,
284 mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp);
285 */
286
287 return GL_TRUE;
288 }
289
290
291 GLboolean
292 i945_miptree_layout(struct pipe_context *pipe, struct pipe_mipmap_tree * mt)
293 {
294 GLint level;
295
296 switch (mt->target) {
297 case GL_TEXTURE_CUBE_MAP:{
298 const GLuint dim = mt->width0;
299 GLuint face;
300 GLuint lvlWidth = mt->width0, lvlHeight = mt->height0;
301
302 assert(lvlWidth == lvlHeight); /* cubemap images are square */
303
304 /* Depending on the size of the largest images, pitch can be
305 * determined either by the old-style packing of cubemap faces,
306 * or the final row of 4x4, 2x2 and 1x1 faces below this.
307 */
308 if (dim > 32)
309 mt->pitch = ((dim * mt->cpp * 2 + 3) & ~3) / mt->cpp;
310 else
311 mt->pitch = 14 * 8;
312
313 mt->total_height = dim * 4 + 4;
314
315 /* Set all the levels to effectively occupy the whole rectangular region.
316 */
317 for (level = mt->first_level; level <= mt->last_level; level++) {
318 intel_miptree_set_level_info(mt, level, 6,
319 0, 0,
320 lvlWidth, lvlHeight, 1);
321 lvlWidth /= 2;
322 lvlHeight /= 2;
323 }
324
325
326 for (face = 0; face < 6; face++) {
327 GLuint x = initial_offsets[face][0] * dim;
328 GLuint y = initial_offsets[face][1] * dim;
329 GLuint d = dim;
330
331 if (dim == 4 && face >= 4) {
332 y = mt->total_height - 4;
333 x = (face - 4) * 8;
334 }
335 else if (dim < 4 && (face > 0 || mt->first_level > 0)) {
336 y = mt->total_height - 4;
337 x = face * 8;
338 }
339
340 for (level = mt->first_level; level <= mt->last_level; level++) {
341 intel_miptree_set_image_offset(mt, level, face, x, y);
342
343 d >>= 1;
344
345 switch (d) {
346 case 4:
347 switch (face) {
348 case FACE_POS_X:
349 case FACE_NEG_X:
350 x += step_offsets[face][0] * d;
351 y += step_offsets[face][1] * d;
352 break;
353 case FACE_POS_Y:
354 case FACE_NEG_Y:
355 y += 12;
356 x -= 8;
357 break;
358 case FACE_POS_Z:
359 case FACE_NEG_Z:
360 y = mt->total_height - 4;
361 x = (face - 4) * 8;
362 break;
363 }
364
365 case 2:
366 y = mt->total_height - 4;
367 x = 16 + face * 8;
368 break;
369
370 case 1:
371 x += 48;
372 break;
373
374 default:
375 x += step_offsets[face][0] * d;
376 y += step_offsets[face][1] * d;
377 break;
378 }
379 }
380 }
381 break;
382 }
383 case GL_TEXTURE_3D:{
384 GLuint width = mt->width0;
385 GLuint height = mt->height0;
386 GLuint depth = mt->depth0;
387 GLuint pack_x_pitch, pack_x_nr;
388 GLuint pack_y_pitch;
389 GLuint level;
390
391 mt->pitch = ((mt->width0 * mt->cpp + 3) & ~3) / mt->cpp;
392 mt->total_height = 0;
393
394 pack_y_pitch = MAX2(mt->height0, 2);
395 pack_x_pitch = mt->pitch;
396 pack_x_nr = 1;
397
398 for (level = mt->first_level; level <= mt->last_level; level++) {
399 GLuint nr_images = mt->target == GL_TEXTURE_3D ? depth : 6;
400 GLint x = 0;
401 GLint y = 0;
402 GLint q, j;
403
404 intel_miptree_set_level_info(mt, level, nr_images,
405 0, mt->total_height,
406 width, height, depth);
407
408 for (q = 0; q < nr_images;) {
409 for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
410 intel_miptree_set_image_offset(mt, level, q, x, y);
411 x += pack_x_pitch;
412 }
413
414 x = 0;
415 y += pack_y_pitch;
416 }
417
418
419 mt->total_height += y;
420
421 if (pack_x_pitch > 4) {
422 pack_x_pitch >>= 1;
423 pack_x_nr <<= 1;
424 assert(pack_x_pitch * pack_x_nr <= mt->pitch);
425 }
426
427 if (pack_y_pitch > 2) {
428 pack_y_pitch >>= 1;
429 }
430
431 width = minify(width);
432 height = minify(height);
433 depth = minify(depth);
434 }
435 break;
436 }
437
438 case GL_TEXTURE_1D:
439 case GL_TEXTURE_2D:
440 case GL_TEXTURE_RECTANGLE_ARB:
441 i945_miptree_layout_2d(mt);
442 break;
443 default:
444 _mesa_problem(NULL, "Unexpected tex target in i945_miptree_layout()");
445 }
446
447 /*
448 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
449 mt->pitch,
450 mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp);
451 */
452
453 return GL_TRUE;
454 }