d44a2f47b3731fd0390fec8401429d9abe1edc4c
[mesa.git] / src / mesa / drivers / dri / i915 / i915_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 /** @file i915_tex_layout.c
29 * Code to layout images in a mipmap tree for i830M-GM915 and G945 and beyond.
30 */
31
32 #include "intel_mipmap_tree.h"
33 #include "intel_tex_layout.h"
34 #include "main/macros.h"
35 #include "intel_context.h"
36
37 #define FILE_DEBUG_FLAG DEBUG_TEXTURE
38
39 static GLint initial_offsets[6][2] = {
40 [FACE_POS_X] = {0, 0},
41 [FACE_POS_Y] = {1, 0},
42 [FACE_POS_Z] = {1, 1},
43 [FACE_NEG_X] = {0, 2},
44 [FACE_NEG_Y] = {1, 2},
45 [FACE_NEG_Z] = {1, 3},
46 };
47
48
49 static GLint step_offsets[6][2] = {
50 [FACE_POS_X] = {0, 2},
51 [FACE_POS_Y] = {-1, 2},
52 [FACE_POS_Z] = {-1, 1},
53 [FACE_NEG_X] = {0, 2},
54 [FACE_NEG_Y] = {-1, 2},
55 [FACE_NEG_Z] = {-1, 1},
56 };
57
58 /**
59 * Cube texture map layout for i830M-GM915.
60 *
61 * Hardware layout looks like:
62 *
63 * +-------+-------+
64 * | | |
65 * | | |
66 * | | |
67 * | +x | +y |
68 * | | |
69 * | | |
70 * | | |
71 * | | |
72 * +---+---+-------+
73 * | | | |
74 * | +x| +y| |
75 * | | | |
76 * | | | |
77 * +-+-+---+ +z |
78 * | | | | |
79 * +-+-+ +z| |
80 * | | | |
81 * +-+-+---+-------+
82 * | | |
83 * | | |
84 * | | |
85 * | -x | -y |
86 * | | |
87 * | | |
88 * | | |
89 * | | |
90 * +---+---+-------+
91 * | | | |
92 * | -x| -y| |
93 * | | | |
94 * | | | |
95 * +-+-+---+ -z |
96 * | | | | |
97 * +-+-+ -z| |
98 * | | | |
99 * +-+---+-------+
100 *
101 */
102 static void
103 i915_miptree_layout_cube(struct intel_context *intel,
104 struct intel_mipmap_tree * mt)
105 {
106 const GLuint dim = mt->width0;
107 GLuint face;
108 GLuint lvlWidth = mt->width0, lvlHeight = mt->height0;
109 GLint level;
110
111 assert(lvlWidth == lvlHeight); /* cubemap images are square */
112
113 /* double pitch for cube layouts */
114 mt->pitch = intel_miptree_pitch_align (intel, mt, dim * 2);
115 mt->total_height = dim * 4;
116
117 for (level = mt->first_level; level <= mt->last_level; level++) {
118 intel_miptree_set_level_info(mt, level, 6,
119 0, 0,
120 /*OLD: mt->pitch, mt->total_height,*/
121 lvlWidth, lvlHeight,
122 1);
123 lvlWidth /= 2;
124 lvlHeight /= 2;
125 }
126
127 for (face = 0; face < 6; face++) {
128 GLuint x = initial_offsets[face][0] * dim;
129 GLuint y = initial_offsets[face][1] * dim;
130 GLuint d = dim;
131
132 for (level = mt->first_level; level <= mt->last_level; level++) {
133 intel_miptree_set_image_offset(mt, level, face, x, y);
134
135 if (d == 0)
136 _mesa_printf("cube mipmap %d/%d (%d..%d) is 0x0\n",
137 face, level, mt->first_level, mt->last_level);
138
139 d >>= 1;
140 x += step_offsets[face][0] * d;
141 y += step_offsets[face][1] * d;
142 }
143 }
144 }
145
146 static void
147 i915_miptree_layout_3d(struct intel_context *intel,
148 struct intel_mipmap_tree * mt)
149 {
150 GLuint width = mt->width0;
151 GLuint height = mt->height0;
152 GLuint depth = mt->depth0;
153 GLuint stack_height = 0;
154 GLint level;
155
156 /* Calculate the size of a single slice. */
157 mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0);
158
159 /* XXX: hardware expects/requires 9 levels at minimum. */
160 for (level = mt->first_level; level <= MAX2(8, mt->last_level); level++) {
161 intel_miptree_set_level_info(mt, level, depth, 0, mt->total_height,
162 width, height, depth);
163
164 stack_height += MAX2(2, height);
165
166 width = minify(width);
167 height = minify(height);
168 depth = minify(depth);
169 }
170
171 /* Fixup depth image_offsets: */
172 depth = mt->depth0;
173 for (level = mt->first_level; level <= mt->last_level; level++) {
174 GLuint i;
175 for (i = 0; i < depth; i++) {
176 intel_miptree_set_image_offset(mt, level, i,
177 0, i * stack_height);
178 }
179
180 depth = minify(depth);
181 }
182
183 /* Multiply slice size by texture depth for total size. It's
184 * remarkable how wasteful of memory the i915 texture layouts
185 * are. They are largely fixed in the i945.
186 */
187 mt->total_height = stack_height * mt->depth0;
188 }
189
190 static void
191 i915_miptree_layout_2d(struct intel_context *intel,
192 struct intel_mipmap_tree * mt)
193 {
194 GLuint width = mt->width0;
195 GLuint height = mt->height0;
196 GLuint img_height;
197 GLint level;
198
199 mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0);
200 mt->total_height = 0;
201
202 for (level = mt->first_level; level <= mt->last_level; level++) {
203 intel_miptree_set_level_info(mt, level, 1,
204 0, mt->total_height,
205 width, height, 1);
206
207 if (mt->compressed)
208 img_height = MAX2(1, height / 4);
209 else
210 img_height = (MAX2(2, height) + 1) & ~1;
211
212 mt->total_height += img_height;
213
214 width = minify(width);
215 height = minify(height);
216 }
217 }
218
219 GLboolean
220 i915_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree * mt)
221 {
222 switch (mt->target) {
223 case GL_TEXTURE_CUBE_MAP:
224 i915_miptree_layout_cube(intel, mt);
225 break;
226 case GL_TEXTURE_3D:
227 i915_miptree_layout_3d(intel, mt);
228 break;
229 case GL_TEXTURE_1D:
230 case GL_TEXTURE_2D:
231 case GL_TEXTURE_RECTANGLE_ARB:
232 i915_miptree_layout_2d(intel, mt);
233 break;
234 default:
235 _mesa_problem(NULL, "Unexpected tex target in i915_miptree_layout()");
236 break;
237 }
238
239 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
240 mt->pitch,
241 mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp);
242
243 return GL_TRUE;
244 }
245
246
247 /**
248 * Cube texture map layout for GM945 and later.
249 *
250 * The hardware layout looks like the 830-915 layout, except for the small
251 * sizes. A zoomed in view of the layout for 945 is:
252 *
253 * +-------+-------+
254 * | 8x8 | 8x8 |
255 * | | |
256 * | | |
257 * | +x | +y |
258 * | | |
259 * | | |
260 * | | |
261 * | | |
262 * +---+---+-------+
263 * |4x4| | 8x8 |
264 * | +x| | |
265 * | | | |
266 * | | | |
267 * +---+ | +z |
268 * |4x4| | |
269 * | +y| | |
270 * | | | |
271 * +---+ +-------+
272 *
273 * ...
274 *
275 * +-------+-------+
276 * | 8x8 | 8x8 |
277 * | | |
278 * | | |
279 * | -x | -y |
280 * | | |
281 * | | |
282 * | | |
283 * | | |
284 * +---+---+-------+
285 * |4x4| | 8x8 |
286 * | -x| | |
287 * | | | |
288 * | | | |
289 * +---+ | -z |
290 * |4x4| | |
291 * | -y| | |
292 * | | | |
293 * +---+ +---+---+---+---+---+---+---+---+---+
294 * |4x4| |4x4| |2x2| |2x2| |2x2| |2x2|
295 * | +z| | -z| | +x| | +y| | +z| | -x| ...
296 * | | | | | | | | | | | |
297 * +---+ +---+ +---+ +---+ +---+ +---+
298 *
299 * The bottom row continues with the remaining 2x2 then the 1x1 mip contents
300 * in order, with each of them aligned to a 4x4 block boundary. Thus, for
301 * 32x32 cube maps and smaller, the bottom row layout is going to dictate the
302 * pitch of the tree. For a tree with 4x4 images, the pitch is at least
303 * 14 * 8 = 112 texels, for 2x2 it is at least 12 * 8 texels, and for 1x1
304 * it is 6 * 8 texels.
305 */
306
307 static void
308 i945_miptree_layout_cube(struct intel_context *intel,
309 struct intel_mipmap_tree * mt)
310 {
311 const GLuint dim = mt->width0;
312 GLuint face;
313 GLuint lvlWidth = mt->width0, lvlHeight = mt->height0;
314 GLint level;
315
316 assert(lvlWidth == lvlHeight); /* cubemap images are square */
317
318 /* Depending on the size of the largest images, pitch can be
319 * determined either by the old-style packing of cubemap faces,
320 * or the final row of 4x4, 2x2 and 1x1 faces below this.
321 */
322 if (dim > 32)
323 mt->pitch = intel_miptree_pitch_align (intel, mt, dim * 2);
324 else
325 mt->pitch = intel_miptree_pitch_align (intel, mt, 14 * 8);
326
327 if (dim >= 4)
328 mt->total_height = dim * 4 + 4;
329 else
330 mt->total_height = 4;
331
332 /* Set all the levels to effectively occupy the whole rectangular region. */
333 for (level = mt->first_level; level <= mt->last_level; level++) {
334 intel_miptree_set_level_info(mt, level, 6,
335 0, 0,
336 lvlWidth, lvlHeight, 1);
337 lvlWidth /= 2;
338 lvlHeight /= 2;
339 }
340
341 for (face = 0; face < 6; face++) {
342 GLuint x = initial_offsets[face][0] * dim;
343 GLuint y = initial_offsets[face][1] * dim;
344 GLuint d = dim;
345
346 if (dim == 4 && face >= 4) {
347 y = mt->total_height - 4;
348 x = (face - 4) * 8;
349 } else if (dim < 4 && (face > 0 || mt->first_level > 0)) {
350 y = mt->total_height - 4;
351 x = face * 8;
352 }
353
354 for (level = mt->first_level; level <= mt->last_level; level++) {
355 intel_miptree_set_image_offset(mt, level, face, x, y);
356
357 d >>= 1;
358
359 switch (d) {
360 case 4:
361 switch (face) {
362 case FACE_POS_X:
363 case FACE_NEG_X:
364 x += step_offsets[face][0] * d;
365 y += step_offsets[face][1] * d;
366 break;
367 case FACE_POS_Y:
368 case FACE_NEG_Y:
369 y += 12;
370 x -= 8;
371 break;
372 case FACE_POS_Z:
373 case FACE_NEG_Z:
374 y = mt->total_height - 4;
375 x = (face - 4) * 8;
376 break;
377 }
378
379 case 2:
380 y = mt->total_height - 4;
381 x = 16 + face * 8;
382 break;
383
384 case 1:
385 x += 48;
386 break;
387
388 default:
389 x += step_offsets[face][0] * d;
390 y += step_offsets[face][1] * d;
391 break;
392 }
393 }
394 }
395 }
396
397 static void
398 i945_miptree_layout_3d(struct intel_context *intel,
399 struct intel_mipmap_tree * mt)
400 {
401 GLuint width = mt->width0;
402 GLuint height = mt->height0;
403 GLuint depth = mt->depth0;
404 GLuint pack_x_pitch, pack_x_nr;
405 GLuint pack_y_pitch;
406 GLuint level;
407
408 mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0);
409 mt->total_height = 0;
410
411 pack_y_pitch = MAX2(mt->height0, 2);
412 pack_x_pitch = mt->pitch;
413 pack_x_nr = 1;
414
415 for (level = mt->first_level; level <= mt->last_level; level++) {
416 GLint x = 0;
417 GLint y = 0;
418 GLint q, j;
419
420 intel_miptree_set_level_info(mt, level, depth,
421 0, mt->total_height,
422 width, height, depth);
423
424 for (q = 0; q < depth;) {
425 for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
426 intel_miptree_set_image_offset(mt, level, q, x, y);
427 x += pack_x_pitch;
428 }
429
430 x = 0;
431 y += pack_y_pitch;
432 }
433
434 mt->total_height += y;
435
436 if (pack_x_pitch > 4) {
437 pack_x_pitch >>= 1;
438 pack_x_nr <<= 1;
439 assert(pack_x_pitch * pack_x_nr <= mt->pitch);
440 }
441
442 if (pack_y_pitch > 2) {
443 pack_y_pitch >>= 1;
444 }
445
446 width = minify(width);
447 height = minify(height);
448 depth = minify(depth);
449 }
450 }
451
452 GLboolean
453 i945_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree * mt)
454 {
455 switch (mt->target) {
456 case GL_TEXTURE_CUBE_MAP:
457 i945_miptree_layout_cube(intel, mt);
458 break;
459 case GL_TEXTURE_3D:
460 i945_miptree_layout_3d(intel, mt);
461 break;
462 case GL_TEXTURE_1D:
463 case GL_TEXTURE_2D:
464 case GL_TEXTURE_RECTANGLE_ARB:
465 i945_miptree_layout_2d(intel, mt);
466 break;
467 default:
468 _mesa_problem(NULL, "Unexpected tex target in i945_miptree_layout()");
469 break;
470 }
471
472 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
473 mt->pitch,
474 mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp);
475
476 return GL_TRUE;
477 }