Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * |
||
4 | * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. |
||
5 | * Copyright (c) 2009 VMware, Inc. |
||
6 | * |
||
7 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
8 | * copy of this software and associated documentation files (the "Software"), |
||
9 | * to deal in the Software without restriction, including without limitation |
||
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
11 | * and/or sell copies of the Software, and to permit persons to whom the |
||
12 | * Software is furnished to do so, subject to the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice shall be included |
||
15 | * in all copies or substantial portions of the Software. |
||
16 | * |
||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
18 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
23 | * OTHER DEALINGS IN THE SOFTWARE. |
||
24 | */ |
||
25 | |||
26 | |||
27 | /** |
||
28 | * Code for glGetTexImage() and glGetCompressedTexImage(). |
||
29 | */ |
||
30 | |||
31 | |||
32 | #include "glheader.h" |
||
33 | #include "bufferobj.h" |
||
34 | #include "enums.h" |
||
35 | #include "context.h" |
||
36 | #include "formats.h" |
||
37 | #include "format_unpack.h" |
||
38 | #include "glformats.h" |
||
39 | #include "image.h" |
||
40 | #include "mtypes.h" |
||
41 | #include "pack.h" |
||
42 | #include "pbo.h" |
||
43 | #include "pixelstore.h" |
||
44 | #include "texcompress.h" |
||
45 | #include "texgetimage.h" |
||
46 | #include "teximage.h" |
||
47 | #include "texobj.h" |
||
48 | #include "texstore.h" |
||
49 | #include "format_utils.h" |
||
50 | #include "pixeltransfer.h" |
||
51 | |||
52 | /** |
||
53 | * Can the given type represent negative values? |
||
54 | */ |
||
55 | static inline GLboolean |
||
56 | type_needs_clamping(GLenum type) |
||
57 | { |
||
58 | switch (type) { |
||
59 | case GL_BYTE: |
||
60 | case GL_SHORT: |
||
61 | case GL_INT: |
||
62 | case GL_FLOAT: |
||
63 | case GL_HALF_FLOAT_ARB: |
||
64 | case GL_UNSIGNED_INT_10F_11F_11F_REV: |
||
65 | case GL_UNSIGNED_INT_5_9_9_9_REV: |
||
66 | return GL_FALSE; |
||
67 | default: |
||
68 | return GL_TRUE; |
||
69 | } |
||
70 | } |
||
71 | |||
72 | |||
73 | /** |
||
74 | * glGetTexImage for depth/Z pixels. |
||
75 | */ |
||
76 | static void |
||
77 | get_tex_depth(struct gl_context *ctx, GLuint dimensions, |
||
78 | GLenum format, GLenum type, GLvoid *pixels, |
||
79 | struct gl_texture_image *texImage) |
||
80 | { |
||
81 | const GLint width = texImage->Width; |
||
82 | GLint height = texImage->Height; |
||
83 | GLint depth = texImage->Depth; |
||
84 | GLint img, row; |
||
85 | GLfloat *depthRow = malloc(width * sizeof(GLfloat)); |
||
86 | |||
87 | if (!depthRow) { |
||
88 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); |
||
89 | return; |
||
90 | } |
||
91 | |||
92 | if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { |
||
93 | depth = height; |
||
94 | height = 1; |
||
95 | } |
||
96 | |||
97 | for (img = 0; img < depth; img++) { |
||
98 | GLubyte *srcMap; |
||
99 | GLint srcRowStride; |
||
100 | |||
101 | /* map src texture buffer */ |
||
102 | ctx->Driver.MapTextureImage(ctx, texImage, img, |
||
103 | 0, 0, width, height, GL_MAP_READ_BIT, |
||
104 | &srcMap, &srcRowStride); |
||
105 | |||
106 | if (srcMap) { |
||
107 | for (row = 0; row < height; row++) { |
||
108 | void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, |
||
109 | width, height, format, type, |
||
110 | img, row, 0); |
||
111 | const GLubyte *src = srcMap + row * srcRowStride; |
||
112 | _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow); |
||
113 | _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); |
||
114 | } |
||
115 | |||
116 | ctx->Driver.UnmapTextureImage(ctx, texImage, img); |
||
117 | } |
||
118 | else { |
||
119 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); |
||
120 | break; |
||
121 | } |
||
122 | } |
||
123 | |||
124 | free(depthRow); |
||
125 | } |
||
126 | |||
127 | |||
128 | /** |
||
129 | * glGetTexImage for depth/stencil pixels. |
||
130 | */ |
||
131 | static void |
||
132 | get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, |
||
133 | GLenum format, GLenum type, GLvoid *pixels, |
||
134 | struct gl_texture_image *texImage) |
||
135 | { |
||
136 | const GLint width = texImage->Width; |
||
137 | const GLint height = texImage->Height; |
||
138 | const GLint depth = texImage->Depth; |
||
139 | GLint img, row; |
||
140 | |||
141 | assert(format == GL_DEPTH_STENCIL); |
||
142 | assert(type == GL_UNSIGNED_INT_24_8 || |
||
143 | type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); |
||
144 | |||
145 | for (img = 0; img < depth; img++) { |
||
146 | GLubyte *srcMap; |
||
147 | GLint rowstride; |
||
148 | |||
149 | /* map src texture buffer */ |
||
150 | ctx->Driver.MapTextureImage(ctx, texImage, img, |
||
151 | 0, 0, width, height, GL_MAP_READ_BIT, |
||
152 | &srcMap, &rowstride); |
||
153 | |||
154 | if (srcMap) { |
||
155 | for (row = 0; row < height; row++) { |
||
156 | const GLubyte *src = srcMap + row * rowstride; |
||
157 | void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, |
||
158 | width, height, format, type, |
||
159 | img, row, 0); |
||
160 | _mesa_unpack_depth_stencil_row(texImage->TexFormat, |
||
161 | width, |
||
162 | (const GLuint *) src, |
||
163 | type, dest); |
||
164 | if (ctx->Pack.SwapBytes) { |
||
165 | _mesa_swap4((GLuint *) dest, width); |
||
166 | } |
||
167 | } |
||
168 | |||
169 | ctx->Driver.UnmapTextureImage(ctx, texImage, img); |
||
170 | } |
||
171 | else { |
||
172 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); |
||
173 | break; |
||
174 | } |
||
175 | } |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * glGetTexImage for stencil pixels. |
||
180 | */ |
||
181 | static void |
||
182 | get_tex_stencil(struct gl_context *ctx, GLuint dimensions, |
||
183 | GLenum format, GLenum type, GLvoid *pixels, |
||
184 | struct gl_texture_image *texImage) |
||
185 | { |
||
186 | const GLint width = texImage->Width; |
||
187 | const GLint height = texImage->Height; |
||
188 | const GLint depth = texImage->Depth; |
||
189 | GLint img, row; |
||
190 | |||
191 | assert(format == GL_STENCIL_INDEX); |
||
192 | |||
193 | for (img = 0; img < depth; img++) { |
||
194 | GLubyte *srcMap; |
||
195 | GLint rowstride; |
||
196 | |||
197 | /* map src texture buffer */ |
||
198 | ctx->Driver.MapTextureImage(ctx, texImage, img, |
||
199 | 0, 0, width, height, GL_MAP_READ_BIT, |
||
200 | &srcMap, &rowstride); |
||
201 | |||
202 | if (srcMap) { |
||
203 | for (row = 0; row < height; row++) { |
||
204 | const GLubyte *src = srcMap + row * rowstride; |
||
205 | void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, |
||
206 | width, height, format, type, |
||
207 | img, row, 0); |
||
208 | _mesa_unpack_ubyte_stencil_row(texImage->TexFormat, |
||
209 | width, |
||
210 | (const GLuint *) src, |
||
211 | dest); |
||
212 | } |
||
213 | |||
214 | ctx->Driver.UnmapTextureImage(ctx, texImage, img); |
||
215 | } |
||
216 | else { |
||
217 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); |
||
218 | break; |
||
219 | } |
||
220 | } |
||
221 | } |
||
222 | |||
223 | |||
224 | /** |
||
225 | * glGetTexImage for YCbCr pixels. |
||
226 | */ |
||
227 | static void |
||
228 | get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, |
||
229 | GLenum format, GLenum type, GLvoid *pixels, |
||
230 | struct gl_texture_image *texImage) |
||
231 | { |
||
232 | const GLint width = texImage->Width; |
||
233 | const GLint height = texImage->Height; |
||
234 | const GLint depth = texImage->Depth; |
||
235 | GLint img, row; |
||
236 | |||
237 | for (img = 0; img < depth; img++) { |
||
238 | GLubyte *srcMap; |
||
239 | GLint rowstride; |
||
240 | |||
241 | /* map src texture buffer */ |
||
242 | ctx->Driver.MapTextureImage(ctx, texImage, img, |
||
243 | 0, 0, width, height, GL_MAP_READ_BIT, |
||
244 | &srcMap, &rowstride); |
||
245 | |||
246 | if (srcMap) { |
||
247 | for (row = 0; row < height; row++) { |
||
248 | const GLubyte *src = srcMap + row * rowstride; |
||
249 | void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, |
||
250 | width, height, format, type, |
||
251 | img, row, 0); |
||
252 | memcpy(dest, src, width * sizeof(GLushort)); |
||
253 | |||
254 | /* check for byte swapping */ |
||
255 | if ((texImage->TexFormat == MESA_FORMAT_YCBCR |
||
256 | && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || |
||
257 | (texImage->TexFormat == MESA_FORMAT_YCBCR_REV |
||
258 | && type == GL_UNSIGNED_SHORT_8_8_MESA)) { |
||
259 | if (!ctx->Pack.SwapBytes) |
||
260 | _mesa_swap2((GLushort *) dest, width); |
||
261 | } |
||
262 | else if (ctx->Pack.SwapBytes) { |
||
263 | _mesa_swap2((GLushort *) dest, width); |
||
264 | } |
||
265 | } |
||
266 | |||
267 | ctx->Driver.UnmapTextureImage(ctx, texImage, img); |
||
268 | } |
||
269 | else { |
||
270 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); |
||
271 | break; |
||
272 | } |
||
273 | } |
||
274 | } |
||
275 | |||
276 | |||
277 | /** |
||
278 | * Get a color texture image with decompression. |
||
279 | */ |
||
280 | static void |
||
281 | get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, |
||
282 | GLenum format, GLenum type, GLvoid *pixels, |
||
283 | struct gl_texture_image *texImage, |
||
284 | GLbitfield transferOps) |
||
285 | { |
||
286 | /* don't want to apply sRGB -> RGB conversion here so override the format */ |
||
287 | const mesa_format texFormat = |
||
288 | _mesa_get_srgb_format_linear(texImage->TexFormat); |
||
289 | const GLenum baseFormat = _mesa_get_format_base_format(texFormat); |
||
290 | const GLuint width = texImage->Width; |
||
291 | const GLuint height = texImage->Height; |
||
292 | const GLuint depth = texImage->Depth; |
||
293 | GLfloat *tempImage, *tempSlice; |
||
294 | GLuint slice; |
||
295 | int srcStride, dstStride; |
||
296 | uint32_t dstFormat; |
||
297 | bool needsRebase; |
||
298 | uint8_t rebaseSwizzle[4]; |
||
299 | |||
300 | /* Decompress into temp float buffer, then pack into user buffer */ |
||
301 | tempImage = malloc(width * height * depth |
||
302 | * 4 * sizeof(GLfloat)); |
||
303 | if (!tempImage) { |
||
304 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); |
||
305 | return; |
||
306 | } |
||
307 | |||
308 | /* Decompress the texture image slices - results in 'tempImage' */ |
||
309 | for (slice = 0; slice < depth; slice++) { |
||
310 | GLubyte *srcMap; |
||
311 | GLint srcRowStride; |
||
312 | |||
313 | tempSlice = tempImage + slice * 4 * width * height; |
||
314 | |||
315 | ctx->Driver.MapTextureImage(ctx, texImage, slice, |
||
316 | 0, 0, width, height, |
||
317 | GL_MAP_READ_BIT, |
||
318 | &srcMap, &srcRowStride); |
||
319 | if (srcMap) { |
||
320 | _mesa_decompress_image(texFormat, width, height, |
||
321 | srcMap, srcRowStride, tempSlice); |
||
322 | |||
323 | ctx->Driver.UnmapTextureImage(ctx, texImage, slice); |
||
324 | } |
||
325 | else { |
||
326 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); |
||
327 | free(tempImage); |
||
328 | return; |
||
329 | } |
||
330 | } |
||
331 | |||
332 | /* Depending on the base format involved we may need to apply a rebase |
||
333 | * transform (for example: if we download to a Luminance format we want |
||
334 | * G=0 and B=0). |
||
335 | */ |
||
336 | if (baseFormat == GL_LUMINANCE || |
||
337 | baseFormat == GL_INTENSITY) { |
||
338 | needsRebase = true; |
||
339 | rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; |
||
340 | rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; |
||
341 | rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; |
||
342 | rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE; |
||
343 | } else if (baseFormat == GL_LUMINANCE_ALPHA) { |
||
344 | needsRebase = true; |
||
345 | rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; |
||
346 | rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; |
||
347 | rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; |
||
348 | rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W; |
||
349 | } else { |
||
350 | needsRebase = false; |
||
351 | } |
||
352 | |||
353 | srcStride = 4 * width * sizeof(GLfloat); |
||
354 | dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type); |
||
355 | dstFormat = _mesa_format_from_format_and_type(format, type); |
||
356 | tempSlice = tempImage; |
||
357 | for (slice = 0; slice < depth; slice++) { |
||
358 | void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, |
||
359 | width, height, format, type, |
||
360 | slice, 0, 0); |
||
361 | _mesa_format_convert(dest, dstFormat, dstStride, |
||
362 | tempSlice, RGBA32_FLOAT, srcStride, |
||
363 | width, height, |
||
364 | needsRebase ? rebaseSwizzle : NULL); |
||
365 | tempSlice += 4 * width * height; |
||
366 | } |
||
367 | |||
368 | free(tempImage); |
||
369 | } |
||
370 | |||
371 | |||
372 | /** |
||
373 | * Return a base GL format given the user-requested format |
||
374 | * for glGetTexImage(). |
||
375 | */ |
||
376 | GLenum |
||
377 | _mesa_base_pack_format(GLenum format) |
||
378 | { |
||
379 | switch (format) { |
||
380 | case GL_ABGR_EXT: |
||
381 | case GL_BGRA: |
||
382 | case GL_BGRA_INTEGER: |
||
383 | case GL_RGBA_INTEGER: |
||
384 | return GL_RGBA; |
||
385 | case GL_BGR: |
||
386 | case GL_BGR_INTEGER: |
||
387 | case GL_RGB_INTEGER: |
||
388 | return GL_RGB; |
||
389 | case GL_RED_INTEGER: |
||
390 | return GL_RED; |
||
391 | case GL_GREEN_INTEGER: |
||
392 | return GL_GREEN; |
||
393 | case GL_BLUE_INTEGER: |
||
394 | return GL_BLUE; |
||
395 | case GL_ALPHA_INTEGER: |
||
396 | return GL_ALPHA; |
||
397 | case GL_LUMINANCE_INTEGER_EXT: |
||
398 | return GL_LUMINANCE; |
||
399 | case GL_LUMINANCE_ALPHA_INTEGER_EXT: |
||
400 | return GL_LUMINANCE_ALPHA; |
||
401 | default: |
||
402 | return format; |
||
403 | } |
||
404 | } |
||
405 | |||
406 | |||
407 | /** |
||
408 | * Get an uncompressed color texture image. |
||
409 | */ |
||
410 | static void |
||
411 | get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, |
||
412 | GLenum format, GLenum type, GLvoid *pixels, |
||
413 | struct gl_texture_image *texImage, |
||
414 | GLbitfield transferOps) |
||
415 | { |
||
416 | /* don't want to apply sRGB -> RGB conversion here so override the format */ |
||
417 | const mesa_format texFormat = |
||
418 | _mesa_get_srgb_format_linear(texImage->TexFormat); |
||
419 | const GLuint width = texImage->Width; |
||
420 | GLuint height = texImage->Height; |
||
421 | GLuint depth = texImage->Depth; |
||
422 | GLuint img; |
||
423 | GLboolean dst_is_integer; |
||
424 | uint32_t dst_format; |
||
425 | int dst_stride; |
||
426 | uint8_t rebaseSwizzle[4]; |
||
427 | bool needsRebase; |
||
428 | void *rgba = NULL; |
||
429 | |||
430 | if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { |
||
431 | depth = height; |
||
432 | height = 1; |
||
433 | } |
||
434 | |||
435 | /* Depending on the base format involved we may need to apply a rebase |
||
436 | * transform (for example: if we download to a Luminance format we want |
||
437 | * G=0 and B=0). |
||
438 | */ |
||
439 | if (texImage->_BaseFormat == GL_LUMINANCE || |
||
440 | texImage->_BaseFormat == GL_INTENSITY) { |
||
441 | needsRebase = true; |
||
442 | rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; |
||
443 | rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; |
||
444 | rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; |
||
445 | rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE; |
||
446 | } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { |
||
447 | needsRebase = true; |
||
448 | rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; |
||
449 | rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; |
||
450 | rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; |
||
451 | rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W; |
||
452 | } else if (texImage->_BaseFormat != _mesa_get_format_base_format(texFormat)) { |
||
453 | needsRebase = |
||
454 | _mesa_compute_rgba2base2rgba_component_mapping(texImage->_BaseFormat, |
||
455 | rebaseSwizzle); |
||
456 | } else { |
||
457 | needsRebase = false; |
||
458 | } |
||
459 | |||
460 | /* Describe the dst format */ |
||
461 | dst_is_integer = _mesa_is_enum_format_integer(format); |
||
462 | dst_format = _mesa_format_from_format_and_type(format, type); |
||
463 | dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type); |
||
464 | |||
465 | /* Since _mesa_format_convert does not handle transferOps we need to handle |
||
466 | * them before we call the function. This requires to convert to RGBA float |
||
467 | * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is |
||
468 | * integer then transferOps do not apply. |
||
469 | */ |
||
470 | assert(!transferOps || (transferOps && !dst_is_integer)); |
||
471 | (void) dst_is_integer; /* silence unused var warning */ |
||
472 | |||
473 | for (img = 0; img < depth; img++) { |
||
474 | GLubyte *srcMap; |
||
475 | GLint rowstride; |
||
476 | GLubyte *img_src; |
||
477 | void *dest; |
||
478 | void *src; |
||
479 | int src_stride; |
||
480 | uint32_t src_format; |
||
481 | |||
482 | /* map src texture buffer */ |
||
483 | ctx->Driver.MapTextureImage(ctx, texImage, img, |
||
484 | 0, 0, width, height, GL_MAP_READ_BIT, |
||
485 | &srcMap, &rowstride); |
||
486 | if (!srcMap) { |
||
487 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); |
||
488 | goto done; |
||
489 | } |
||
490 | |||
491 | img_src = srcMap; |
||
492 | dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, |
||
493 | width, height, format, type, |
||
494 | img, 0, 0); |
||
495 | |||
496 | if (transferOps) { |
||
497 | uint32_t rgba_format; |
||
498 | int rgba_stride; |
||
499 | bool need_convert = false; |
||
500 | |||
501 | /* We will convert to RGBA float */ |
||
502 | rgba_format = RGBA32_FLOAT; |
||
503 | rgba_stride = width * 4 * sizeof(GLfloat); |
||
504 | |||
505 | /* If we are lucky and the dst format matches the RGBA format we need |
||
506 | * to convert to, then we can convert directly into the dst buffer |
||
507 | * and avoid the final conversion/copy from the rgba buffer to the dst |
||
508 | * buffer. |
||
509 | */ |
||
510 | if (format == rgba_format) { |
||
511 | rgba = dest; |
||
512 | } else if (rgba == NULL) { /* Allocate the RGBA buffer only once */ |
||
513 | need_convert = true; |
||
514 | rgba = malloc(height * rgba_stride); |
||
515 | if (!rgba) { |
||
516 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); |
||
517 | ctx->Driver.UnmapTextureImage(ctx, texImage, img); |
||
518 | return; |
||
519 | } |
||
520 | } |
||
521 | |||
522 | _mesa_format_convert(rgba, rgba_format, rgba_stride, |
||
523 | img_src, texFormat, rowstride, |
||
524 | width, height, |
||
525 | needsRebase ? rebaseSwizzle : NULL); |
||
526 | |||
527 | /* Handle transfer ops now */ |
||
528 | _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba); |
||
529 | |||
530 | /* If we had to rebase, we have already handled that */ |
||
531 | needsRebase = false; |
||
532 | |||
533 | /* If we were lucky and our RGBA conversion matches the dst format, then |
||
534 | * we are done. |
||
535 | */ |
||
536 | if (!need_convert) |
||
537 | goto do_swap; |
||
538 | |||
539 | /* Otherwise, we need to convert from RGBA to dst next */ |
||
540 | src = rgba; |
||
541 | src_format = rgba_format; |
||
542 | src_stride = rgba_stride; |
||
543 | } else { |
||
544 | /* No RGBA conversion needed, convert directly to dst */ |
||
545 | src = img_src; |
||
546 | src_format = texFormat; |
||
547 | src_stride = rowstride; |
||
548 | } |
||
549 | |||
550 | /* Do the conversion to destination format */ |
||
551 | _mesa_format_convert(dest, dst_format, dst_stride, |
||
552 | src, src_format, src_stride, |
||
553 | width, height, |
||
554 | needsRebase ? rebaseSwizzle : NULL); |
||
555 | |||
556 | do_swap: |
||
557 | /* Handle byte swapping if required */ |
||
558 | if (ctx->Pack.SwapBytes) { |
||
559 | GLint swapSize = _mesa_sizeof_packed_type(type); |
||
560 | if (swapSize == 2 || swapSize == 4) { |
||
561 | int swapsPerPixel = _mesa_bytes_per_pixel(format, type) / swapSize; |
||
562 | assert(_mesa_bytes_per_pixel(format, type) % swapSize == 0); |
||
563 | if (swapSize == 2) |
||
564 | _mesa_swap2((GLushort *) dest, width * height * swapsPerPixel); |
||
565 | else if (swapSize == 4) |
||
566 | _mesa_swap4((GLuint *) dest, width * height * swapsPerPixel); |
||
567 | } |
||
568 | } |
||
569 | |||
570 | /* Unmap the src texture buffer */ |
||
571 | ctx->Driver.UnmapTextureImage(ctx, texImage, img); |
||
572 | } |
||
573 | |||
574 | done: |
||
575 | if (rgba) |
||
576 | free(rgba); |
||
577 | } |
||
578 | |||
579 | |||
580 | /** |
||
581 | * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). |
||
582 | * Compressed textures are handled here as well. |
||
583 | */ |
||
584 | static void |
||
585 | get_tex_rgba(struct gl_context *ctx, GLuint dimensions, |
||
586 | GLenum format, GLenum type, GLvoid *pixels, |
||
587 | struct gl_texture_image *texImage) |
||
588 | { |
||
589 | const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); |
||
590 | GLbitfield transferOps = 0x0; |
||
591 | |||
592 | /* In general, clamping does not apply to glGetTexImage, except when |
||
593 | * the returned type of the image can't hold negative values. |
||
594 | */ |
||
595 | if (type_needs_clamping(type)) { |
||
596 | /* the returned image type can't have negative values */ |
||
597 | if (dataType == GL_FLOAT || |
||
598 | dataType == GL_HALF_FLOAT || |
||
599 | dataType == GL_SIGNED_NORMALIZED || |
||
600 | format == GL_LUMINANCE || |
||
601 | format == GL_LUMINANCE_ALPHA) { |
||
602 | transferOps |= IMAGE_CLAMP_BIT; |
||
603 | } |
||
604 | } |
||
605 | |||
606 | if (_mesa_is_format_compressed(texImage->TexFormat)) { |
||
607 | get_tex_rgba_compressed(ctx, dimensions, format, type, |
||
608 | pixels, texImage, transferOps); |
||
609 | } |
||
610 | else { |
||
611 | get_tex_rgba_uncompressed(ctx, dimensions, format, type, |
||
612 | pixels, texImage, transferOps); |
||
613 | } |
||
614 | } |
||
615 | |||
616 | |||
617 | /** |
||
618 | * Try to do glGetTexImage() with simple memcpy(). |
||
619 | * \return GL_TRUE if done, GL_FALSE otherwise |
||
620 | */ |
||
621 | static GLboolean |
||
622 | get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, |
||
623 | GLvoid *pixels, |
||
624 | struct gl_texture_image *texImage) |
||
625 | { |
||
626 | const GLenum target = texImage->TexObject->Target; |
||
627 | GLboolean memCopy = GL_FALSE; |
||
628 | GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat); |
||
629 | |||
630 | /* |
||
631 | * Check if we can use memcpy to copy from the hardware texture |
||
632 | * format to the user's format/type. |
||
633 | * Note that GL's pixel transfer ops don't apply to glGetTexImage() |
||
634 | */ |
||
635 | if ((target == GL_TEXTURE_1D || |
||
636 | target == GL_TEXTURE_2D || |
||
637 | target == GL_TEXTURE_RECTANGLE || |
||
638 | _mesa_is_cube_face(target)) && |
||
639 | texBaseFormat == texImage->_BaseFormat) { |
||
640 | memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat, |
||
641 | format, type, |
||
642 | ctx->Pack.SwapBytes); |
||
643 | } |
||
644 | |||
645 | if (memCopy) { |
||
646 | const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); |
||
647 | const GLint bytesPerRow = texImage->Width * bpp; |
||
648 | GLubyte *dst = |
||
649 | _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, |
||
650 | texImage->Height, format, type, 0, 0); |
||
651 | const GLint dstRowStride = |
||
652 | _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); |
||
653 | GLubyte *src; |
||
654 | GLint srcRowStride; |
||
655 | |||
656 | /* map src texture buffer */ |
||
657 | ctx->Driver.MapTextureImage(ctx, texImage, 0, |
||
658 | 0, 0, texImage->Width, texImage->Height, |
||
659 | GL_MAP_READ_BIT, &src, &srcRowStride); |
||
660 | |||
661 | if (src) { |
||
662 | if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { |
||
663 | memcpy(dst, src, bytesPerRow * texImage->Height); |
||
664 | } |
||
665 | else { |
||
666 | GLuint row; |
||
667 | for (row = 0; row < texImage->Height; row++) { |
||
668 | memcpy(dst, src, bytesPerRow); |
||
669 | dst += dstRowStride; |
||
670 | src += srcRowStride; |
||
671 | } |
||
672 | } |
||
673 | |||
674 | /* unmap src texture buffer */ |
||
675 | ctx->Driver.UnmapTextureImage(ctx, texImage, 0); |
||
676 | } |
||
677 | else { |
||
678 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); |
||
679 | } |
||
680 | } |
||
681 | |||
682 | return memCopy; |
||
683 | } |
||
684 | |||
685 | |||
686 | /** |
||
687 | * This is the software fallback for Driver.GetTexImage(). |
||
688 | * All error checking will have been done before this routine is called. |
||
689 | * We'll call ctx->Driver.MapTextureImage() to access the data, then |
||
690 | * unmap with ctx->Driver.UnmapTextureImage(). |
||
691 | */ |
||
692 | void |
||
693 | _mesa_GetTexImage_sw(struct gl_context *ctx, |
||
694 | GLenum format, GLenum type, GLvoid *pixels, |
||
695 | struct gl_texture_image *texImage) |
||
696 | { |
||
697 | const GLuint dimensions = |
||
698 | _mesa_get_texture_dimensions(texImage->TexObject->Target); |
||
699 | |||
700 | /* map dest buffer, if PBO */ |
||
701 | if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { |
||
702 | /* Packing texture image into a PBO. |
||
703 | * Map the (potentially) VRAM-based buffer into our process space so |
||
704 | * we can write into it with the code below. |
||
705 | * A hardware driver might use a sophisticated blit to move the |
||
706 | * texture data to the PBO if the PBO is in VRAM along with the texture. |
||
707 | */ |
||
708 | GLubyte *buf = (GLubyte *) |
||
709 | ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, |
||
710 | GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, |
||
711 | MAP_INTERNAL); |
||
712 | if (!buf) { |
||
713 | /* out of memory or other unexpected error */ |
||
714 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); |
||
715 | return; |
||
716 | } |
||
717 | /* |
||
718 | * Now make it a real, client-side pointer inside the mapped region. |
||
719 | */ |
||
720 | pixels = ADD_POINTERS(buf, pixels); |
||
721 | } |
||
722 | |||
723 | if (get_tex_memcpy(ctx, format, type, pixels, texImage)) { |
||
724 | /* all done */ |
||
725 | } |
||
726 | else if (format == GL_DEPTH_COMPONENT) { |
||
727 | get_tex_depth(ctx, dimensions, format, type, pixels, texImage); |
||
728 | } |
||
729 | else if (format == GL_DEPTH_STENCIL_EXT) { |
||
730 | get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); |
||
731 | } |
||
732 | else if (format == GL_STENCIL_INDEX) { |
||
733 | get_tex_stencil(ctx, dimensions, format, type, pixels, texImage); |
||
734 | } |
||
735 | else if (format == GL_YCBCR_MESA) { |
||
736 | get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); |
||
737 | } |
||
738 | else { |
||
739 | get_tex_rgba(ctx, dimensions, format, type, pixels, texImage); |
||
740 | } |
||
741 | |||
742 | if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { |
||
743 | ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); |
||
744 | } |
||
745 | } |
||
746 | |||
747 | |||
748 | |||
749 | /** |
||
750 | * This is the software fallback for Driver.GetCompressedTexImage(). |
||
751 | * All error checking will have been done before this routine is called. |
||
752 | */ |
||
753 | void |
||
754 | _mesa_GetCompressedTexImage_sw(struct gl_context *ctx, |
||
755 | struct gl_texture_image *texImage, |
||
756 | GLvoid *img) |
||
757 | { |
||
758 | const GLuint dimensions = |
||
759 | _mesa_get_texture_dimensions(texImage->TexObject->Target); |
||
760 | struct compressed_pixelstore store; |
||
761 | GLint slice; |
||
762 | GLubyte *dest; |
||
763 | |||
764 | _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat, |
||
765 | texImage->Width, texImage->Height, |
||
766 | texImage->Depth, |
||
767 | &ctx->Pack, |
||
768 | &store); |
||
769 | |||
770 | if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { |
||
771 | /* pack texture image into a PBO */ |
||
772 | dest = (GLubyte *) |
||
773 | ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, |
||
774 | GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, |
||
775 | MAP_INTERNAL); |
||
776 | if (!dest) { |
||
777 | /* out of memory or other unexpected error */ |
||
778 | _mesa_error(ctx, GL_OUT_OF_MEMORY, |
||
779 | "glGetCompresssedTexImage(map PBO failed)"); |
||
780 | return; |
||
781 | } |
||
782 | dest = ADD_POINTERS(dest, img); |
||
783 | } else { |
||
784 | dest = img; |
||
785 | } |
||
786 | |||
787 | dest += store.SkipBytes; |
||
788 | |||
789 | for (slice = 0; slice < store.CopySlices; slice++) { |
||
790 | GLint srcRowStride; |
||
791 | GLubyte *src; |
||
792 | |||
793 | /* map src texture buffer */ |
||
794 | ctx->Driver.MapTextureImage(ctx, texImage, slice, |
||
795 | 0, 0, texImage->Width, texImage->Height, |
||
796 | GL_MAP_READ_BIT, &src, &srcRowStride); |
||
797 | |||
798 | if (src) { |
||
799 | GLint i; |
||
800 | for (i = 0; i < store.CopyRowsPerSlice; i++) { |
||
801 | memcpy(dest, src, store.CopyBytesPerRow); |
||
802 | dest += store.TotalBytesPerRow; |
||
803 | src += srcRowStride; |
||
804 | } |
||
805 | |||
806 | ctx->Driver.UnmapTextureImage(ctx, texImage, slice); |
||
807 | |||
808 | /* Advance to next slice */ |
||
809 | dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice - store.CopyRowsPerSlice); |
||
810 | |||
811 | } else { |
||
812 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); |
||
813 | } |
||
814 | } |
||
815 | |||
816 | if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { |
||
817 | ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); |
||
818 | } |
||
819 | } |
||
820 | |||
821 | |||
822 | /** |
||
823 | * Validate the texture target enum supplied to glGetTex(ture)Image or |
||
824 | * glGetCompressedTex(ture)Image. |
||
825 | */ |
||
826 | static GLboolean |
||
827 | legal_getteximage_target(struct gl_context *ctx, GLenum target, bool dsa) |
||
828 | { |
||
829 | switch (target) { |
||
830 | case GL_TEXTURE_1D: |
||
831 | case GL_TEXTURE_2D: |
||
832 | case GL_TEXTURE_3D: |
||
833 | return GL_TRUE; |
||
834 | case GL_TEXTURE_RECTANGLE_NV: |
||
835 | return ctx->Extensions.NV_texture_rectangle; |
||
836 | case GL_TEXTURE_1D_ARRAY_EXT: |
||
837 | case GL_TEXTURE_2D_ARRAY_EXT: |
||
838 | return ctx->Extensions.EXT_texture_array; |
||
839 | case GL_TEXTURE_CUBE_MAP_ARRAY: |
||
840 | return ctx->Extensions.ARB_texture_cube_map_array; |
||
841 | |||
842 | /* Section 8.11 (Texture Queries) of the OpenGL 4.5 core profile spec |
||
843 | * (30.10.2014) says: |
||
844 | * "An INVALID_ENUM error is generated if the effective target is not |
||
845 | * one of TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_1D_ARRAY, |
||
846 | * TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, TEXTURE_RECTANGLE, one of |
||
847 | * the targets from table 8.19 (for GetTexImage and GetnTexImage *only*), |
||
848 | * or TEXTURE_CUBE_MAP (for GetTextureImage *only*)." (Emphasis added.) |
||
849 | */ |
||
850 | case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: |
||
851 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: |
||
852 | case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: |
||
853 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: |
||
854 | case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: |
||
855 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: |
||
856 | return dsa ? GL_FALSE : ctx->Extensions.ARB_texture_cube_map; |
||
857 | case GL_TEXTURE_CUBE_MAP: |
||
858 | return dsa ? GL_TRUE : GL_FALSE; |
||
859 | default: |
||
860 | return GL_FALSE; |
||
861 | } |
||
862 | } |
||
863 | |||
864 | |||
865 | /** |
||
866 | * Do error checking for a glGetTex(ture)Image() call. |
||
867 | * \return GL_TRUE if any error, GL_FALSE if no errors. |
||
868 | */ |
||
869 | static GLboolean |
||
870 | getteximage_error_check(struct gl_context *ctx, |
||
871 | struct gl_texture_image *texImage, |
||
872 | GLenum target, GLint level, |
||
873 | GLenum format, GLenum type, GLsizei clientMemSize, |
||
874 | GLvoid *pixels, bool dsa) |
||
875 | { |
||
876 | const GLint maxLevels = _mesa_max_texture_levels(ctx, target); |
||
877 | const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; |
||
878 | GLenum baseFormat; |
||
879 | const char *suffix = dsa ? "ture" : ""; |
||
880 | |||
881 | assert(texImage); |
||
882 | assert(maxLevels != 0); |
||
883 | if (level < 0 || level >= maxLevels) { |
||
884 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
885 | "glGetTex%sImage(level out of range)", suffix); |
||
886 | return GL_TRUE; |
||
887 | } |
||
888 | |||
889 | /* |
||
890 | * Format and type checking has been moved up to GetnTexImage and |
||
891 | * GetTextureImage so that it happens before getting the texImage object. |
||
892 | */ |
||
893 | |||
894 | baseFormat = _mesa_get_format_base_format(texImage->TexFormat); |
||
895 | |||
896 | /* Make sure the requested image format is compatible with the |
||
897 | * texture's format. |
||
898 | */ |
||
899 | if (_mesa_is_color_format(format) |
||
900 | && !_mesa_is_color_format(baseFormat)) { |
||
901 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
902 | "glGetTex%sImage(format mismatch)", suffix); |
||
903 | return GL_TRUE; |
||
904 | } |
||
905 | else if (_mesa_is_depth_format(format) |
||
906 | && !_mesa_is_depth_format(baseFormat) |
||
907 | && !_mesa_is_depthstencil_format(baseFormat)) { |
||
908 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
909 | "glGetTex%sImage(format mismatch)", suffix); |
||
910 | return GL_TRUE; |
||
911 | } |
||
912 | else if (_mesa_is_stencil_format(format) |
||
913 | && !ctx->Extensions.ARB_texture_stencil8) { |
||
914 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
915 | "glGetTex%sImage(format=GL_STENCIL_INDEX)", suffix); |
||
916 | return GL_TRUE; |
||
917 | } |
||
918 | else if (_mesa_is_ycbcr_format(format) |
||
919 | && !_mesa_is_ycbcr_format(baseFormat)) { |
||
920 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
921 | "glGetTex%sImage(format mismatch)", suffix); |
||
922 | return GL_TRUE; |
||
923 | } |
||
924 | else if (_mesa_is_depthstencil_format(format) |
||
925 | && !_mesa_is_depthstencil_format(baseFormat)) { |
||
926 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
927 | "glGetTex%sImage(format mismatch)", suffix); |
||
928 | return GL_TRUE; |
||
929 | } |
||
930 | else if (!_mesa_is_stencil_format(format) && _mesa_is_enum_format_integer(format) != |
||
931 | _mesa_is_format_integer(texImage->TexFormat)) { |
||
932 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
933 | "glGetTex%sImage(format mismatch)", suffix); |
||
934 | return GL_TRUE; |
||
935 | } |
||
936 | |||
937 | if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, |
||
938 | texImage->Height, texImage->Depth, |
||
939 | format, type, clientMemSize, pixels)) { |
||
940 | if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { |
||
941 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
942 | "glGetTex%sImage(out of bounds PBO access)", suffix); |
||
943 | } else { |
||
944 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
945 | "%s(out of bounds access:" |
||
946 | " bufSize (%d) is too small)", |
||
947 | dsa ? "glGetTextureImage" : "glGetnTexImageARB", |
||
948 | clientMemSize); |
||
949 | } |
||
950 | return GL_TRUE; |
||
951 | } |
||
952 | |||
953 | if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { |
||
954 | /* PBO should not be mapped */ |
||
955 | if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { |
||
956 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
957 | "glGetTex%sImage(PBO is mapped)", suffix); |
||
958 | return GL_TRUE; |
||
959 | } |
||
960 | } |
||
961 | |||
962 | return GL_FALSE; |
||
963 | } |
||
964 | |||
965 | |||
966 | /** |
||
967 | * This is the implementation for glGetnTexImageARB, glGetTextureImage, |
||
968 | * and glGetTexImage. |
||
969 | * |
||
970 | * Requires caller to pass in texImage object because _mesa_GetTextureImage |
||
971 | * must handle the GL_TEXTURE_CUBE_MAP target. |
||
972 | * |
||
973 | * \param target texture target. |
||
974 | * \param level image level. |
||
975 | * \param format pixel data format for returned image. |
||
976 | * \param type pixel data type for returned image. |
||
977 | * \param bufSize size of the pixels data buffer. |
||
978 | * \param pixels returned pixel data. |
||
979 | * \param dsa True when the caller is an ARB_direct_state_access function, |
||
980 | * false otherwise |
||
981 | */ |
||
982 | void |
||
983 | _mesa_get_texture_image(struct gl_context *ctx, |
||
984 | struct gl_texture_object *texObj, |
||
985 | struct gl_texture_image *texImage, GLenum target, |
||
986 | GLint level, GLenum format, GLenum type, |
||
987 | GLsizei bufSize, GLvoid *pixels, bool dsa) |
||
988 | { |
||
989 | assert(texObj); |
||
990 | assert(texImage); |
||
991 | |||
992 | FLUSH_VERTICES(ctx, 0); |
||
993 | |||
994 | /* |
||
995 | * Legal target checking has been moved up to GetnTexImage and |
||
996 | * GetTextureImage so that it can be caught before receiving a NULL |
||
997 | * texImage object and exiting. |
||
998 | */ |
||
999 | |||
1000 | if (getteximage_error_check(ctx, texImage, target, level, format, |
||
1001 | type, bufSize, pixels, dsa)) { |
||
1002 | return; |
||
1003 | } |
||
1004 | |||
1005 | if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { |
||
1006 | /* not an error, do nothing */ |
||
1007 | return; |
||
1008 | } |
||
1009 | |||
1010 | if (_mesa_is_zero_size_texture(texImage)) |
||
1011 | return; |
||
1012 | |||
1013 | if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { |
||
1014 | _mesa_debug(ctx, "glGetTex%sImage(tex %u) format = %s, w=%d, h=%d," |
||
1015 | " dstFmt=0x%x, dstType=0x%x\n", |
||
1016 | dsa ? "ture": "", |
||
1017 | texObj->Name, |
||
1018 | _mesa_get_format_name(texImage->TexFormat), |
||
1019 | texImage->Width, texImage->Height, |
||
1020 | format, type); |
||
1021 | } |
||
1022 | |||
1023 | _mesa_lock_texture(ctx, texObj); |
||
1024 | { |
||
1025 | ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage); |
||
1026 | } |
||
1027 | _mesa_unlock_texture(ctx, texObj); |
||
1028 | } |
||
1029 | |||
1030 | /** |
||
1031 | * Get texture image. Called by glGetTexImage. |
||
1032 | * |
||
1033 | * \param target texture target. |
||
1034 | * \param level image level. |
||
1035 | * \param format pixel data format for returned image. |
||
1036 | * \param type pixel data type for returned image. |
||
1037 | * \param bufSize size of the pixels data buffer. |
||
1038 | * \param pixels returned pixel data. |
||
1039 | */ |
||
1040 | void GLAPIENTRY |
||
1041 | _mesa_GetnTexImageARB(GLenum target, GLint level, GLenum format, |
||
1042 | GLenum type, GLsizei bufSize, GLvoid *pixels) |
||
1043 | { |
||
1044 | struct gl_texture_object *texObj; |
||
1045 | struct gl_texture_image *texImage; |
||
1046 | GLenum err; |
||
1047 | GET_CURRENT_CONTEXT(ctx); |
||
1048 | |||
1049 | /* |
||
1050 | * This has been moved here because a format/type mismatch can cause a NULL |
||
1051 | * texImage object, which in turn causes the mismatch error to be |
||
1052 | * ignored. |
||
1053 | */ |
||
1054 | err = _mesa_error_check_format_and_type(ctx, format, type); |
||
1055 | if (err != GL_NO_ERROR) { |
||
1056 | _mesa_error(ctx, err, "glGetnTexImage(format/type)"); |
||
1057 | return; |
||
1058 | } |
||
1059 | |||
1060 | /* |
||
1061 | * Legal target checking has been moved here to prevent exiting with a NULL |
||
1062 | * texImage object. |
||
1063 | */ |
||
1064 | if (!legal_getteximage_target(ctx, target, false)) { |
||
1065 | _mesa_error(ctx, GL_INVALID_ENUM, "glGetnTexImage(target=0x%x)", |
||
1066 | target); |
||
1067 | return; |
||
1068 | } |
||
1069 | |||
1070 | texObj = _mesa_get_current_tex_object(ctx, target); |
||
1071 | if (!texObj) |
||
1072 | return; |
||
1073 | |||
1074 | texImage = _mesa_select_tex_image(texObj, target, level); |
||
1075 | if (!texImage) |
||
1076 | return; |
||
1077 | |||
1078 | _mesa_get_texture_image(ctx, texObj, texImage, target, level, format, type, |
||
1079 | bufSize, pixels, false); |
||
1080 | } |
||
1081 | |||
1082 | |||
1083 | void GLAPIENTRY |
||
1084 | _mesa_GetTexImage( GLenum target, GLint level, GLenum format, |
||
1085 | GLenum type, GLvoid *pixels ) |
||
1086 | { |
||
1087 | _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels); |
||
1088 | } |
||
1089 | |||
1090 | /** |
||
1091 | * Get texture image. |
||
1092 | * |
||
1093 | * \param texture texture name. |
||
1094 | * \param level image level. |
||
1095 | * \param format pixel data format for returned image. |
||
1096 | * \param type pixel data type for returned image. |
||
1097 | * \param bufSize size of the pixels data buffer. |
||
1098 | * \param pixels returned pixel data. |
||
1099 | */ |
||
1100 | void GLAPIENTRY |
||
1101 | _mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, |
||
1102 | GLenum type, GLsizei bufSize, GLvoid *pixels) |
||
1103 | { |
||
1104 | struct gl_texture_object *texObj; |
||
1105 | struct gl_texture_image *texImage; |
||
1106 | int i; |
||
1107 | GLint image_stride; |
||
1108 | GLenum err; |
||
1109 | GET_CURRENT_CONTEXT(ctx); |
||
1110 | |||
1111 | if (!ctx->Extensions.ARB_direct_state_access) { |
||
1112 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1113 | "glGetTextureImage(GL_ARB_direct_state_access " |
||
1114 | "is not supported)"); |
||
1115 | return; |
||
1116 | } |
||
1117 | |||
1118 | /* |
||
1119 | * This has been moved here because a format/type mismatch can cause a NULL |
||
1120 | * texImage object, which in turn causes the mismatch error to be |
||
1121 | * ignored. |
||
1122 | */ |
||
1123 | err = _mesa_error_check_format_and_type(ctx, format, type); |
||
1124 | if (err != GL_NO_ERROR) { |
||
1125 | _mesa_error(ctx, err, "glGetTextureImage(format/type)"); |
||
1126 | return; |
||
1127 | } |
||
1128 | |||
1129 | texObj = _mesa_lookup_texture_err(ctx, texture, "glGetTextureImage"); |
||
1130 | if (!texObj) |
||
1131 | return; |
||
1132 | |||
1133 | /* |
||
1134 | * Legal target checking has been moved here to prevent exiting with a NULL |
||
1135 | * texImage object. |
||
1136 | */ |
||
1137 | if (!legal_getteximage_target(ctx, texObj->Target, true)) { |
||
1138 | _mesa_error(ctx, GL_INVALID_ENUM, "glGetTextureImage(target=%s)", |
||
1139 | _mesa_lookup_enum_by_nr(texObj->Target)); |
||
1140 | return; |
||
1141 | } |
||
1142 | |||
1143 | /* Must handle special case GL_TEXTURE_CUBE_MAP. */ |
||
1144 | if (texObj->Target == GL_TEXTURE_CUBE_MAP) { |
||
1145 | |||
1146 | /* Make sure the texture object is a proper cube. |
||
1147 | * (See texturesubimage in teximage.c for details on why this check is |
||
1148 | * performed.) |
||
1149 | */ |
||
1150 | if (!_mesa_cube_level_complete(texObj, level)) { |
||
1151 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1152 | "glGetTextureImage(cube map incomplete)"); |
||
1153 | return; |
||
1154 | } |
||
1155 | |||
1156 | /* Copy each face. */ |
||
1157 | for (i = 0; i < 6; ++i) { |
||
1158 | texImage = texObj->Image[i][level]; |
||
1159 | assert(texImage); |
||
1160 | |||
1161 | _mesa_get_texture_image(ctx, texObj, texImage, texObj->Target, level, |
||
1162 | format, type, bufSize, pixels, true); |
||
1163 | |||
1164 | image_stride = _mesa_image_image_stride(&ctx->Pack, texImage->Width, |
||
1165 | texImage->Height, format, |
||
1166 | type); |
||
1167 | pixels = (GLubyte *) pixels + image_stride; |
||
1168 | bufSize -= image_stride; |
||
1169 | } |
||
1170 | } |
||
1171 | else { |
||
1172 | texImage = _mesa_select_tex_image(texObj, texObj->Target, level); |
||
1173 | if (!texImage) |
||
1174 | return; |
||
1175 | |||
1176 | _mesa_get_texture_image(ctx, texObj, texImage, texObj->Target, level, |
||
1177 | format, type, bufSize, pixels, true); |
||
1178 | } |
||
1179 | } |
||
1180 | |||
1181 | /** |
||
1182 | * Do error checking for a glGetCompressedTexImage() call. |
||
1183 | * \return GL_TRUE if any error, GL_FALSE if no errors. |
||
1184 | */ |
||
1185 | static GLboolean |
||
1186 | getcompressedteximage_error_check(struct gl_context *ctx, |
||
1187 | struct gl_texture_image *texImage, |
||
1188 | GLenum target, |
||
1189 | GLint level, GLsizei clientMemSize, |
||
1190 | GLvoid *img, bool dsa) |
||
1191 | { |
||
1192 | const GLint maxLevels = _mesa_max_texture_levels(ctx, target); |
||
1193 | GLuint compressedSize, dimensions; |
||
1194 | const char *suffix = dsa ? "ture" : ""; |
||
1195 | |||
1196 | assert(texImage); |
||
1197 | |||
1198 | if (!legal_getteximage_target(ctx, target, dsa)) { |
||
1199 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
1200 | "glGetCompressedTex%sImage(target=%s)", suffix, |
||
1201 | _mesa_lookup_enum_by_nr(target)); |
||
1202 | return GL_TRUE; |
||
1203 | } |
||
1204 | |||
1205 | assert(maxLevels != 0); |
||
1206 | if (level < 0 || level >= maxLevels) { |
||
1207 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
1208 | "glGetCompressedTex%sImage(bad level = %d)", suffix, level); |
||
1209 | return GL_TRUE; |
||
1210 | } |
||
1211 | |||
1212 | if (!_mesa_is_format_compressed(texImage->TexFormat)) { |
||
1213 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1214 | "glGetCompressedTex%sImage(texture is not compressed)", |
||
1215 | suffix); |
||
1216 | return GL_TRUE; |
||
1217 | } |
||
1218 | |||
1219 | compressedSize = _mesa_format_image_size(texImage->TexFormat, |
||
1220 | texImage->Width, |
||
1221 | texImage->Height, |
||
1222 | texImage->Depth); |
||
1223 | |||
1224 | /* Check for invalid pixel storage modes */ |
||
1225 | dimensions = _mesa_get_texture_dimensions(texImage->TexObject->Target); |
||
1226 | if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions, |
||
1227 | &ctx->Pack, dsa ? |
||
1228 | "glGetCompressedTextureImage": |
||
1229 | "glGetCompressedTexImage")) { |
||
1230 | return GL_TRUE; |
||
1231 | } |
||
1232 | |||
1233 | if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) { |
||
1234 | /* do bounds checking on writing to client memory */ |
||
1235 | if (clientMemSize < (GLsizei) compressedSize) { |
||
1236 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1237 | "%s(out of bounds access: bufSize (%d) is too small)", |
||
1238 | dsa ? "glGetCompressedTextureImage" : |
||
1239 | "glGetnCompressedTexImageARB", clientMemSize); |
||
1240 | return GL_TRUE; |
||
1241 | } |
||
1242 | } else { |
||
1243 | /* do bounds checking on PBO write */ |
||
1244 | if ((const GLubyte *) img + compressedSize > |
||
1245 | (const GLubyte *) ctx->Pack.BufferObj->Size) { |
||
1246 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1247 | "glGetCompressedTex%sImage(out of bounds PBO access)", |
||
1248 | suffix); |
||
1249 | return GL_TRUE; |
||
1250 | } |
||
1251 | |||
1252 | /* make sure PBO is not mapped */ |
||
1253 | if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { |
||
1254 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1255 | "glGetCompressedTex%sImage(PBO is mapped)", suffix); |
||
1256 | return GL_TRUE; |
||
1257 | } |
||
1258 | } |
||
1259 | |||
1260 | return GL_FALSE; |
||
1261 | } |
||
1262 | |||
1263 | /** Implements glGetnCompressedTexImageARB, glGetCompressedTexImage, and |
||
1264 | * glGetCompressedTextureImage. |
||
1265 | * |
||
1266 | * texImage must be passed in because glGetCompressedTexImage must handle the |
||
1267 | * target GL_TEXTURE_CUBE_MAP. |
||
1268 | */ |
||
1269 | void |
||
1270 | _mesa_get_compressed_texture_image(struct gl_context *ctx, |
||
1271 | struct gl_texture_object *texObj, |
||
1272 | struct gl_texture_image *texImage, |
||
1273 | GLenum target, GLint level, |
||
1274 | GLsizei bufSize, GLvoid *pixels, |
||
1275 | bool dsa) |
||
1276 | { |
||
1277 | assert(texObj); |
||
1278 | assert(texImage); |
||
1279 | |||
1280 | FLUSH_VERTICES(ctx, 0); |
||
1281 | |||
1282 | if (getcompressedteximage_error_check(ctx, texImage, target, level, |
||
1283 | bufSize, pixels, dsa)) { |
||
1284 | return; |
||
1285 | } |
||
1286 | |||
1287 | if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { |
||
1288 | /* not an error, do nothing */ |
||
1289 | return; |
||
1290 | } |
||
1291 | |||
1292 | if (_mesa_is_zero_size_texture(texImage)) |
||
1293 | return; |
||
1294 | |||
1295 | if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { |
||
1296 | _mesa_debug(ctx, |
||
1297 | "glGetCompressedTex%sImage(tex %u) format = %s, w=%d, h=%d\n", |
||
1298 | dsa ? "ture" : "", texObj->Name, |
||
1299 | _mesa_get_format_name(texImage->TexFormat), |
||
1300 | texImage->Width, texImage->Height); |
||
1301 | } |
||
1302 | |||
1303 | _mesa_lock_texture(ctx, texObj); |
||
1304 | { |
||
1305 | ctx->Driver.GetCompressedTexImage(ctx, texImage, pixels); |
||
1306 | } |
||
1307 | _mesa_unlock_texture(ctx, texObj); |
||
1308 | } |
||
1309 | |||
1310 | void GLAPIENTRY |
||
1311 | _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, |
||
1312 | GLvoid *img) |
||
1313 | { |
||
1314 | struct gl_texture_object *texObj; |
||
1315 | struct gl_texture_image *texImage; |
||
1316 | GET_CURRENT_CONTEXT(ctx); |
||
1317 | |||
1318 | texObj = _mesa_get_current_tex_object(ctx, target); |
||
1319 | if (!texObj) |
||
1320 | return; |
||
1321 | |||
1322 | texImage = _mesa_select_tex_image(texObj, target, level); |
||
1323 | if (!texImage) |
||
1324 | return; |
||
1325 | |||
1326 | _mesa_get_compressed_texture_image(ctx, texObj, texImage, target, level, |
||
1327 | bufSize, img, false); |
||
1328 | } |
||
1329 | |||
1330 | void GLAPIENTRY |
||
1331 | _mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img) |
||
1332 | { |
||
1333 | _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); |
||
1334 | } |
||
1335 | |||
1336 | /** |
||
1337 | * Get compressed texture image. |
||
1338 | * |
||
1339 | * \param texture texture name. |
||
1340 | * \param level image level. |
||
1341 | * \param bufSize size of the pixels data buffer. |
||
1342 | * \param pixels returned pixel data. |
||
1343 | */ |
||
1344 | void GLAPIENTRY |
||
1345 | _mesa_GetCompressedTextureImage(GLuint texture, GLint level, |
||
1346 | GLsizei bufSize, GLvoid *pixels) |
||
1347 | { |
||
1348 | struct gl_texture_object *texObj; |
||
1349 | struct gl_texture_image *texImage; |
||
1350 | int i; |
||
1351 | GLint image_stride; |
||
1352 | GET_CURRENT_CONTEXT(ctx); |
||
1353 | |||
1354 | if (!ctx->Extensions.ARB_direct_state_access) { |
||
1355 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1356 | "glGetCompressedTextureImage(GL_ARB_direct_state_access " |
||
1357 | "is not supported)"); |
||
1358 | return; |
||
1359 | } |
||
1360 | |||
1361 | texObj = _mesa_lookup_texture_err(ctx, texture, |
||
1362 | "glGetCompressedTextureImage"); |
||
1363 | if (!texObj) |
||
1364 | return; |
||
1365 | |||
1366 | /* Must handle special case GL_TEXTURE_CUBE_MAP. */ |
||
1367 | if (texObj->Target == GL_TEXTURE_CUBE_MAP) { |
||
1368 | |||
1369 | /* Make sure the texture object is a proper cube. |
||
1370 | * (See texturesubimage in teximage.c for details on why this check is |
||
1371 | * performed.) |
||
1372 | */ |
||
1373 | if (!_mesa_cube_level_complete(texObj, level)) { |
||
1374 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1375 | "glGetCompressedTextureImage(cube map incomplete)"); |
||
1376 | return; |
||
1377 | } |
||
1378 | |||
1379 | /* Copy each face. */ |
||
1380 | for (i = 0; i < 6; ++i) { |
||
1381 | texImage = texObj->Image[i][level]; |
||
1382 | assert(texImage); |
||
1383 | |||
1384 | _mesa_get_compressed_texture_image(ctx, texObj, texImage, |
||
1385 | texObj->Target, level, |
||
1386 | bufSize, pixels, true); |
||
1387 | |||
1388 | /* Compressed images don't have a client format */ |
||
1389 | image_stride = _mesa_format_image_size(texImage->TexFormat, |
||
1390 | texImage->Width, |
||
1391 | texImage->Height, 1); |
||
1392 | |||
1393 | pixels = (GLubyte *) pixels + image_stride; |
||
1394 | bufSize -= image_stride; |
||
1395 | } |
||
1396 | } |
||
1397 | else { |
||
1398 | texImage = _mesa_select_tex_image(texObj, texObj->Target, level); |
||
1399 | if (!texImage) |
||
1400 | return; |
||
1401 | |||
1402 | _mesa_get_compressed_texture_image(ctx, texObj, texImage, |
||
1403 | texObj->Target, level, bufSize, |
||
1404 | pixels, true); |
||
1405 | } |
||
1406 | }>>>>>>>>>>>>>>>>>>> |