draw: corrections to allow for different cliptest cases
[mesa.git] / src / mesa / main / texrender.c
1
2 #include "context.h"
3 #include "colormac.h"
4 #include "macros.h"
5 #include "texfetch.h"
6 #include "texrender.h"
7 #include "renderbuffer.h"
8
9
10 /*
11 * Render-to-texture code for GL_EXT_framebuffer_object
12 */
13
14
15 /**
16 * Derived from gl_renderbuffer class
17 */
18 struct texture_renderbuffer
19 {
20 struct gl_renderbuffer Base; /**< Base class object */
21 struct gl_texture_image *TexImage;
22 StoreTexelFunc Store;
23 GLint Yoffset; /**< Layer for 1D array textures. */
24 GLint Zoffset; /**< Layer for 2D array textures, or slice
25 * for 3D textures
26 */
27 };
28
29
30 /**
31 * Get row of values from the renderbuffer that wraps a texture image.
32 */
33 static void
34 texture_get_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
35 GLint x, GLint y, void *values)
36 {
37 const struct texture_renderbuffer *trb
38 = (const struct texture_renderbuffer *) rb;
39 const GLint z = trb->Zoffset;
40 GLuint i;
41
42 ASSERT(trb->TexImage->Width == rb->Width);
43 ASSERT(trb->TexImage->Height == rb->Height);
44
45 y += trb->Yoffset;
46
47 if (rb->DataType == CHAN_TYPE) {
48 GLchan *rgbaOut = (GLchan *) values;
49 for (i = 0; i < count; i++) {
50 GLfloat rgba[4];
51 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, rgba);
52 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
53 }
54 }
55 else if (rb->DataType == GL_UNSIGNED_SHORT) {
56 GLushort *zValues = (GLushort *) values;
57 for (i = 0; i < count; i++) {
58 GLfloat flt;
59 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
60 zValues[i] = (GLushort) (flt * 0xffff);
61 }
62 }
63 else if (rb->DataType == GL_UNSIGNED_INT) {
64 GLuint *zValues = (GLuint *) values;
65 /*
66 const GLdouble scale = (GLdouble) 0xffffffff;
67 */
68 for (i = 0; i < count; i++) {
69 GLfloat flt;
70 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
71 #if 0
72 /* this should work, but doesn't (overflow due to low precision) */
73 zValues[i] = (GLuint) (flt * scale);
74 #else
75 /* temporary hack */
76 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
77 #endif
78 }
79 }
80 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
81 GLuint *zValues = (GLuint *) values;
82 for (i = 0; i < count; i++) {
83 GLfloat flt;
84 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
85 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
86 }
87 }
88 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
89 GLuint *zValues = (GLuint *) values;
90 for (i = 0; i < count; i++) {
91 GLfloat flt;
92 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
93 zValues[i] = (GLuint) (flt * 0xffffff);
94 }
95 }
96 else {
97 _mesa_problem(ctx, "invalid rb->DataType in texture_get_row");
98 }
99 }
100
101
102 static void
103 texture_get_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
104 const GLint x[], const GLint y[], void *values)
105 {
106 const struct texture_renderbuffer *trb
107 = (const struct texture_renderbuffer *) rb;
108 const GLint z = trb->Zoffset;
109 GLuint i;
110
111 if (rb->DataType == CHAN_TYPE) {
112 GLchan *rgbaOut = (GLchan *) values;
113 for (i = 0; i < count; i++) {
114 GLfloat rgba[4];
115 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
116 z, rgba);
117 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
118 }
119 }
120 else if (rb->DataType == GL_UNSIGNED_SHORT) {
121 GLushort *zValues = (GLushort *) values;
122 for (i = 0; i < count; i++) {
123 GLfloat flt;
124 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
125 z, &flt);
126 zValues[i] = (GLushort) (flt * 0xffff);
127 }
128 }
129 else if (rb->DataType == GL_UNSIGNED_INT) {
130 GLuint *zValues = (GLuint *) values;
131 for (i = 0; i < count; i++) {
132 GLfloat flt;
133 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
134 z, &flt);
135 #if 0
136 zValues[i] = (GLuint) (flt * 0xffffffff);
137 #else
138 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
139 #endif
140 }
141 }
142 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
143 GLuint *zValues = (GLuint *) values;
144 for (i = 0; i < count; i++) {
145 GLfloat flt;
146 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
147 z, &flt);
148 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
149 }
150 }
151 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
152 GLuint *zValues = (GLuint *) values;
153 for (i = 0; i < count; i++) {
154 GLfloat flt;
155 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
156 z, &flt);
157 zValues[i] = (GLuint) (flt * 0xffffff);
158 }
159 }
160 else {
161 _mesa_problem(ctx, "invalid rb->DataType in texture_get_values");
162 }
163 }
164
165
166 /**
167 * Put row of values into a renderbuffer that wraps a texture image.
168 */
169 static void
170 texture_put_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
171 GLint x, GLint y, const void *values, const GLubyte *mask)
172 {
173 const struct texture_renderbuffer *trb
174 = (const struct texture_renderbuffer *) rb;
175 const GLint z = trb->Zoffset;
176 GLuint i;
177
178 y += trb->Yoffset;
179
180 if (rb->DataType == CHAN_TYPE) {
181 const GLchan *rgba = (const GLchan *) values;
182 for (i = 0; i < count; i++) {
183 if (!mask || mask[i]) {
184 trb->Store(trb->TexImage, x + i, y, z, rgba);
185 }
186 rgba += 4;
187 }
188 }
189 else if (rb->DataType == GL_UNSIGNED_SHORT) {
190 const GLushort *zValues = (const GLushort *) values;
191 for (i = 0; i < count; i++) {
192 if (!mask || mask[i]) {
193 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
194 }
195 }
196 }
197 else if (rb->DataType == GL_UNSIGNED_INT) {
198 const GLuint *zValues = (const GLuint *) values;
199 for (i = 0; i < count; i++) {
200 if (!mask || mask[i]) {
201 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
202 }
203 }
204 }
205 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
206 const GLuint *zValues = (const GLuint *) values;
207 for (i = 0; i < count; i++) {
208 if (!mask || mask[i]) {
209 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
210 trb->Store(trb->TexImage, x + i, y, z, &flt);
211 }
212 }
213 }
214 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
215 const GLuint *zValues = (const GLuint *) values;
216 for (i = 0; i < count; i++) {
217 if (!mask || mask[i]) {
218 GLfloat flt = (GLfloat) ((zValues[i] & 0xffffff) * (1.0 / 0xffffff));
219 trb->Store(trb->TexImage, x + i, y, z, &flt);
220 }
221 }
222 }
223 else {
224 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
225 }
226 }
227
228 /**
229 * Put row of RGB values into a renderbuffer that wraps a texture image.
230 */
231 static void
232 texture_put_row_rgb(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
233 GLint x, GLint y, const void *values, const GLubyte *mask)
234 {
235 const struct texture_renderbuffer *trb
236 = (const struct texture_renderbuffer *) rb;
237 const GLint z = trb->Zoffset;
238 GLuint i;
239
240 y += trb->Yoffset;
241
242 if (rb->DataType == CHAN_TYPE) {
243 const GLchan *rgb = (const GLchan *) values;
244 for (i = 0; i < count; i++) {
245 if (!mask || mask[i]) {
246 trb->Store(trb->TexImage, x + i, y, z, rgb);
247 }
248 rgb += 3;
249 }
250 }
251 else if (rb->DataType == GL_UNSIGNED_SHORT) {
252 const GLushort *zValues = (const GLushort *) values;
253 for (i = 0; i < count; i++) {
254 if (!mask || mask[i]) {
255 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
256 }
257 }
258 }
259 else if (rb->DataType == GL_UNSIGNED_INT) {
260 const GLuint *zValues = (const GLuint *) values;
261 for (i = 0; i < count; i++) {
262 if (!mask || mask[i]) {
263 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
264 }
265 }
266 }
267 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
268 const GLuint *zValues = (const GLuint *) values;
269 for (i = 0; i < count; i++) {
270 if (!mask || mask[i]) {
271 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
272 trb->Store(trb->TexImage, x + i, y, z, &flt);
273 }
274 }
275 }
276 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
277 const GLuint *zValues = (const GLuint *) values;
278 for (i = 0; i < count; i++) {
279 if (!mask || mask[i]) {
280 GLfloat flt = (GLfloat) ((zValues[i] & 0xffffff) * (1.0 / 0xffffff));
281 trb->Store(trb->TexImage, x + i, y, z, &flt);
282 }
283 }
284 }
285 else {
286 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
287 }
288 }
289
290
291 static void
292 texture_put_mono_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
293 GLint x, GLint y, const void *value, const GLubyte *mask)
294 {
295 const struct texture_renderbuffer *trb
296 = (const struct texture_renderbuffer *) rb;
297 const GLint z = trb->Zoffset;
298 GLuint i;
299
300 y += trb->Yoffset;
301
302 if (rb->DataType == CHAN_TYPE) {
303 const GLchan *rgba = (const GLchan *) value;
304 for (i = 0; i < count; i++) {
305 if (!mask || mask[i]) {
306 trb->Store(trb->TexImage, x + i, y, z, rgba);
307 }
308 }
309 }
310 else if (rb->DataType == GL_UNSIGNED_SHORT) {
311 const GLushort zValue = *((const GLushort *) value);
312 for (i = 0; i < count; i++) {
313 if (!mask || mask[i]) {
314 trb->Store(trb->TexImage, x + i, y, z, &zValue);
315 }
316 }
317 }
318 else if (rb->DataType == GL_UNSIGNED_INT) {
319 const GLuint zValue = *((const GLuint *) value);
320 for (i = 0; i < count; i++) {
321 if (!mask || mask[i]) {
322 trb->Store(trb->TexImage, x + i, y, z, &zValue);
323 }
324 }
325 }
326 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
327 const GLuint zValue = *((const GLuint *) value);
328 const GLfloat flt = (GLfloat) ((zValue >> 8) * (1.0 / 0xffffff));
329 for (i = 0; i < count; i++) {
330 if (!mask || mask[i]) {
331 trb->Store(trb->TexImage, x + i, y, z, &flt);
332 }
333 }
334 }
335 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
336 const GLuint zValue = *((const GLuint *) value);
337 const GLfloat flt = (GLfloat) ((zValue & 0xffffff) * (1.0 / 0xffffff));
338 for (i = 0; i < count; i++) {
339 if (!mask || mask[i]) {
340 trb->Store(trb->TexImage, x + i, y, z, &flt);
341 }
342 }
343 }
344 else {
345 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_row");
346 }
347 }
348
349
350 static void
351 texture_put_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
352 const GLint x[], const GLint y[], const void *values,
353 const GLubyte *mask)
354 {
355 const struct texture_renderbuffer *trb
356 = (const struct texture_renderbuffer *) rb;
357 const GLint z = trb->Zoffset;
358 GLuint i;
359
360 if (rb->DataType == CHAN_TYPE) {
361 const GLchan *rgba = (const GLchan *) values;
362 for (i = 0; i < count; i++) {
363 if (!mask || mask[i]) {
364 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
365 }
366 rgba += 4;
367 }
368 }
369 else if (rb->DataType == GL_UNSIGNED_SHORT) {
370 const GLushort *zValues = (const GLushort *) values;
371 for (i = 0; i < count; i++) {
372 if (!mask || mask[i]) {
373 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, zValues + i);
374 }
375 }
376 }
377 else if (rb->DataType == GL_UNSIGNED_INT) {
378 const GLuint *zValues = (const GLuint *) values;
379 for (i = 0; i < count; i++) {
380 if (!mask || mask[i]) {
381 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, zValues + i);
382 }
383 }
384 }
385 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
386 const GLuint *zValues = (const GLuint *) values;
387 for (i = 0; i < count; i++) {
388 if (!mask || mask[i]) {
389 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
390 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
391 }
392 }
393 }
394 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
395 const GLuint *zValues = (const GLuint *) values;
396 for (i = 0; i < count; i++) {
397 if (!mask || mask[i]) {
398 GLfloat flt = (GLfloat) ((zValues[i] & 0xffffff) * (1.0 / 0xffffff));
399 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
400 }
401 }
402 }
403 else {
404 _mesa_problem(ctx, "invalid rb->DataType in texture_put_values");
405 }
406 }
407
408
409 static void
410 texture_put_mono_values(GLcontext *ctx, struct gl_renderbuffer *rb,
411 GLuint count, const GLint x[], const GLint y[],
412 const void *value, const GLubyte *mask)
413 {
414 const struct texture_renderbuffer *trb
415 = (const struct texture_renderbuffer *) rb;
416 const GLint z = trb->Zoffset;
417 GLuint i;
418
419 if (rb->DataType == CHAN_TYPE) {
420 const GLchan *rgba = (const GLchan *) value;
421 for (i = 0; i < count; i++) {
422 if (!mask || mask[i]) {
423 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
424 }
425 }
426 }
427 else if (rb->DataType == GL_UNSIGNED_INT) {
428 const GLuint zValue = *((const GLuint *) value);
429 for (i = 0; i < count; i++) {
430 if (!mask || mask[i]) {
431 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
432 }
433 }
434 }
435 else if (rb->DataType == GL_UNSIGNED_SHORT) {
436 const GLushort zValue = *((const GLushort *) value);
437 for (i = 0; i < count; i++) {
438 if (!mask || mask[i]) {
439 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
440 }
441 }
442 }
443 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
444 const GLuint zValue = *((const GLuint *) value);
445 const GLfloat flt = (GLfloat) ((zValue >> 8) * (1.0 / 0xffffff));
446 for (i = 0; i < count; i++) {
447 if (!mask || mask[i]) {
448 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
449 }
450 }
451 }
452 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
453 const GLuint zValue = *((const GLuint *) value);
454 const GLfloat flt = (GLfloat) ((zValue & 0xffffff) * (1.0 / 0xffffff));
455 for (i = 0; i < count; i++) {
456 if (!mask || mask[i]) {
457 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
458 }
459 }
460 }
461 else {
462 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_values");
463 }
464 }
465
466
467 static void
468 store_nop(struct gl_texture_image *texImage,
469 GLint col, GLint row, GLint img,
470 const void *texel)
471 {
472 }
473
474
475 static void
476 delete_texture_wrapper(struct gl_renderbuffer *rb)
477 {
478 ASSERT(rb->RefCount == 0);
479 free(rb);
480 }
481
482
483 /**
484 * This function creates a renderbuffer object which wraps a texture image.
485 * The new renderbuffer is plugged into the given attachment point.
486 * This allows rendering into the texture as if it were a renderbuffer.
487 */
488 static void
489 wrap_texture(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
490 {
491 struct texture_renderbuffer *trb;
492 const GLuint name = 0;
493
494 ASSERT(att->Type == GL_TEXTURE);
495 ASSERT(att->Renderbuffer == NULL);
496
497 trb = CALLOC_STRUCT(texture_renderbuffer);
498 if (!trb) {
499 _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture");
500 return;
501 }
502
503 /* init base gl_renderbuffer fields */
504 _mesa_init_renderbuffer(&trb->Base, name);
505 /* plug in our texture_renderbuffer-specific functions */
506 trb->Base.Delete = delete_texture_wrapper;
507 trb->Base.AllocStorage = NULL; /* illegal! */
508 trb->Base.GetRow = texture_get_row;
509 trb->Base.GetValues = texture_get_values;
510 trb->Base.PutRow = texture_put_row;
511 trb->Base.PutRowRGB = texture_put_row_rgb;
512 trb->Base.PutMonoRow = texture_put_mono_row;
513 trb->Base.PutValues = texture_put_values;
514 trb->Base.PutMonoValues = texture_put_mono_values;
515
516 /* update attachment point */
517 _mesa_reference_renderbuffer(&att->Renderbuffer, &(trb->Base));
518 }
519
520
521
522 /**
523 * Update the renderbuffer wrapper for rendering to a texture.
524 * For example, update the width, height of the RB based on the texture size,
525 * update the internal format info, etc.
526 */
527 static void
528 update_wrapper(GLcontext *ctx, const struct gl_renderbuffer_attachment *att)
529 {
530 struct texture_renderbuffer *trb
531 = (struct texture_renderbuffer *) att->Renderbuffer;
532
533 (void) ctx;
534 ASSERT(trb);
535
536 trb->TexImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
537 ASSERT(trb->TexImage);
538
539 trb->Store = _mesa_get_texel_store_func(trb->TexImage->TexFormat);
540 if (!trb->Store) {
541 /* we'll never draw into some textures (compressed formats) */
542 trb->Store = store_nop;
543 }
544
545 if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
546 trb->Yoffset = att->Zoffset;
547 trb->Zoffset = 0;
548 }
549 else {
550 trb->Yoffset = 0;
551 trb->Zoffset = att->Zoffset;
552 }
553
554 trb->Base.Width = trb->TexImage->Width;
555 trb->Base.Height = trb->TexImage->Height;
556 trb->Base.InternalFormat = trb->TexImage->InternalFormat;
557 trb->Base.Format = trb->TexImage->TexFormat;
558
559 /* XXX may need more special cases here */
560 switch (trb->TexImage->TexFormat) {
561 case MESA_FORMAT_Z24_S8:
562 trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
563 trb->Base._BaseFormat = GL_DEPTH_STENCIL;
564 break;
565 case MESA_FORMAT_S8_Z24:
566 trb->Base.DataType = GL_UNSIGNED_INT_8_24_REV_MESA;
567 trb->Base._BaseFormat = GL_DEPTH_STENCIL;
568 break;
569 case MESA_FORMAT_Z24_X8:
570 trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
571 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
572 break;
573 case MESA_FORMAT_X8_Z24:
574 trb->Base.DataType = GL_UNSIGNED_INT_8_24_REV_MESA;
575 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
576 break;
577 case MESA_FORMAT_Z16:
578 trb->Base.DataType = GL_UNSIGNED_SHORT;
579 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
580 break;
581 case MESA_FORMAT_Z32:
582 trb->Base.DataType = GL_UNSIGNED_INT;
583 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
584 break;
585 default:
586 trb->Base.DataType = CHAN_TYPE;
587 trb->Base._BaseFormat = GL_RGBA;
588 }
589 trb->Base.Data = trb->TexImage->Data;
590 }
591
592
593
594 /**
595 * Called when rendering to a texture image begins, or when changing
596 * the dest mipmap level, cube face, etc.
597 * This is a fallback routine for software render-to-texture.
598 *
599 * Called via the glRenderbufferTexture1D/2D/3D() functions
600 * and elsewhere (such as glTexImage2D).
601 *
602 * The image we're rendering into is
603 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
604 * It'll never be NULL.
605 *
606 * \param fb the framebuffer object the texture is being bound to
607 * \param att the fb attachment point of the texture
608 *
609 * \sa _mesa_framebuffer_renderbuffer
610 */
611 void
612 _mesa_render_texture(GLcontext *ctx,
613 struct gl_framebuffer *fb,
614 struct gl_renderbuffer_attachment *att)
615 {
616 (void) fb;
617
618 if (!att->Renderbuffer) {
619 wrap_texture(ctx, att);
620 }
621 update_wrapper(ctx, att);
622 }
623
624
625 void
626 _mesa_finish_render_texture(GLcontext *ctx,
627 struct gl_renderbuffer_attachment *att)
628 {
629 /* do nothing */
630 /* The renderbuffer texture wrapper will get deleted by the
631 * normal mechanism for deleting renderbuffers.
632 */
633 (void) ctx;
634 (void) att;
635 }