Merge commit 'origin/7.8'
[mesa.git] / src / gallium / drivers / i965 / brw_resource_texture_layout.c
1 /*
2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a 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, sublicense, 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
16 portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **********************************************************************/
27
28 #include "pipe/p_format.h"
29
30 #include "util/u_math.h"
31 #include "util/u_memory.h"
32
33 #include "brw_resource.h"
34 #include "brw_debug.h"
35 #include "brw_winsys.h"
36
37 /* Code to layout images in a mipmap tree for i965.
38 */
39
40 static int
41 brw_tex_pitch_align (struct brw_texture *tex,
42 int pitch)
43 {
44 if (!tex->compressed) {
45 int pitch_align;
46
47 switch (tex->tiling) {
48 case BRW_TILING_X:
49 pitch_align = 512;
50 break;
51 case BRW_TILING_Y:
52 pitch_align = 128;
53 break;
54 default:
55 /* XXX: Untiled pitch alignment of 64 bytes for now to allow
56 * render-to-texture to work in all cases. This should
57 * probably be replaced at some point by some scheme to only
58 * do this when really necessary, for example standalone
59 * render target views.
60 */
61 pitch_align = 64;
62 break;
63 }
64
65 pitch = align(pitch * tex->cpp, pitch_align);
66 pitch /= tex->cpp;
67 }
68
69 return pitch;
70 }
71
72
73 static void
74 brw_tex_alignment_unit(enum pipe_format pf,
75 GLuint *w, GLuint *h)
76 {
77 switch (pf) {
78 case PIPE_FORMAT_DXT1_RGB:
79 case PIPE_FORMAT_DXT1_RGBA:
80 case PIPE_FORMAT_DXT3_RGBA:
81 case PIPE_FORMAT_DXT5_RGBA:
82 case PIPE_FORMAT_DXT1_SRGB:
83 case PIPE_FORMAT_DXT1_SRGBA:
84 case PIPE_FORMAT_DXT3_SRGBA:
85 case PIPE_FORMAT_DXT5_SRGBA:
86 *w = 4;
87 *h = 4;
88 break;
89
90 default:
91 *w = 4;
92 *h = 2;
93 break;
94 }
95 }
96
97
98 static void
99 brw_tex_set_level_info(struct brw_texture *tex,
100 GLuint level,
101 GLuint nr_images,
102 GLuint x, GLuint y,
103 GLuint w, GLuint h, GLuint d)
104 {
105
106 if (BRW_DEBUG & DEBUG_TEXTURE)
107 debug_printf("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
108 level, w, h, d, x, y, tex->level_offset[level]);
109
110 assert(tex->image_offset[level] == NULL);
111 assert(nr_images >= 1);
112
113 tex->level_offset[level] = (x + y * tex->pitch) * tex->cpp;
114 tex->nr_images[level] = nr_images;
115
116 tex->image_offset[level] = MALLOC(nr_images * sizeof(GLuint));
117 tex->image_offset[level][0] = 0;
118 }
119
120
121 static void
122 brw_tex_set_image_offset(struct brw_texture *tex,
123 GLuint level, GLuint img,
124 GLuint x, GLuint y,
125 GLuint offset)
126 {
127 assert((x == 0 && y == 0) || img != 0 || level != 0);
128 assert(img < tex->nr_images[level]);
129
130 if (BRW_DEBUG & DEBUG_TEXTURE)
131 debug_printf("%s level %d img %d pos %d,%d image_offset %x\n",
132 __FUNCTION__, level, img, x, y,
133 tex->image_offset[level][img]);
134
135 tex->image_offset[level][img] = (x + y * tex->pitch) * tex->cpp + offset;
136 }
137
138
139
140 static void brw_layout_2d( struct brw_texture *tex )
141 {
142 GLuint align_h = 2, align_w = 4;
143 GLuint level;
144 GLuint x = 0;
145 GLuint y = 0;
146 GLuint width = tex->b.b.width0;
147 GLuint height = tex->b.b.height0;
148
149 tex->pitch = tex->b.b.width0;
150 brw_tex_alignment_unit(tex->b.b.format, &align_w, &align_h);
151
152 if (tex->compressed) {
153 tex->pitch = align(tex->b.b.width0, align_w);
154 }
155
156 /* May need to adjust pitch to accomodate the placement of
157 * the 2nd mipmap. This occurs when the alignment
158 * constraints of mipmap placement push the right edge of the
159 * 2nd mipmap out past the width of its parent.
160 */
161 if (tex->b.b.last_level > 0) {
162 GLuint mip1_width;
163
164 if (tex->compressed) {
165 mip1_width = (align(u_minify(tex->b.b.width0, 1), align_w) +
166 align(u_minify(tex->b.b.width0, 2), align_w));
167 } else {
168 mip1_width = (align(u_minify(tex->b.b.width0, 1), align_w) +
169 u_minify(tex->b.b.width0, 2));
170 }
171
172 if (mip1_width > tex->pitch) {
173 tex->pitch = mip1_width;
174 }
175 }
176
177 /* Pitch must be a whole number of dwords, even though we
178 * express it in texels.
179 */
180 tex->pitch = brw_tex_pitch_align (tex, tex->pitch);
181 tex->total_height = 0;
182
183 for ( level = 0 ; level <= tex->b.b.last_level ; level++ ) {
184 GLuint img_height;
185
186 brw_tex_set_level_info(tex, level, 1, x, y, width, height, 1);
187
188 if (tex->compressed)
189 img_height = MAX2(1, height/4);
190 else
191 img_height = align(height, align_h);
192
193
194 /* Because the images are packed better, the final offset
195 * might not be the maximal one:
196 */
197 tex->total_height = MAX2(tex->total_height, y + img_height);
198
199 /* Layout_below: step right after second mipmap.
200 */
201 if (level == 1) {
202 x += align(width, align_w);
203 }
204 else {
205 y += img_height;
206 }
207
208 width = u_minify(width, 1);
209 height = u_minify(height, 1);
210 }
211 }
212
213
214 static boolean
215 brw_layout_cubemap_idgng( struct brw_texture *tex )
216 {
217 GLuint align_h = 2, align_w = 4;
218 GLuint level;
219 GLuint x = 0;
220 GLuint y = 0;
221 GLuint width = tex->b.b.width0;
222 GLuint height = tex->b.b.height0;
223 GLuint qpitch = 0;
224 GLuint y_pitch = 0;
225
226 tex->pitch = tex->b.b.width0;
227 brw_tex_alignment_unit(tex->b.b.format, &align_w, &align_h);
228 y_pitch = align(height, align_h);
229
230 if (tex->compressed) {
231 tex->pitch = align(tex->b.b.width0, align_w);
232 }
233
234 if (tex->b.b.last_level != 0) {
235 GLuint mip1_width;
236
237 if (tex->compressed) {
238 mip1_width = (align(u_minify(tex->b.b.width0, 1), align_w) +
239 align(u_minify(tex->b.b.width0, 2), align_w));
240 } else {
241 mip1_width = (align(u_minify(tex->b.b.width0, 1), align_w) +
242 u_minify(tex->b.b.width0, 2));
243 }
244
245 if (mip1_width > tex->pitch) {
246 tex->pitch = mip1_width;
247 }
248 }
249
250 tex->pitch = brw_tex_pitch_align(tex, tex->pitch);
251
252 if (tex->compressed) {
253 qpitch = ((y_pitch +
254 align(u_minify(y_pitch, 1), align_h) +
255 11 * align_h) / 4) * tex->pitch * tex->cpp;
256
257 tex->total_height = ((y_pitch +
258 align(u_minify(y_pitch, 1), align_h) +
259 11 * align_h) / 4) * 6;
260 } else {
261 qpitch = (y_pitch +
262 align(u_minify(y_pitch, 1), align_h) +
263 11 * align_h) * tex->pitch * tex->cpp;
264
265 tex->total_height = (y_pitch +
266 align(u_minify(y_pitch, 1), align_h) +
267 11 * align_h) * 6;
268 }
269
270 for (level = 0; level <= tex->b.b.last_level; level++) {
271 GLuint img_height;
272 GLuint nr_images = 6;
273 GLuint q = 0;
274
275 brw_tex_set_level_info(tex, level, nr_images, x, y, width, height, 1);
276
277 for (q = 0; q < nr_images; q++)
278 brw_tex_set_image_offset(tex, level, q, x, y, q * qpitch);
279
280 if (tex->compressed)
281 img_height = MAX2(1, height/4);
282 else
283 img_height = align(height, align_h);
284
285 if (level == 1) {
286 x += align(width, align_w);
287 }
288 else {
289 y += img_height;
290 }
291
292 width = u_minify(width, 1);
293 height = u_minify(height, 1);
294 }
295
296 return TRUE;
297 }
298
299
300 static boolean
301 brw_layout_3d_cube( struct brw_texture *tex )
302 {
303 GLuint width = tex->b.b.width0;
304 GLuint height = tex->b.b.height0;
305 GLuint depth = tex->b.b.depth0;
306 GLuint pack_x_pitch, pack_x_nr;
307 GLuint pack_y_pitch;
308 GLuint level;
309 GLuint align_h = 2;
310 GLuint align_w = 4;
311
312 tex->total_height = 0;
313 brw_tex_alignment_unit(tex->b.b.format, &align_w, &align_h);
314
315 if (tex->compressed) {
316 tex->pitch = align(width, align_w);
317 pack_y_pitch = (height + 3) / 4;
318 } else {
319 tex->pitch = brw_tex_pitch_align(tex, tex->b.b.width0);
320 pack_y_pitch = align(tex->b.b.height0, align_h);
321 }
322
323 pack_x_pitch = width;
324 pack_x_nr = 1;
325
326 for (level = 0 ; level <= tex->b.b.last_level ; level++) {
327 GLuint nr_images = tex->b.b.target == PIPE_TEXTURE_3D ? depth : 6;
328 GLint x = 0;
329 GLint y = 0;
330 GLint q, j;
331
332 brw_tex_set_level_info(tex, level, nr_images,
333 0, tex->total_height,
334 width, height, depth);
335
336 for (q = 0; q < nr_images;) {
337 for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) {
338 brw_tex_set_image_offset(tex, level, q, x, y, 0);
339 x += pack_x_pitch;
340 }
341
342 x = 0;
343 y += pack_y_pitch;
344 }
345
346
347 tex->total_height += y;
348 width = u_minify(width, 1);
349 height = u_minify(height, 1);
350 depth = u_minify(depth, 1);
351
352 if (tex->compressed) {
353 pack_y_pitch = (height + 3) / 4;
354
355 if (pack_x_pitch > align(width, align_w)) {
356 pack_x_pitch = align(width, align_w);
357 pack_x_nr <<= 1;
358 }
359 } else {
360 if (pack_x_pitch > 4) {
361 pack_x_pitch >>= 1;
362 pack_x_nr <<= 1;
363 assert(pack_x_pitch * pack_x_nr <= tex->pitch);
364 }
365
366 if (pack_y_pitch > 2) {
367 pack_y_pitch >>= 1;
368 pack_y_pitch = align(pack_y_pitch, align_h);
369 }
370 }
371 }
372
373 /* The 965's sampler lays cachelines out according to how accesses
374 * in the texture surfaces run, so they may be "vertical" through
375 * memory. As a result, the docs say in Surface Padding Requirements:
376 * Sampling Engine Surfaces that two extra rows of padding are required.
377 */
378 if (tex->b.b.target == PIPE_TEXTURE_CUBE)
379 tex->total_height += 2;
380
381 return TRUE;
382 }
383
384
385
386 GLboolean brw_texture_layout(struct brw_screen *brw_screen,
387 struct brw_texture *tex )
388 {
389 switch (tex->b.b.target) {
390 case PIPE_TEXTURE_CUBE:
391 if (brw_screen->chipset.is_igdng)
392 brw_layout_cubemap_idgng( tex );
393 else
394 brw_layout_3d_cube( tex );
395 break;
396
397 case PIPE_TEXTURE_3D:
398 brw_layout_3d_cube( tex );
399 break;
400
401 default:
402 brw_layout_2d( tex );
403 break;
404 }
405
406 if (BRW_DEBUG & DEBUG_TEXTURE)
407 debug_printf("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__,
408 tex->pitch,
409 tex->total_height,
410 tex->cpp,
411 tex->pitch * tex->total_height * tex->cpp );
412
413 return GL_TRUE;
414 }