intel: Kill intel_mipmap_level::nr_images [v4]
[mesa.git] / src / mesa / drivers / dri / intel / 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 "intel_tex_layout.h"
32 #include "intel_tex.h"
33 #include "intel_blit.h"
34 #include "main/enums.h"
35 #include "main/formats.h"
36 #include "main/teximage.h"
37
38 #define FILE_DEBUG_FLAG DEBUG_MIPTREE
39
40
41 static GLenum
42 target_to_target(GLenum target)
43 {
44 switch (target) {
45 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
46 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
47 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
48 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
49 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
50 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
51 return GL_TEXTURE_CUBE_MAP_ARB;
52 default:
53 return target;
54 }
55 }
56
57
58 static struct intel_mipmap_tree *
59 intel_miptree_create_internal(struct intel_context *intel,
60 GLenum target,
61 gl_format format,
62 GLuint first_level,
63 GLuint last_level,
64 GLuint width0,
65 GLuint height0,
66 GLuint depth0)
67 {
68 struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1);
69 int compress_byte = 0;
70
71 DBG("%s target %s format %s level %d..%d <-- %p\n", __FUNCTION__,
72 _mesa_lookup_enum_by_nr(target),
73 _mesa_get_format_name(format),
74 first_level, last_level, mt);
75
76 if (_mesa_is_format_compressed(format))
77 compress_byte = intel_compressed_num_bytes(format);
78
79 mt->target = target_to_target(target);
80 mt->format = format;
81 mt->first_level = first_level;
82 mt->last_level = last_level;
83 mt->width0 = width0;
84 mt->height0 = height0;
85 mt->cpp = compress_byte ? compress_byte : _mesa_get_format_bytes(mt->format);
86 mt->compressed = compress_byte ? 1 : 0;
87 mt->refcount = 1;
88
89 if (target == GL_TEXTURE_CUBE_MAP) {
90 assert(depth0 == 1);
91 mt->depth0 = 6;
92 } else {
93 mt->depth0 = depth0;
94 }
95
96 #ifdef I915
97 (void) intel;
98 if (intel->is_945)
99 i945_miptree_layout(mt);
100 else
101 i915_miptree_layout(mt);
102 #else
103 brw_miptree_layout(intel, mt);
104 #endif
105
106 return mt;
107 }
108
109
110 struct intel_mipmap_tree *
111 intel_miptree_create(struct intel_context *intel,
112 GLenum target,
113 gl_format format,
114 GLuint first_level,
115 GLuint last_level,
116 GLuint width0,
117 GLuint height0,
118 GLuint depth0,
119 bool expect_accelerated_upload)
120 {
121 struct intel_mipmap_tree *mt;
122 uint32_t tiling = I915_TILING_NONE;
123 GLenum base_format = _mesa_get_format_base_format(format);
124
125 if (intel->use_texture_tiling && !_mesa_is_format_compressed(format)) {
126 if (intel->gen >= 4 &&
127 (base_format == GL_DEPTH_COMPONENT ||
128 base_format == GL_DEPTH_STENCIL_EXT))
129 tiling = I915_TILING_Y;
130 else if (width0 >= 64)
131 tiling = I915_TILING_X;
132 }
133
134 mt = intel_miptree_create_internal(intel, target, format,
135 first_level, last_level, width0,
136 height0, depth0);
137 /*
138 * pitch == 0 || height == 0 indicates the null texture
139 */
140 if (!mt || !mt->total_width || !mt->total_height) {
141 free(mt);
142 return NULL;
143 }
144
145 mt->region = intel_region_alloc(intel->intelScreen,
146 tiling,
147 mt->cpp,
148 mt->total_width,
149 mt->total_height,
150 expect_accelerated_upload);
151
152 if (!mt->region) {
153 free(mt);
154 return NULL;
155 }
156
157 return mt;
158 }
159
160
161 struct intel_mipmap_tree *
162 intel_miptree_create_for_region(struct intel_context *intel,
163 GLenum target,
164 gl_format format,
165 struct intel_region *region)
166 {
167 struct intel_mipmap_tree *mt;
168
169 mt = intel_miptree_create_internal(intel, target, format,
170 0, 0,
171 region->width, region->height, 1);
172 if (!mt)
173 return mt;
174
175 intel_region_reference(&mt->region, region);
176
177 return mt;
178 }
179
180 struct intel_mipmap_tree*
181 intel_miptree_create_for_renderbuffer(struct intel_context *intel,
182 gl_format format,
183 uint32_t tiling,
184 uint32_t cpp,
185 uint32_t width,
186 uint32_t height)
187 {
188 struct intel_region *region;
189 struct intel_mipmap_tree *mt;
190
191 region = intel_region_alloc(intel->intelScreen,
192 tiling, cpp, width, height, true);
193 if (!region)
194 return NULL;
195
196 mt = intel_miptree_create_for_region(intel, GL_TEXTURE_2D, format, region);
197 intel_region_release(&region);
198 return mt;
199 }
200
201 void
202 intel_miptree_reference(struct intel_mipmap_tree **dst,
203 struct intel_mipmap_tree *src)
204 {
205 if (*dst == src)
206 return;
207
208 intel_miptree_release(dst);
209
210 if (src) {
211 src->refcount++;
212 DBG("%s %p refcount now %d\n", __FUNCTION__, src, src->refcount);
213 }
214
215 *dst = src;
216 }
217
218
219 void
220 intel_miptree_release(struct intel_mipmap_tree **mt)
221 {
222 if (!*mt)
223 return;
224
225 DBG("%s %p refcount will be %d\n", __FUNCTION__, *mt, (*mt)->refcount - 1);
226 if (--(*mt)->refcount <= 0) {
227 GLuint i;
228
229 DBG("%s deleting %p\n", __FUNCTION__, *mt);
230
231 intel_region_release(&((*mt)->region));
232 intel_region_release(&((*mt)->hiz_region));
233
234 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
235 free((*mt)->level[i].slice);
236 }
237
238 free(*mt);
239 }
240 *mt = NULL;
241 }
242
243 void
244 intel_miptree_get_dimensions_for_image(struct gl_texture_image *image,
245 int *width, int *height, int *depth)
246 {
247 switch (image->TexObject->Target) {
248 case GL_TEXTURE_1D_ARRAY:
249 *width = image->Width;
250 *height = 1;
251 *depth = image->Height;
252 break;
253 default:
254 *width = image->Width;
255 *height = image->Height;
256 *depth = image->Depth;
257 break;
258 }
259 }
260
261 /**
262 * Can the image be pulled into a unified mipmap tree? This mirrors
263 * the completeness test in a lot of ways.
264 *
265 * Not sure whether I want to pass gl_texture_image here.
266 */
267 bool
268 intel_miptree_match_image(struct intel_mipmap_tree *mt,
269 struct gl_texture_image *image)
270 {
271 struct intel_texture_image *intelImage = intel_texture_image(image);
272 GLuint level = intelImage->base.Base.Level;
273 int width, height, depth;
274
275 if (image->TexFormat != mt->format)
276 return false;
277
278 intel_miptree_get_dimensions_for_image(image, &width, &height, &depth);
279
280 /* Test image dimensions against the base level image adjusted for
281 * minification. This will also catch images not present in the
282 * tree, changed targets, etc.
283 */
284 if (width != mt->level[level].width ||
285 height != mt->level[level].height ||
286 depth != mt->level[level].depth)
287 return false;
288
289 return true;
290 }
291
292
293 void
294 intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
295 GLuint level,
296 GLuint x, GLuint y,
297 GLuint w, GLuint h, GLuint d)
298 {
299 mt->level[level].width = w;
300 mt->level[level].height = h;
301 mt->level[level].depth = d;
302 mt->level[level].level_x = x;
303 mt->level[level].level_y = y;
304
305 DBG("%s level %d size: %d,%d,%d offset %d,%d\n", __FUNCTION__,
306 level, w, h, d, x, y);
307
308 assert(mt->level[level].slice == NULL);
309
310 mt->level[level].slice = malloc(d * sizeof(*mt->level[0].slice));
311 mt->level[level].slice[0].x_offset = mt->level[level].level_x;
312 mt->level[level].slice[0].y_offset = mt->level[level].level_y;
313 }
314
315
316 void
317 intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
318 GLuint level, GLuint img,
319 GLuint x, GLuint y)
320 {
321 if (img == 0 && level == 0)
322 assert(x == 0 && y == 0);
323
324 assert(img < mt->level[level].depth);
325
326 mt->level[level].slice[img].x_offset = mt->level[level].level_x + x;
327 mt->level[level].slice[img].y_offset = mt->level[level].level_y + y;
328
329 DBG("%s level %d img %d pos %d,%d\n",
330 __FUNCTION__, level, img,
331 mt->level[level].slice[img].x_offset,
332 mt->level[level].slice[img].y_offset);
333 }
334
335
336 /**
337 * For cube map textures, either the \c face parameter can be used, of course,
338 * or the cube face can be interpreted as a depth layer and the \c layer
339 * parameter used.
340 */
341 void
342 intel_miptree_get_image_offset(struct intel_mipmap_tree *mt,
343 GLuint level, GLuint face, GLuint layer,
344 GLuint *x, GLuint *y)
345 {
346 int slice;
347
348 if (face > 0) {
349 assert(mt->target == GL_TEXTURE_CUBE_MAP);
350 assert(face < 6);
351 assert(layer == 0);
352 slice = face;
353 } else {
354 /* This branch may be taken even if the texture target is a cube map. In
355 * that case, the caller chose to interpret each cube face as a layer.
356 */
357 assert(face == 0);
358 slice = layer;
359 }
360
361 *x = mt->level[level].slice[slice].x_offset;
362 *y = mt->level[level].slice[slice].y_offset;
363 }
364
365 static void
366 intel_miptree_copy_slice(struct intel_context *intel,
367 struct intel_mipmap_tree *dst_mt,
368 struct intel_mipmap_tree *src_mt,
369 int level,
370 int face,
371 int depth)
372
373 {
374 gl_format format = src_mt->format;
375 uint32_t width = src_mt->level[level].width;
376 uint32_t height = src_mt->level[level].height;
377
378 assert(depth < src_mt->level[level].depth);
379
380 if (dst_mt->compressed) {
381 uint32_t align_w, align_h;
382 intel_get_texture_alignment_unit(format,
383 &align_w, &align_h);
384 height = ALIGN(height, align_h) / align_h;
385 width = ALIGN(width, align_w);
386 }
387
388 uint32_t dst_x, dst_y, src_x, src_y;
389 intel_miptree_get_image_offset(dst_mt, level, face, depth,
390 &dst_x, &dst_y);
391 intel_miptree_get_image_offset(src_mt, level, face, depth,
392 &src_x, &src_y);
393
394 DBG("validate blit mt %p %d,%d/%d -> mt %p %d,%d/%d (%dx%d)\n",
395 src_mt, src_x, src_y, src_mt->region->pitch * src_mt->region->cpp,
396 dst_mt, dst_x, dst_y, dst_mt->region->pitch * dst_mt->region->cpp,
397 width, height);
398
399 if (!intelEmitCopyBlit(intel,
400 dst_mt->region->cpp,
401 src_mt->region->pitch, src_mt->region->bo,
402 0, src_mt->region->tiling,
403 dst_mt->region->pitch, dst_mt->region->bo,
404 0, dst_mt->region->tiling,
405 src_x, src_y,
406 dst_x, dst_y,
407 width, height,
408 GL_COPY)) {
409
410 fallback_debug("miptree validate blit for %s failed\n",
411 _mesa_get_format_name(format));
412 void *dst = intel_region_map(intel, dst_mt->region, GL_MAP_WRITE_BIT);
413 void *src = intel_region_map(intel, src_mt->region, GL_MAP_READ_BIT);
414
415 _mesa_copy_rect(dst,
416 dst_mt->cpp,
417 dst_mt->region->pitch,
418 dst_x, dst_y,
419 width, height,
420 src, src_mt->region->pitch,
421 src_x, src_y);
422
423 intel_region_unmap(intel, dst_mt->region);
424 intel_region_unmap(intel, src_mt->region);
425 }
426 }
427
428 /**
429 * Copies the image's current data to the given miptree, and associates that
430 * miptree with the image.
431 */
432 void
433 intel_miptree_copy_teximage(struct intel_context *intel,
434 struct intel_texture_image *intelImage,
435 struct intel_mipmap_tree *dst_mt)
436 {
437 struct intel_mipmap_tree *src_mt = intelImage->mt;
438 int level = intelImage->base.Base.Level;
439 int face = intelImage->base.Base.Face;
440 GLuint depth = intelImage->base.Base.Depth;
441
442 for (int slice = 0; slice < depth; slice++) {
443 intel_miptree_copy_slice(intel, dst_mt, src_mt, level, face, slice);
444 }
445
446 intel_miptree_reference(&intelImage->mt, dst_mt);
447 }
448