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