[Intel] Centralize mipmap pitch computations.
[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 /* Code to layout images in a mipmap tree for i915 and i945
29 * respectively.
30 */
31
32 #include "intel_mipmap_tree.h"
33 #include "intel_tex_layout.h"
34 #include "macros.h"
35 #include "intel_context.h"
36
37 #define FILE_DEBUG_FLAG DEBUG_TEXTURE
38
39 static GLint initial_offsets[6][2] = { {0, 0},
40 {0, 2},
41 {1, 0},
42 {1, 2},
43 {1, 1},
44 {1, 3}
45 };
46
47
48 static GLint step_offsets[6][2] = { {0, 2},
49 {0, 2},
50 {-1, 2},
51 {-1, 2},
52 {-1, 1},
53 {-1, 1}
54 };
55
56 GLboolean
57 i915_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree * mt)
58 {
59 GLint level;
60
61 switch (mt->target) {
62 case GL_TEXTURE_CUBE_MAP:{
63 const GLuint dim = mt->width0;
64 GLuint face;
65 GLuint lvlWidth = mt->width0, lvlHeight = mt->height0;
66
67 assert(lvlWidth == lvlHeight); /* cubemap images are square */
68
69 /* double pitch for cube layouts */
70 mt->pitch = intel_miptree_pitch_align (intel, mt, dim * 2);
71 mt->total_height = dim * 4;
72
73 for (level = mt->first_level; level <= mt->last_level; level++) {
74 intel_miptree_set_level_info(mt, level, 6,
75 0, 0,
76 /*OLD: mt->pitch, mt->total_height,*/
77 lvlWidth, lvlHeight,
78 1);
79 lvlWidth /= 2;
80 lvlHeight /= 2;
81 }
82
83 for (face = 0; face < 6; face++) {
84 GLuint x = initial_offsets[face][0] * dim;
85 GLuint y = initial_offsets[face][1] * dim;
86 GLuint d = dim;
87
88 for (level = mt->first_level; level <= mt->last_level; level++) {
89 intel_miptree_set_image_offset(mt, level, face, x, y);
90
91 if (d == 0)
92 _mesa_printf("cube mipmap %d/%d (%d..%d) is 0x0\n",
93 face, level, mt->first_level, mt->last_level);
94
95 d >>= 1;
96 x += step_offsets[face][0] * d;
97 y += step_offsets[face][1] * d;
98 }
99 }
100 break;
101 }
102 case GL_TEXTURE_3D:{
103 GLuint width = mt->width0;
104 GLuint height = mt->height0;
105 GLuint depth = mt->depth0;
106 GLuint stack_height = 0;
107
108 /* Calculate the size of a single slice.
109 */
110 mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0);
111
112 /* XXX: hardware expects/requires 9 levels at minimum.
113 */
114 for (level = mt->first_level; level <= MAX2(8, mt->last_level);
115 level++) {
116 intel_miptree_set_level_info(mt, level, depth, 0, mt->total_height,
117 width, height, depth);
118
119
120 stack_height += MAX2(2, height);
121
122 width = minify(width);
123 height = minify(height);
124 depth = minify(depth);
125 }
126
127 /* Fixup depth image_offsets:
128 */
129 depth = mt->depth0;
130 for (level = mt->first_level; level <= mt->last_level; level++) {
131 GLuint i;
132 for (i = 0; i < depth; i++)
133 intel_miptree_set_image_offset(mt, level, i,
134 0, i * stack_height);
135
136 depth = minify(depth);
137 }
138
139
140 /* Multiply slice size by texture depth for total size. It's
141 * remarkable how wasteful of memory the i915 texture layouts
142 * are. They are largely fixed in the i945.
143 */
144 mt->total_height = stack_height * mt->depth0;
145 break;
146 }
147
148 default:{
149 GLuint width = mt->width0;
150 GLuint height = mt->height0;
151 GLuint img_height;
152
153 mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0);
154 mt->total_height = 0;
155
156 for (level = mt->first_level; level <= mt->last_level; level++) {
157 intel_miptree_set_level_info(mt, level, 1,
158 0, mt->total_height,
159 width, height, 1);
160
161 if (mt->compressed)
162 img_height = MAX2(1, height / 4);
163 else
164 img_height = (MAX2(2, height) + 1) & ~1;
165
166 mt->total_height += img_height;
167
168 width = minify(width);
169 height = minify(height);
170 }
171 break;
172 }
173 }
174 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
175 mt->pitch,
176 mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp);
177
178 return GL_TRUE;
179 }
180
181
182 GLboolean
183 i945_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree * mt)
184 {
185 GLint level;
186
187 switch (mt->target) {
188 case GL_TEXTURE_CUBE_MAP:{
189 const GLuint dim = mt->width0;
190 GLuint face;
191 GLuint lvlWidth = mt->width0, lvlHeight = mt->height0;
192
193 assert(lvlWidth == lvlHeight); /* cubemap images are square */
194
195 /* Depending on the size of the largest images, pitch can be
196 * determined either by the old-style packing of cubemap faces,
197 * or the final row of 4x4, 2x2 and 1x1 faces below this.
198 */
199 if (dim > 32)
200 mt->pitch = intel_miptree_pitch_align (intel, mt, dim);
201 else
202 mt->pitch = 14 * 8;
203
204 mt->total_height = dim * 4 + 4;
205
206 /* Set all the levels to effectively occupy the whole rectangular region.
207 */
208 for (level = mt->first_level; level <= mt->last_level; level++) {
209 intel_miptree_set_level_info(mt, level, 6,
210 0, 0,
211 lvlWidth, lvlHeight, 1);
212 lvlWidth /= 2;
213 lvlHeight /= 2;
214 }
215
216
217 for (face = 0; face < 6; face++) {
218 GLuint x = initial_offsets[face][0] * dim;
219 GLuint y = initial_offsets[face][1] * dim;
220 GLuint d = dim;
221
222 if (dim == 4 && face >= 4) {
223 y = mt->total_height - 4;
224 x = (face - 4) * 8;
225 }
226 else if (dim < 4 && (face > 0 || mt->first_level > 0)) {
227 y = mt->total_height - 4;
228 x = face * 8;
229 }
230
231 for (level = mt->first_level; level <= mt->last_level; level++) {
232 intel_miptree_set_image_offset(mt, level, face, x, y);
233
234 d >>= 1;
235
236 switch (d) {
237 case 4:
238 switch (face) {
239 case FACE_POS_X:
240 case FACE_NEG_X:
241 x += step_offsets[face][0] * d;
242 y += step_offsets[face][1] * d;
243 break;
244 case FACE_POS_Y:
245 case FACE_NEG_Y:
246 y += 12;
247 x -= 8;
248 break;
249 case FACE_POS_Z:
250 case FACE_NEG_Z:
251 y = mt->total_height - 4;
252 x = (face - 4) * 8;
253 break;
254 }
255
256 case 2:
257 y = mt->total_height - 4;
258 x = 16 + face * 8;
259 break;
260
261 case 1:
262 x += 48;
263 break;
264
265 default:
266 x += step_offsets[face][0] * d;
267 y += step_offsets[face][1] * d;
268 break;
269 }
270 }
271 }
272 break;
273 }
274 case GL_TEXTURE_3D:{
275 GLuint width = mt->width0;
276 GLuint height = mt->height0;
277 GLuint depth = mt->depth0;
278 GLuint pack_x_pitch, pack_x_nr;
279 GLuint pack_y_pitch;
280 GLuint level;
281
282 mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0);
283 mt->total_height = 0;
284
285 pack_y_pitch = MAX2(mt->height0, 2);
286 pack_x_pitch = mt->pitch;
287 pack_x_nr = 1;
288
289 for (level = mt->first_level; level <= mt->last_level; level++) {
290 GLuint nr_images = mt->target == GL_TEXTURE_3D ? depth : 6;
291 GLint x = 0;
292 GLint y = 0;
293 GLint q, j;
294
295 intel_miptree_set_level_info(mt, level, nr_images,
296 0, mt->total_height,
297 width, height, depth);
298
299 for (q = 0; q < nr_images;) {
300 for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
301 intel_miptree_set_image_offset(mt, level, q, x, y);
302 x += pack_x_pitch;
303 }
304
305 x = 0;
306 y += pack_y_pitch;
307 }
308
309
310 mt->total_height += y;
311
312 if (pack_x_pitch > 4) {
313 pack_x_pitch >>= 1;
314 pack_x_nr <<= 1;
315 assert(pack_x_pitch * pack_x_nr <= mt->pitch);
316 }
317
318 if (pack_y_pitch > 2) {
319 pack_y_pitch >>= 1;
320 }
321
322 width = minify(width);
323 height = minify(height);
324 depth = minify(depth);
325 }
326 break;
327 }
328
329 case GL_TEXTURE_1D:
330 case GL_TEXTURE_2D:
331 case GL_TEXTURE_RECTANGLE_ARB:
332 i945_miptree_layout_2d(intel, mt);
333 break;
334 default:
335 _mesa_problem(NULL, "Unexpected tex target in i945_miptree_layout()");
336 }
337
338 DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
339 mt->pitch,
340 mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp);
341
342 return GL_TRUE;
343 }