Merge branch '965-glsl'
[mesa.git] / src / mesa / drivers / dri / i915 / intel_mipmap_tree.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 #include "intel_context.h"
29 #include "intel_mipmap_tree.h"
30 #include "intel_regions.h"
31 #include "enums.h"
32
33 #define FILE_DEBUG_FLAG DEBUG_MIPTREE
34
35 static GLenum
36 target_to_target(GLenum target)
37 {
38 switch (target) {
39 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
40 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
41 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
42 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
43 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
44 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
45 return GL_TEXTURE_CUBE_MAP_ARB;
46 default:
47 return target;
48 }
49 }
50
51 struct intel_mipmap_tree *
52 intel_miptree_create(struct intel_context *intel,
53 GLenum target,
54 GLenum internal_format,
55 GLuint first_level,
56 GLuint last_level,
57 GLuint width0,
58 GLuint height0,
59 GLuint depth0, GLuint cpp, GLuint compress_byte)
60 {
61 GLboolean ok;
62 struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1);
63
64 DBG("%s target %s format %s level %d..%d\n", __FUNCTION__,
65 _mesa_lookup_enum_by_nr(target),
66 _mesa_lookup_enum_by_nr(internal_format), first_level, last_level);
67
68 mt->target = target_to_target(target);
69 mt->internal_format = internal_format;
70 mt->first_level = first_level;
71 mt->last_level = last_level;
72 mt->width0 = width0;
73 mt->height0 = height0;
74 mt->depth0 = depth0;
75 mt->cpp = compress_byte ? compress_byte : cpp;
76 mt->compressed = compress_byte ? 1 : 0;
77 mt->refcount = 1;
78
79 switch (intel->intelScreen->deviceID) {
80 case PCI_CHIP_I945_G:
81 case PCI_CHIP_I945_GM:
82 case PCI_CHIP_I945_GME:
83 case PCI_CHIP_G33_G:
84 case PCI_CHIP_Q33_G:
85 case PCI_CHIP_Q35_G:
86 ok = i945_miptree_layout(mt);
87 break;
88 case PCI_CHIP_I915_G:
89 case PCI_CHIP_I915_GM:
90 case PCI_CHIP_I830_M:
91 case PCI_CHIP_I855_GM:
92 case PCI_CHIP_I865_G:
93 default:
94 /* All the i830 chips and the i915 use this layout:
95 */
96 ok = i915_miptree_layout(mt);
97 break;
98 }
99
100 if (ok) {
101 if (!mt->compressed) {
102 int align;
103
104 if (intel->intelScreen->ttm) {
105 /* XXX: Align pitch to multiple of 64 bytes for now to allow
106 * render-to-texture to work in all cases. This should probably be
107 * replaced at some point by some scheme to only do this when really
108 * necessary.
109 */
110 align = 63;
111 } else {
112 align = 3;
113 }
114
115 mt->pitch = (mt->pitch * cpp + align) & ~align;
116
117 /* XXX: At least the i915 seems very upset when the pitch is a multiple
118 * of 1024 and sometimes 512 bytes - performance can drop by several
119 * times. Go to the next multiple of the required alignment for now.
120 */
121 if (!(mt->pitch & 511))
122 mt->pitch += align + 1;
123
124 mt->pitch /= cpp;
125 }
126
127 mt->region = intel_region_alloc(intel->intelScreen,
128 mt->cpp, mt->pitch, mt->total_height);
129 }
130
131 if (!mt->region) {
132 free(mt);
133 return NULL;
134 }
135
136 return mt;
137 }
138
139
140 void
141 intel_miptree_reference(struct intel_mipmap_tree **dst,
142 struct intel_mipmap_tree *src)
143 {
144 src->refcount++;
145 *dst = src;
146 DBG("%s %p refcount now %d\n", __FUNCTION__, src, src->refcount);
147 }
148
149 void
150 intel_miptree_release(struct intel_context *intel,
151 struct intel_mipmap_tree **mt)
152 {
153 if (!*mt)
154 return;
155
156 DBG("%s %p refcount will be %d\n", __FUNCTION__, *mt, (*mt)->refcount - 1);
157 if (--(*mt)->refcount <= 0) {
158 GLuint i;
159
160 DBG("%s deleting %p\n", __FUNCTION__, *mt);
161
162 intel_region_release(&((*mt)->region));
163
164 for (i = 0; i < MAX_TEXTURE_LEVELS; i++)
165 if ((*mt)->level[i].image_offset)
166 free((*mt)->level[i].image_offset);
167
168 free(*mt);
169 }
170 *mt = NULL;
171 }
172
173
174
175
176 /* Can the image be pulled into a unified mipmap tree. This mirrors
177 * the completeness test in a lot of ways.
178 *
179 * Not sure whether I want to pass gl_texture_image here.
180 */
181 GLboolean
182 intel_miptree_match_image(struct intel_mipmap_tree *mt,
183 struct gl_texture_image *image,
184 GLuint face, GLuint level)
185 {
186 /* Images with borders are never pulled into mipmap trees.
187 */
188 if (image->Border)
189 return GL_FALSE;
190
191 if (image->InternalFormat != mt->internal_format ||
192 image->IsCompressed != mt->compressed)
193 return GL_FALSE;
194
195 /* Test image dimensions against the base level image adjusted for
196 * minification. This will also catch images not present in the
197 * tree, changed targets, etc.
198 */
199 if (image->Width != mt->level[level].width ||
200 image->Height != mt->level[level].height ||
201 image->Depth != mt->level[level].depth)
202 return GL_FALSE;
203
204 return GL_TRUE;
205 }
206
207
208 void
209 intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
210 GLuint level,
211 GLuint nr_images,
212 GLuint x, GLuint y, GLuint w, GLuint h, GLuint d)
213 {
214
215 mt->level[level].width = w;
216 mt->level[level].height = h;
217 mt->level[level].depth = d;
218 mt->level[level].level_offset = (x + y * mt->pitch) * mt->cpp;
219 mt->level[level].nr_images = nr_images;
220
221 DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
222 level, w, h, d, x, y, mt->level[level].level_offset);
223
224 /* Not sure when this would happen, but anyway:
225 */
226 if (mt->level[level].image_offset) {
227 free(mt->level[level].image_offset);
228 mt->level[level].image_offset = NULL;
229 }
230
231 assert(nr_images);
232
233 mt->level[level].image_offset = malloc(nr_images * sizeof(GLuint));
234 mt->level[level].image_offset[0] = 0;
235 }
236
237
238
239 void
240 intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
241 GLuint level, GLuint img, GLuint x, GLuint y)
242 {
243 if (img == 0 && level == 0)
244 assert(x == 0 && y == 0);
245
246 assert(img < mt->level[level].nr_images);
247
248 mt->level[level].image_offset[img] = (x + y * mt->pitch);
249
250 DBG("%s level %d img %d pos %d,%d image_offset %x\n",
251 __FUNCTION__, level, img, x, y, mt->level[level].image_offset[img]);
252 }
253
254
255 /* Although we use the image_offset[] array to store relative offsets
256 * to cube faces, Mesa doesn't know anything about this and expects
257 * each cube face to be treated as a separate image.
258 *
259 * These functions present that view to mesa:
260 */
261 const GLuint *
262 intel_miptree_depth_offsets(struct intel_mipmap_tree *mt, GLuint level)
263 {
264 static const GLuint zero = 0;
265
266 if (mt->target != GL_TEXTURE_3D || mt->level[level].nr_images == 1)
267 return &zero;
268 else
269 return mt->level[level].image_offset;
270 }
271
272
273 GLuint
274 intel_miptree_image_offset(struct intel_mipmap_tree * mt,
275 GLuint face, GLuint level)
276 {
277 if (mt->target == GL_TEXTURE_CUBE_MAP_ARB)
278 return (mt->level[level].level_offset +
279 mt->level[level].image_offset[face] * mt->cpp);
280 else
281 return mt->level[level].level_offset;
282 }
283
284
285
286 /**
287 * Map a teximage in a mipmap tree.
288 * \param row_stride returns row stride in bytes
289 * \param image_stride returns image stride in bytes (for 3D textures).
290 * \return address of mapping
291 */
292 GLubyte *
293 intel_miptree_image_map(struct intel_context * intel,
294 struct intel_mipmap_tree * mt,
295 GLuint face,
296 GLuint level,
297 GLuint * row_stride, GLuint * image_offsets)
298 {
299 DBG("%s \n", __FUNCTION__);
300
301 if (row_stride)
302 *row_stride = mt->pitch * mt->cpp;
303
304 if (image_offsets)
305 memcpy(image_offsets, mt->level[level].image_offset,
306 mt->level[level].depth * sizeof(GLuint));
307
308 return (intel_region_map(intel->intelScreen, mt->region) +
309 intel_miptree_image_offset(mt, face, level));
310 }
311
312 void
313 intel_miptree_image_unmap(struct intel_context *intel,
314 struct intel_mipmap_tree *mt)
315 {
316 DBG("%s\n", __FUNCTION__);
317 intel_region_unmap(intel->intelScreen, mt->region);
318 }
319
320
321
322 /* Upload data for a particular image.
323 */
324 void
325 intel_miptree_image_data(struct intel_context *intel,
326 struct intel_mipmap_tree *dst,
327 GLuint face,
328 GLuint level,
329 void *src,
330 GLuint src_row_pitch, GLuint src_image_pitch)
331 {
332 GLuint depth = dst->level[level].depth;
333 GLuint dst_offset = intel_miptree_image_offset(dst, face, level);
334 const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level);
335 GLuint i;
336 GLuint height = 0;
337
338 DBG("%s\n", __FUNCTION__);
339 for (i = 0; i < depth; i++) {
340 height = dst->level[level].height;
341 if(dst->compressed)
342 height /= 4;
343 intel_region_data(intel->intelScreen, dst->region,
344 dst_offset + dst_depth_offset[i], /* dst_offset */
345 0, 0, /* dstx, dsty */
346 src,
347 src_row_pitch,
348 0, 0, /* source x, y */
349 dst->level[level].width, height); /* width, height */
350
351 src += src_image_pitch * dst->cpp;
352 }
353 }
354
355 extern GLuint intel_compressed_alignment(GLenum);
356 /* Copy mipmap image between trees
357 */
358 void
359 intel_miptree_image_copy(struct intel_context *intel,
360 struct intel_mipmap_tree *dst,
361 GLuint face, GLuint level,
362 struct intel_mipmap_tree *src)
363 {
364 GLuint width = src->level[level].width;
365 GLuint height = src->level[level].height;
366 GLuint depth = src->level[level].depth;
367 GLuint dst_offset = intel_miptree_image_offset(dst, face, level);
368 GLuint src_offset = intel_miptree_image_offset(src, face, level);
369 const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level);
370 const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level);
371 GLuint i;
372
373 if (dst->compressed) {
374 GLuint alignment = intel_compressed_alignment(dst->internal_format);
375 height = (height + 3) / 4;
376 width = ((width + alignment - 1) & ~(alignment - 1));
377 }
378
379 for (i = 0; i < depth; i++) {
380 intel_region_copy(intel->intelScreen,
381 dst->region, dst_offset + dst_depth_offset[i],
382 0,
383 0,
384 src->region, src_offset + src_depth_offset[i],
385 0, 0, width, height);
386 }
387
388 }