2ed4c6c9540d5946c32cc991863e7cbf2ee278ce
[mesa.git] / src / mesa / swrast / s_texstore.c
1 /* $Id: s_texstore.c,v 1.7 2002/09/16 17:57:14 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 /*
28 * Authors:
29 * Brian Paul
30 */
31
32
33 /*
34 * The functions in this file are mostly related to software texture fallbacks.
35 * This includes texture image transfer/packing and texel fetching.
36 * Hardware drivers will likely override most of this.
37 */
38
39
40
41 #include "colormac.h"
42 #include "context.h"
43 #include "convolve.h"
44 #include "image.h"
45 #include "macros.h"
46 #include "mem.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 * Read an RGBA image from the frame buffer.
57 * This is used by glCopyTex[Sub]Image[12]D().
58 * Input: ctx - the context
59 * x, y - lower left corner
60 * width, height - size of region to read
61 * Return: pointer to block of GL_RGBA, GLchan data.
62 */
63 static GLchan *
64 read_color_image( GLcontext *ctx, GLint x, GLint y,
65 GLsizei width, GLsizei height )
66 {
67 SWcontext *swrast = SWRAST_CONTEXT(ctx);
68 GLint stride, i;
69 GLchan *image, *dst;
70
71 image = (GLchan *) MALLOC(width * height * 4 * sizeof(GLchan));
72 if (!image)
73 return NULL;
74
75 /* Select buffer to read from */
76 _swrast_use_read_buffer(ctx);
77
78 RENDER_START(swrast,ctx);
79
80 dst = image;
81 stride = width * 4;
82 for (i = 0; i < height; i++) {
83 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, x, y + i,
84 (GLchan (*)[4]) dst );
85 dst += stride;
86 }
87
88 RENDER_FINISH(swrast,ctx);
89
90 /* Read from draw buffer (the default) */
91 _swrast_use_draw_buffer(ctx);
92
93 return image;
94 }
95
96
97 /*
98 * As above, but read data from depth buffer.
99 */
100 static GLfloat *
101 read_depth_image( GLcontext *ctx, GLint x, GLint y,
102 GLsizei width, GLsizei height )
103 {
104 SWcontext *swrast = SWRAST_CONTEXT(ctx);
105 GLfloat *image, *dst;
106 GLint i;
107
108 image = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
109 if (!image)
110 return NULL;
111
112 RENDER_START(swrast,ctx);
113
114 dst = image;
115 for (i = 0; i < height; i++) {
116 _mesa_read_depth_span_float(ctx, width, x, y + i, dst);
117 dst += width;
118 }
119
120 RENDER_FINISH(swrast,ctx);
121
122 return image;
123 }
124
125
126
127 static GLboolean
128 is_depth_format(GLenum format)
129 {
130 switch (format) {
131 case GL_DEPTH_COMPONENT:
132 case GL_DEPTH_COMPONENT16_SGIX:
133 case GL_DEPTH_COMPONENT24_SGIX:
134 case GL_DEPTH_COMPONENT32_SGIX:
135 return GL_TRUE;
136 default:
137 return GL_FALSE;
138 }
139 }
140
141
142 /*
143 * Fallback for Driver.CopyTexImage1D().
144 */
145 void
146 _swrast_copy_teximage1d( GLcontext *ctx, GLenum target, GLint level,
147 GLenum internalFormat,
148 GLint x, GLint y, GLsizei width, GLint border )
149 {
150 struct gl_texture_unit *texUnit;
151 struct gl_texture_object *texObj;
152 struct gl_texture_image *texImage;
153
154 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
155 texObj = _mesa_select_tex_object(ctx, texUnit, target);
156 ASSERT(texObj);
157 texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
158 ASSERT(texImage);
159
160 ASSERT(ctx->Driver.TexImage1D);
161
162 if (is_depth_format(internalFormat)) {
163 /* read depth image from framebuffer */
164 GLfloat *image = read_depth_image(ctx, x, y, width, 1);
165 if (!image) {
166 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
167 return;
168 }
169
170 /* call glTexImage1D to redefine the texture */
171 (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat,
172 width, border,
173 GL_DEPTH_COMPONENT, GL_FLOAT, image,
174 &_mesa_native_packing, texObj, texImage);
175 FREE(image);
176 }
177 else {
178 /* read RGBA image from framebuffer */
179 GLchan *image = read_color_image(ctx, x, y, width, 1);
180 if (!image) {
181 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
182 return;
183 }
184
185 /* call glTexImage1D to redefine the texture */
186 (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat,
187 width, border,
188 GL_RGBA, CHAN_TYPE, image,
189 &_mesa_native_packing, texObj, texImage);
190 FREE(image);
191 }
192
193 /* GL_SGIS_generate_mipmap */
194 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
195 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
196 }
197 }
198
199
200 /*
201 * Fallback for Driver.CopyTexImage2D().
202 */
203 void
204 _swrast_copy_teximage2d( GLcontext *ctx, GLenum target, GLint level,
205 GLenum internalFormat,
206 GLint x, GLint y, GLsizei width, GLsizei height,
207 GLint border )
208 {
209 struct gl_texture_unit *texUnit;
210 struct gl_texture_object *texObj;
211 struct gl_texture_image *texImage;
212
213 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
214 texObj = _mesa_select_tex_object(ctx, texUnit, target);
215 ASSERT(texObj);
216 texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
217 ASSERT(texImage);
218
219 ASSERT(ctx->Driver.TexImage2D);
220
221 if (is_depth_format(internalFormat)) {
222 /* read depth image from framebuffer */
223 GLfloat *image = read_depth_image(ctx, x, y, width, height);
224 if (!image) {
225 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
226 return;
227 }
228
229 /* call glTexImage2D to redefine the texture */
230 (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat,
231 width, height, border,
232 GL_DEPTH_COMPONENT, GL_FLOAT, image,
233 &_mesa_native_packing, texObj, texImage);
234 FREE(image);
235 }
236 else {
237 /* read RGBA image from framebuffer */
238 GLchan *image = read_color_image(ctx, x, y, width, height);
239 if (!image) {
240 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
241 return;
242 }
243
244 /* call glTexImage2D to redefine the texture */
245 (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat,
246 width, height, border,
247 GL_RGBA, CHAN_TYPE, image,
248 &_mesa_native_packing, texObj, texImage);
249 FREE(image);
250 }
251
252 /* GL_SGIS_generate_mipmap */
253 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
254 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
255 }
256 }
257
258
259 /*
260 * Fallback for Driver.CopyTexSubImage1D().
261 */
262 void
263 _swrast_copy_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
264 GLint xoffset, GLint x, GLint y, GLsizei width)
265 {
266 struct gl_texture_unit *texUnit;
267 struct gl_texture_object *texObj;
268 struct gl_texture_image *texImage;
269
270 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
271 texObj = _mesa_select_tex_object(ctx, texUnit, target);
272 ASSERT(texObj);
273 texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
274 ASSERT(texImage);
275
276 ASSERT(ctx->Driver.TexImage1D);
277
278 if (texImage->Format != GL_DEPTH_COMPONENT) {
279 /* read RGBA image from framebuffer */
280 GLchan *image = read_color_image(ctx, x, y, width, 1);
281 if (!image) {
282 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D" );
283 return;
284 }
285
286 #if 0
287 /*
288 * XXX this is a bit of a hack. We need to be sure that the alpha
289 * channel is 1.0 if the internal texture format is not supposed to
290 * have an alpha channel. This is because some drivers may store
291 * RGB textures as RGBA and the texutil.c code isn't smart enough
292 * to set the alpha channel to 1.0 in this situation.
293 */
294 if (texImage->Format == GL_LUMINANCE ||
295 texImage->Format == GL_RGB) {
296 const GLuint n = width * 4;
297 GLuint i;
298 for (i = 0; i < n; i += 4) {
299 image[i + 3] = CHAN_MAX;
300 }
301 }
302 #endif
303 /* now call glTexSubImage1D to do the real work */
304 (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width,
305 GL_RGBA, CHAN_TYPE, image,
306 &_mesa_native_packing, texObj, texImage);
307 FREE(image);
308 }
309 else {
310 /* read depth image from framebuffer */
311 GLfloat *image = read_depth_image(ctx, x, y, width, 1);
312 if (!image) {
313 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D");
314 return;
315 }
316
317 /* call glTexSubImage1D to redefine the texture */
318 (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width,
319 GL_DEPTH_COMPONENT, GL_FLOAT, image,
320 &_mesa_native_packing, texObj, texImage);
321 FREE(image);
322 }
323
324 /* GL_SGIS_generate_mipmap */
325 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
326 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
327 }
328 }
329
330
331 /*
332 * Fallback for Driver.CopyTexSubImage2D().
333 */
334 void
335 _swrast_copy_texsubimage2d( GLcontext *ctx,
336 GLenum target, GLint level,
337 GLint xoffset, GLint yoffset,
338 GLint x, GLint y, GLsizei width, GLsizei height )
339 {
340 struct gl_texture_unit *texUnit;
341 struct gl_texture_object *texObj;
342 struct gl_texture_image *texImage;
343
344 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
345 texObj = _mesa_select_tex_object(ctx, texUnit, target);
346 ASSERT(texObj);
347 texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
348 ASSERT(texImage);
349
350 ASSERT(ctx->Driver.TexImage2D);
351
352 if (texImage->Format != GL_DEPTH_COMPONENT) {
353 /* read RGBA image from framebuffer */
354 GLchan *image = read_color_image(ctx, x, y, width, height);
355 if (!image) {
356 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D" );
357 return;
358 }
359
360 #if 0
361 /*
362 * XXX this is a bit of a hack. We need to be sure that the alpha
363 * channel is 1.0 if the internal texture format is not supposed to
364 * have an alpha channel. This is because some drivers may store
365 * RGB textures as RGBA and the texutil.c code isn't smart enough
366 * to set the alpha channel to 1.0 in this situation.
367 */
368 if (texImage->Format == GL_LUMINANCE ||
369 texImage->Format == GL_RGB) {
370 const GLuint n = width * height * 4;
371 GLuint i;
372 for (i = 0; i < n; i += 4) {
373 image[i + 3] = CHAN_MAX;
374 }
375 }
376 #endif
377 /* now call glTexSubImage2D to do the real work */
378 (*ctx->Driver.TexSubImage2D)(ctx, target, level,
379 xoffset, yoffset, width, height,
380 GL_RGBA, CHAN_TYPE, image,
381 &_mesa_native_packing, texObj, texImage);
382 FREE(image);
383 }
384 else {
385 /* read depth image from framebuffer */
386 GLfloat *image = read_depth_image(ctx, x, y, width, height);
387 if (!image) {
388 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D");
389 return;
390 }
391
392 /* call glTexImage1D to redefine the texture */
393 (*ctx->Driver.TexSubImage2D)(ctx, target, level,
394 xoffset, yoffset, width, height,
395 GL_DEPTH_COMPONENT, GL_FLOAT, image,
396 &_mesa_native_packing, texObj, texImage);
397 FREE(image);
398 }
399
400 /* GL_SGIS_generate_mipmap */
401 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
402 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
403 }
404 }
405
406
407 /*
408 * Fallback for Driver.CopyTexSubImage3D().
409 */
410 void
411 _swrast_copy_texsubimage3d( GLcontext *ctx,
412 GLenum target, GLint level,
413 GLint xoffset, GLint yoffset, GLint zoffset,
414 GLint x, GLint y, GLsizei width, GLsizei height )
415 {
416 struct gl_texture_unit *texUnit;
417 struct gl_texture_object *texObj;
418 struct gl_texture_image *texImage;
419
420 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
421 texObj = _mesa_select_tex_object(ctx, texUnit, target);
422 ASSERT(texObj);
423 texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
424 ASSERT(texImage);
425
426 ASSERT(ctx->Driver.TexImage3D);
427
428 if (texImage->Format != GL_DEPTH_COMPONENT) {
429 /* read RGBA image from framebuffer */
430 GLchan *image = read_color_image(ctx, x, y, width, height);
431 if (!image) {
432 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D" );
433 return;
434 }
435 #if 0
436 /*
437 * XXX this is a bit of a hack. We need to be sure that the alpha
438 * channel is 1.0 if the internal texture format is not supposed to
439 * have an alpha channel. This is because some drivers may store
440 * RGB textures as RGBA and the texutil.c code isn't smart enough
441 * to set the alpha channel to 1.0 in this situation.
442 */
443 if (texImage->Format == GL_LUMINANCE ||
444 texImage->Format == GL_RGB) {
445 const GLuint n = width * height * 4;
446 GLuint i;
447 for (i = 0; i < n; i += 4) {
448 image[i + 3] = CHAN_MAX;
449 }
450 }
451 #endif
452 /* now call glTexSubImage3D to do the real work */
453 (*ctx->Driver.TexSubImage3D)(ctx, target, level,
454 xoffset, yoffset, zoffset, width, height, 1,
455 GL_RGBA, CHAN_TYPE, image,
456 &_mesa_native_packing, texObj, texImage);
457 FREE(image);
458 }
459 else {
460 /* read depth image from framebuffer */
461 GLfloat *image = read_depth_image(ctx, x, y, width, height);
462 if (!image) {
463 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D");
464 return;
465 }
466
467 /* call glTexImage1D to redefine the texture */
468 (*ctx->Driver.TexSubImage3D)(ctx, target, level,
469 xoffset, yoffset, zoffset, width, height, 1,
470 GL_DEPTH_COMPONENT, GL_FLOAT, image,
471 &_mesa_native_packing, texObj, texImage);
472 FREE(image);
473 }
474
475 /* GL_SGIS_generate_mipmap */
476 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
477 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
478 }
479 }