Tizen 2.0 Release
[profile/ivi/osmesa.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->gen == 5)
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 }