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