3f49b40d9c17536c9a63698b4a9ab3b3020aa21d
[mesa.git] / src / mesa / swrast / s_texstore.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /*
26 * Authors:
27 * Brian Paul
28 */
29
30
31 /*
32 * The functions in this file are mostly related to software texture fallbacks.
33 * This includes texture image transfer/packing and texel fetching.
34 * Hardware drivers will likely override most of this.
35 */
36
37
38
39 #include "glheader.h"
40 #include "imports.h"
41 #include "colormac.h"
42 #include "context.h"
43 #include "convolve.h"
44 #include "image.h"
45 #include "macros.h"
46 #include "mipmap.h"
47 #include "texformat.h"
48 #include "teximage.h"
49 #include "texstore.h"
50
51 #include "s_context.h"
52 #include "s_depth.h"
53 #include "s_span.h"
54
55
56 /**
57 * Read an RGBA image from the frame buffer.
58 * This is used by glCopyTex[Sub]Image[12]D().
59 * \param x window source x
60 * \param y window source y
61 * \param width image width
62 * \param height image height
63 * \param type datatype for returned GL_RGBA image
64 * \return pointer to image
65 */
66 static GLvoid *
67 read_color_image( GLcontext *ctx, GLint x, GLint y, GLenum type,
68 GLsizei width, GLsizei height )
69 {
70 SWcontext *swrast = SWRAST_CONTEXT(ctx);
71 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
72 const GLint pixelSize = _mesa_bytes_per_pixel(GL_RGBA, type);
73 const GLint stride = width * pixelSize;
74 GLint row;
75 GLubyte *image, *dst;
76
77 image = (GLubyte *) _mesa_malloc(width * height * pixelSize);
78 if (!image)
79 return NULL;
80
81 RENDER_START(swrast, ctx);
82
83 dst = image;
84 for (row = 0; row < height; row++) {
85 _swrast_read_rgba_span(ctx, rb, width, x, y + row, type, dst);
86 dst += stride;
87 }
88
89 RENDER_FINISH(swrast, ctx);
90
91 return image;
92 }
93
94
95 /**
96 * As above, but read data from depth buffer. Returned as GLuints.
97 * \sa read_color_image
98 */
99 static GLuint *
100 read_depth_image( GLcontext *ctx, GLint x, GLint y,
101 GLsizei width, GLsizei height )
102 {
103 struct gl_renderbuffer *rb = ctx->ReadBuffer->_DepthBuffer;
104 SWcontext *swrast = SWRAST_CONTEXT(ctx);
105 GLuint *image, *dst;
106 GLint i;
107
108 image = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint));
109 if (!image)
110 return NULL;
111
112 RENDER_START(swrast, ctx);
113
114 dst = image;
115 for (i = 0; i < height; i++) {
116 _swrast_read_depth_span_uint(ctx, rb, width, x, y + i, dst);
117 dst += width;
118 }
119
120 RENDER_FINISH(swrast, ctx);
121
122 return image;
123 }
124
125
126 /**
127 * As above, but read data from depth+stencil buffers.
128 */
129 static GLuint *
130 read_depth_stencil_image(GLcontext *ctx, GLint x, GLint y,
131 GLsizei width, GLsizei height)
132 {
133 struct gl_renderbuffer *depthRb = ctx->ReadBuffer->_DepthBuffer;
134 struct gl_renderbuffer *stencilRb = ctx->ReadBuffer->_StencilBuffer;
135 SWcontext *swrast = SWRAST_CONTEXT(ctx);
136 GLuint *image, *dst;
137 GLint i;
138
139 ASSERT(depthRb);
140 ASSERT(stencilRb);
141
142 image = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint));
143 if (!image)
144 return NULL;
145
146 RENDER_START(swrast, ctx);
147
148 /* read from depth buffer */
149 dst = image;
150 if (depthRb->DataType == GL_UNSIGNED_INT) {
151 for (i = 0; i < height; i++) {
152 _swrast_get_row(ctx, depthRb, width, x, y + i, dst, sizeof(GLuint));
153 dst += width;
154 }
155 }
156 else {
157 GLushort z16[MAX_WIDTH];
158 ASSERT(depthRb->DataType == GL_UNSIGNED_SHORT);
159 for (i = 0; i < height; i++) {
160 GLint j;
161 _swrast_get_row(ctx, depthRb, width, x, y + i, z16, sizeof(GLushort));
162 /* convert GLushorts to GLuints */
163 for (j = 0; j < width; j++) {
164 dst[j] = z16[j];
165 }
166 dst += width;
167 }
168 }
169
170 /* put depth values into bits 0xffffff00 */
171 if (ctx->ReadBuffer->Visual.depthBits == 24) {
172 GLint j;
173 for (j = 0; j < width * height; j++) {
174 image[j] <<= 8;
175 }
176 }
177 else if (ctx->ReadBuffer->Visual.depthBits == 16) {
178 GLint j;
179 for (j = 0; j < width * height; j++) {
180 image[j] = (image[j] << 16) | (image[j] & 0xff00);
181 }
182 }
183 else {
184 /* this handles arbitrary depthBits >= 12 */
185 const GLint rShift = ctx->ReadBuffer->Visual.depthBits;
186 const GLint lShift = 32 - rShift;
187 GLint j;
188 for (j = 0; j < width * height; j++) {
189 GLuint z = (image[j] << lShift);
190 image[j] = z | (z >> rShift);
191 }
192 }
193
194 /* read stencil values and interleave into image array */
195 dst = image;
196 for (i = 0; i < height; i++) {
197 GLstencil stencil[MAX_WIDTH];
198 GLint j;
199 ASSERT(8 * sizeof(GLstencil) == stencilRb->StencilBits);
200 _swrast_get_row(ctx, stencilRb, width, x, y + i,
201 stencil, sizeof(GLstencil));
202 for (j = 0; j < width; j++) {
203 dst[j] = (dst[j] & 0xffffff00) | (stencil[j] & 0xff);
204 }
205 dst += width;
206 }
207
208 RENDER_FINISH(swrast, ctx);
209
210 return image;
211 }
212
213
214 static GLboolean
215 is_depth_format(GLenum format)
216 {
217 switch (format) {
218 case GL_DEPTH_COMPONENT:
219 case GL_DEPTH_COMPONENT16_SGIX:
220 case GL_DEPTH_COMPONENT24_SGIX:
221 case GL_DEPTH_COMPONENT32_SGIX:
222 return GL_TRUE;
223 default:
224 return GL_FALSE;
225 }
226 }
227
228
229 static GLboolean
230 is_depth_stencil_format(GLenum format)
231 {
232 switch (format) {
233 case GL_DEPTH_STENCIL_EXT:
234 case GL_DEPTH24_STENCIL8_EXT:
235 return GL_TRUE;
236 default:
237 return GL_FALSE;
238 }
239 }
240
241
242 /*
243 * Fallback for Driver.CopyTexImage1D().
244 */
245 void
246 _swrast_copy_teximage1d( GLcontext *ctx, GLenum target, GLint level,
247 GLenum internalFormat,
248 GLint x, GLint y, GLsizei width, GLint border )
249 {
250 struct gl_texture_unit *texUnit;
251 struct gl_texture_object *texObj;
252 struct gl_texture_image *texImage;
253
254 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
255 texObj = _mesa_select_tex_object(ctx, texUnit, target);
256 ASSERT(texObj);
257 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
258 ASSERT(texImage);
259
260 ASSERT(ctx->Driver.TexImage1D);
261
262 if (is_depth_format(internalFormat)) {
263 /* read depth image from framebuffer */
264 GLuint *image = read_depth_image(ctx, x, y, width, 1);
265 if (!image) {
266 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
267 return;
268 }
269 /* call glTexImage1D to redefine the texture */
270 ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
271 width, border,
272 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image,
273 &ctx->DefaultPacking, texObj, texImage);
274 _mesa_free(image);
275 }
276 else if (is_depth_stencil_format(internalFormat)) {
277 /* read depth/stencil image from framebuffer */
278 GLuint *image = read_depth_stencil_image(ctx, x, y, width, 1);
279 if (!image) {
280 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
281 return;
282 }
283 /* call glTexImage1D to redefine the texture */
284 ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
285 width, border,
286 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT,
287 image, &ctx->DefaultPacking, texObj, texImage);
288 _mesa_free(image);
289 }
290 else {
291 /* read RGBA image from framebuffer */
292 const GLenum format = GL_RGBA;
293 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
294 GLvoid *image = read_color_image(ctx, x, y, type, width, 1);
295 if (!image) {
296 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
297 return;
298 }
299 /* call glTexImage1D to redefine the texture */
300 ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
301 width, border, format, type, image,
302 &ctx->DefaultPacking, texObj, texImage);
303 _mesa_free(image);
304 }
305
306 /* GL_SGIS_generate_mipmap */
307 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
308 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
309 }
310 }
311
312
313 /**
314 * Fallback for Driver.CopyTexImage2D().
315 *
316 * We implement CopyTexImage by reading the image from the framebuffer
317 * then passing it to the ctx->Driver.TexImage2D() function.
318 *
319 * Device drivers should try to implement direct framebuffer->texture copies.
320 */
321 void
322 _swrast_copy_teximage2d( GLcontext *ctx, GLenum target, GLint level,
323 GLenum internalFormat,
324 GLint x, GLint y, GLsizei width, GLsizei height,
325 GLint border )
326 {
327 struct gl_texture_unit *texUnit;
328 struct gl_texture_object *texObj;
329 struct gl_texture_image *texImage;
330
331 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
332 texObj = _mesa_select_tex_object(ctx, texUnit, target);
333 ASSERT(texObj);
334 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
335 ASSERT(texImage);
336
337 ASSERT(ctx->Driver.TexImage2D);
338
339 if (is_depth_format(internalFormat)) {
340 /* read depth image from framebuffer */
341 GLuint *image = read_depth_image(ctx, x, y, width, height);
342 if (!image) {
343 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
344 return;
345 }
346 /* call glTexImage2D to redefine the texture */
347 ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
348 width, height, border,
349 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image,
350 &ctx->DefaultPacking, texObj, texImage);
351 _mesa_free(image);
352 }
353 else if (is_depth_stencil_format(internalFormat)) {
354 GLuint *image = read_depth_stencil_image(ctx, x, y, width, height);
355 if (!image) {
356 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
357 return;
358 }
359 /* call glTexImage2D to redefine the texture */
360 ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
361 width, height, border,
362 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT,
363 image, &ctx->DefaultPacking, texObj, texImage);
364 _mesa_free(image);
365 }
366 else {
367 /* read RGBA image from framebuffer */
368 const GLenum format = GL_RGBA;
369 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
370 GLvoid *image = read_color_image(ctx, x, y, type, width, height);
371 if (!image) {
372 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
373 return;
374 }
375 /* call glTexImage2D to redefine the texture */
376 ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
377 width, height, border, format, type, image,
378 &ctx->DefaultPacking, texObj, texImage);
379 _mesa_free(image);
380 }
381
382 /* GL_SGIS_generate_mipmap */
383 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
384 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
385 }
386 }
387
388
389 /*
390 * Fallback for Driver.CopyTexSubImage1D().
391 */
392 void
393 _swrast_copy_texsubimage1d( GLcontext *ctx, GLenum target, GLint level,
394 GLint xoffset, GLint x, GLint y, GLsizei width )
395 {
396 struct gl_texture_unit *texUnit;
397 struct gl_texture_object *texObj;
398 struct gl_texture_image *texImage;
399
400 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
401 texObj = _mesa_select_tex_object(ctx, texUnit, target);
402 ASSERT(texObj);
403 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
404 ASSERT(texImage);
405
406 ASSERT(ctx->Driver.TexImage1D);
407
408 if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) {
409 /* read depth image from framebuffer */
410 GLuint *image = read_depth_image(ctx, x, y, width, 1);
411 if (!image) {
412 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D");
413 return;
414 }
415
416 /* call glTexSubImage1D to redefine the texture */
417 ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width,
418 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image,
419 &ctx->DefaultPacking, texObj, texImage);
420 _mesa_free(image);
421 }
422 else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
423 /* read depth/stencil image from framebuffer */
424 GLuint *image = read_depth_stencil_image(ctx, x, y, width, 1);
425 if (!image) {
426 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D");
427 return;
428 }
429 /* call glTexImage1D to redefine the texture */
430 ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width,
431 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT,
432 image, &ctx->DefaultPacking, texObj, texImage);
433 _mesa_free(image);
434 }
435 else {
436 /* read RGBA image from framebuffer */
437 const GLenum format = GL_RGBA;
438 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
439 GLvoid *image = read_color_image(ctx, x, y, type, width, 1);
440 if (!image) {
441 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D" );
442 return;
443 }
444 /* now call glTexSubImage1D to do the real work */
445 ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width,
446 format, type, image,
447 &ctx->DefaultPacking, texObj, texImage);
448 _mesa_free(image);
449 }
450
451 /* GL_SGIS_generate_mipmap */
452 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
453 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
454 }
455 }
456
457
458 /**
459 * Fallback for Driver.CopyTexSubImage2D().
460 *
461 * Read the image from the framebuffer then hand it
462 * off to ctx->Driver.TexSubImage2D().
463 */
464 void
465 _swrast_copy_texsubimage2d( GLcontext *ctx,
466 GLenum target, GLint level,
467 GLint xoffset, GLint yoffset,
468 GLint x, GLint y, GLsizei width, GLsizei height )
469 {
470 struct gl_texture_unit *texUnit;
471 struct gl_texture_object *texObj;
472 struct gl_texture_image *texImage;
473
474 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
475 texObj = _mesa_select_tex_object(ctx, texUnit, target);
476 ASSERT(texObj);
477 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
478 ASSERT(texImage);
479
480 ASSERT(ctx->Driver.TexImage2D);
481
482 if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) {
483 /* read depth image from framebuffer */
484 GLuint *image = read_depth_image(ctx, x, y, width, height);
485 if (!image) {
486 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D");
487 return;
488 }
489 /* call glTexImage2D to redefine the texture */
490 ctx->Driver.TexSubImage2D(ctx, target, level,
491 xoffset, yoffset, width, height,
492 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image,
493 &ctx->DefaultPacking, texObj, texImage);
494 _mesa_free(image);
495 }
496 else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
497 /* read depth/stencil image from framebuffer */
498 GLuint *image = read_depth_stencil_image(ctx, x, y, width, height);
499 if (!image) {
500 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D");
501 return;
502 }
503 /* call glTexImage2D to redefine the texture */
504 ctx->Driver.TexSubImage2D(ctx, target, level,
505 xoffset, yoffset, width, height,
506 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT,
507 image, &ctx->DefaultPacking, texObj, texImage);
508 _mesa_free(image);
509 }
510 else {
511 /* read RGBA image from framebuffer */
512 const GLenum format = GL_RGBA;
513 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
514 GLvoid *image = read_color_image(ctx, x, y, type, width, height);
515 if (!image) {
516 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D" );
517 return;
518 }
519 /* now call glTexSubImage2D to do the real work */
520 ctx->Driver.TexSubImage2D(ctx, target, level,
521 xoffset, yoffset, width, height,
522 format, type, image,
523 &ctx->DefaultPacking, texObj, texImage);
524 _mesa_free(image);
525 }
526
527 /* GL_SGIS_generate_mipmap */
528 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
529 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
530 }
531 }
532
533
534 /*
535 * Fallback for Driver.CopyTexSubImage3D().
536 */
537 void
538 _swrast_copy_texsubimage3d( GLcontext *ctx,
539 GLenum target, GLint level,
540 GLint xoffset, GLint yoffset, GLint zoffset,
541 GLint x, GLint y, GLsizei width, GLsizei height )
542 {
543 struct gl_texture_unit *texUnit;
544 struct gl_texture_object *texObj;
545 struct gl_texture_image *texImage;
546
547 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
548 texObj = _mesa_select_tex_object(ctx, texUnit, target);
549 ASSERT(texObj);
550 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
551 ASSERT(texImage);
552
553 ASSERT(ctx->Driver.TexImage3D);
554
555 if (texImage->_BaseFormat == GL_DEPTH_COMPONENT) {
556 /* read depth image from framebuffer */
557 GLuint *image = read_depth_image(ctx, x, y, width, height);
558 if (!image) {
559 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D");
560 return;
561 }
562 /* call glTexImage3D to redefine the texture */
563 ctx->Driver.TexSubImage3D(ctx, target, level,
564 xoffset, yoffset, zoffset, width, height, 1,
565 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image,
566 &ctx->DefaultPacking, texObj, texImage);
567 _mesa_free(image);
568 }
569 else if (texImage->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
570 /* read depth/stencil image from framebuffer */
571 GLuint *image = read_depth_stencil_image(ctx, x, y, width, height);
572 if (!image) {
573 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D");
574 return;
575 }
576 /* call glTexImage3D to redefine the texture */
577 ctx->Driver.TexSubImage3D(ctx, target, level,
578 xoffset, yoffset, zoffset, width, height, 1,
579 GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT,
580 image, &ctx->DefaultPacking, texObj, texImage);
581 _mesa_free(image);
582 }
583 else {
584 /* read RGBA image from framebuffer */
585 const GLenum format = GL_RGBA;
586 const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
587 GLvoid *image = read_color_image(ctx, x, y, type, width, height);
588 if (!image) {
589 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D" );
590 return;
591 }
592 /* now call glTexSubImage3D to do the real work */
593 ctx->Driver.TexSubImage3D(ctx, target, level,
594 xoffset, yoffset, zoffset, width, height, 1,
595 format, type, image,
596 &ctx->DefaultPacking, texObj, texImage);
597 _mesa_free(image);
598 }
599
600 /* GL_SGIS_generate_mipmap */
601 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
602 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
603 }
604 }