2 #include "main/context.h"
3 #include "main/colormac.h"
4 #include "main/fbobject.h"
5 #include "main/macros.h"
6 #include "main/texfetch.h"
7 #include "main/teximage.h"
8 #include "main/renderbuffer.h"
9 #include "swrast/swrast.h"
13 * Render-to-texture code for GL_EXT_framebuffer_object
18 * Derived from gl_renderbuffer class
20 struct texture_renderbuffer
22 struct gl_renderbuffer Base; /**< Base class object */
23 struct gl_texture_image *TexImage;
25 FetchTexelFuncF Fetchf;
26 GLint Yoffset; /**< Layer for 1D array textures. */
27 GLint Zoffset; /**< Layer for 2D array textures, or slice
34 * Get row of values from the renderbuffer that wraps a texture image.
37 texture_get_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
38 GLint x, GLint y, void *values)
40 const struct texture_renderbuffer *trb
41 = (const struct texture_renderbuffer *) rb;
42 const GLint z = trb->Zoffset;
45 ASSERT(trb->TexImage->Width == rb->Width);
46 ASSERT(trb->TexImage->Height == rb->Height);
50 if (rb->DataType == CHAN_TYPE) {
51 GLchan *rgbaOut = (GLchan *) values;
52 for (i = 0; i < count; i++) {
54 trb->Fetchf(trb->TexImage, x + i, y, z, rgba);
55 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
58 else if (rb->DataType == GL_UNSIGNED_SHORT) {
59 GLushort *zValues = (GLushort *) values;
60 for (i = 0; i < count; i++) {
62 trb->Fetchf(trb->TexImage, x + i, y, z, &flt);
63 zValues[i] = (GLushort) (flt * 0xffff);
66 else if (rb->DataType == GL_UNSIGNED_INT) {
67 GLuint *zValues = (GLuint *) values;
69 const GLdouble scale = (GLdouble) 0xffffffff;
71 for (i = 0; i < count; i++) {
73 trb->Fetchf(trb->TexImage, x + i, y, z, &flt);
75 /* this should work, but doesn't (overflow due to low precision) */
76 zValues[i] = (GLuint) (flt * scale);
79 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
83 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
84 GLuint *zValues = (GLuint *) values;
85 for (i = 0; i < count; i++) {
87 trb->Fetchf(trb->TexImage, x + i, y, z, &flt);
88 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
91 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
92 GLuint *zValues = (GLuint *) values;
93 for (i = 0; i < count; i++) {
95 trb->Fetchf(trb->TexImage, x + i, y, z, &flt);
96 zValues[i] = (GLuint) (flt * 0xffffff);
100 _mesa_problem(ctx, "invalid rb->DataType in texture_get_row");
106 texture_get_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
107 const GLint x[], const GLint y[], void *values)
109 const struct texture_renderbuffer *trb
110 = (const struct texture_renderbuffer *) rb;
111 const GLint z = trb->Zoffset;
114 if (rb->DataType == CHAN_TYPE) {
115 GLchan *rgbaOut = (GLchan *) values;
116 for (i = 0; i < count; i++) {
118 trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
120 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
123 else if (rb->DataType == GL_UNSIGNED_SHORT) {
124 GLushort *zValues = (GLushort *) values;
125 for (i = 0; i < count; i++) {
127 trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
129 zValues[i] = (GLushort) (flt * 0xffff);
132 else if (rb->DataType == GL_UNSIGNED_INT) {
133 GLuint *zValues = (GLuint *) values;
134 for (i = 0; i < count; i++) {
136 trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
139 zValues[i] = (GLuint) (flt * 0xffffffff);
141 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
145 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
146 GLuint *zValues = (GLuint *) values;
147 for (i = 0; i < count; i++) {
149 trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
151 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
154 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
155 GLuint *zValues = (GLuint *) values;
156 for (i = 0; i < count; i++) {
158 trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
160 zValues[i] = (GLuint) (flt * 0xffffff);
164 _mesa_problem(ctx, "invalid rb->DataType in texture_get_values");
170 * Put row of values into a renderbuffer that wraps a texture image.
173 texture_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
174 GLint x, GLint y, const void *values, const GLubyte *mask)
176 const struct texture_renderbuffer *trb
177 = (const struct texture_renderbuffer *) rb;
178 const GLint z = trb->Zoffset;
183 if (rb->DataType == CHAN_TYPE) {
184 const GLchan *rgba = (const GLchan *) values;
185 for (i = 0; i < count; i++) {
186 if (!mask || mask[i]) {
187 trb->Store(trb->TexImage, x + i, y, z, rgba);
192 else if (rb->DataType == GL_UNSIGNED_SHORT) {
193 const GLushort *zValues = (const GLushort *) values;
194 for (i = 0; i < count; i++) {
195 if (!mask || mask[i]) {
196 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
200 else if (rb->DataType == GL_UNSIGNED_INT) {
201 const GLuint *zValues = (const GLuint *) values;
202 for (i = 0; i < count; i++) {
203 if (!mask || mask[i]) {
204 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
208 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
209 const GLuint *zValues = (const GLuint *) values;
210 for (i = 0; i < count; i++) {
211 if (!mask || mask[i]) {
212 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
213 trb->Store(trb->TexImage, x + i, y, z, &flt);
217 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
218 const GLuint *zValues = (const GLuint *) values;
219 for (i = 0; i < count; i++) {
220 if (!mask || mask[i]) {
221 GLfloat flt = (GLfloat) ((zValues[i] & 0xffffff) * (1.0 / 0xffffff));
222 trb->Store(trb->TexImage, x + i, y, z, &flt);
227 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
232 * Put row of RGB values into a renderbuffer that wraps a texture image.
235 texture_put_row_rgb(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
236 GLint x, GLint y, const void *values, const GLubyte *mask)
238 const struct texture_renderbuffer *trb
239 = (const struct texture_renderbuffer *) rb;
240 const GLint z = trb->Zoffset;
245 if (rb->DataType == CHAN_TYPE) {
246 const GLchan *rgb = (const GLchan *) values;
247 for (i = 0; i < count; i++) {
248 if (!mask || mask[i]) {
249 trb->Store(trb->TexImage, x + i, y, z, rgb);
254 else if (rb->DataType == GL_UNSIGNED_SHORT) {
255 const GLushort *zValues = (const GLushort *) values;
256 for (i = 0; i < count; i++) {
257 if (!mask || mask[i]) {
258 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
262 else if (rb->DataType == GL_UNSIGNED_INT) {
263 const GLuint *zValues = (const GLuint *) values;
264 for (i = 0; i < count; i++) {
265 if (!mask || mask[i]) {
266 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
270 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
271 const GLuint *zValues = (const GLuint *) values;
272 for (i = 0; i < count; i++) {
273 if (!mask || mask[i]) {
274 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
275 trb->Store(trb->TexImage, x + i, y, z, &flt);
279 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
280 const GLuint *zValues = (const GLuint *) values;
281 for (i = 0; i < count; i++) {
282 if (!mask || mask[i]) {
283 GLfloat flt = (GLfloat) ((zValues[i] & 0xffffff) * (1.0 / 0xffffff));
284 trb->Store(trb->TexImage, x + i, y, z, &flt);
289 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
295 texture_put_mono_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
296 GLint x, GLint y, const void *value, const GLubyte *mask)
298 const struct texture_renderbuffer *trb
299 = (const struct texture_renderbuffer *) rb;
300 const GLint z = trb->Zoffset;
305 if (rb->DataType == CHAN_TYPE) {
306 const GLchan *rgba = (const GLchan *) value;
307 for (i = 0; i < count; i++) {
308 if (!mask || mask[i]) {
309 trb->Store(trb->TexImage, x + i, y, z, rgba);
313 else if (rb->DataType == GL_UNSIGNED_SHORT) {
314 const GLushort zValue = *((const GLushort *) value);
315 for (i = 0; i < count; i++) {
316 if (!mask || mask[i]) {
317 trb->Store(trb->TexImage, x + i, y, z, &zValue);
321 else if (rb->DataType == GL_UNSIGNED_INT) {
322 const GLuint zValue = *((const GLuint *) value);
323 for (i = 0; i < count; i++) {
324 if (!mask || mask[i]) {
325 trb->Store(trb->TexImage, x + i, y, z, &zValue);
329 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
330 const GLuint zValue = *((const GLuint *) value);
331 const GLfloat flt = (GLfloat) ((zValue >> 8) * (1.0 / 0xffffff));
332 for (i = 0; i < count; i++) {
333 if (!mask || mask[i]) {
334 trb->Store(trb->TexImage, x + i, y, z, &flt);
338 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
339 const GLuint zValue = *((const GLuint *) value);
340 const GLfloat flt = (GLfloat) ((zValue & 0xffffff) * (1.0 / 0xffffff));
341 for (i = 0; i < count; i++) {
342 if (!mask || mask[i]) {
343 trb->Store(trb->TexImage, x + i, y, z, &flt);
348 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_row");
354 texture_put_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
355 const GLint x[], const GLint y[], const void *values,
358 const struct texture_renderbuffer *trb
359 = (const struct texture_renderbuffer *) rb;
360 const GLint z = trb->Zoffset;
363 if (rb->DataType == CHAN_TYPE) {
364 const GLchan *rgba = (const GLchan *) values;
365 for (i = 0; i < count; i++) {
366 if (!mask || mask[i]) {
367 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
372 else if (rb->DataType == GL_UNSIGNED_SHORT) {
373 const GLushort *zValues = (const GLushort *) values;
374 for (i = 0; i < count; i++) {
375 if (!mask || mask[i]) {
376 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, zValues + i);
380 else if (rb->DataType == GL_UNSIGNED_INT) {
381 const GLuint *zValues = (const GLuint *) values;
382 for (i = 0; i < count; i++) {
383 if (!mask || mask[i]) {
384 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, zValues + i);
388 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
389 const GLuint *zValues = (const GLuint *) values;
390 for (i = 0; i < count; i++) {
391 if (!mask || mask[i]) {
392 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
393 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
397 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
398 const GLuint *zValues = (const GLuint *) values;
399 for (i = 0; i < count; i++) {
400 if (!mask || mask[i]) {
401 GLfloat flt = (GLfloat) ((zValues[i] & 0xffffff) * (1.0 / 0xffffff));
402 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
407 _mesa_problem(ctx, "invalid rb->DataType in texture_put_values");
413 texture_put_mono_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
414 GLuint count, const GLint x[], const GLint y[],
415 const void *value, const GLubyte *mask)
417 const struct texture_renderbuffer *trb
418 = (const struct texture_renderbuffer *) rb;
419 const GLint z = trb->Zoffset;
422 if (rb->DataType == CHAN_TYPE) {
423 const GLchan *rgba = (const GLchan *) value;
424 for (i = 0; i < count; i++) {
425 if (!mask || mask[i]) {
426 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
430 else if (rb->DataType == GL_UNSIGNED_INT) {
431 const GLuint zValue = *((const GLuint *) value);
432 for (i = 0; i < count; i++) {
433 if (!mask || mask[i]) {
434 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
438 else if (rb->DataType == GL_UNSIGNED_SHORT) {
439 const GLushort zValue = *((const GLushort *) value);
440 for (i = 0; i < count; i++) {
441 if (!mask || mask[i]) {
442 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
446 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
447 const GLuint zValue = *((const GLuint *) value);
448 const GLfloat flt = (GLfloat) ((zValue >> 8) * (1.0 / 0xffffff));
449 for (i = 0; i < count; i++) {
450 if (!mask || mask[i]) {
451 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
455 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
456 const GLuint zValue = *((const GLuint *) value);
457 const GLfloat flt = (GLfloat) ((zValue & 0xffffff) * (1.0 / 0xffffff));
458 for (i = 0; i < count; i++) {
459 if (!mask || mask[i]) {
460 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
465 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_values");
471 store_nop(struct gl_texture_image *texImage,
472 GLint col, GLint row, GLint img,
479 delete_texture_wrapper(struct gl_renderbuffer *rb)
481 ASSERT(rb->RefCount == 0);
487 * This function creates a renderbuffer object which wraps a texture image.
488 * The new renderbuffer is plugged into the given attachment point.
489 * This allows rendering into the texture as if it were a renderbuffer.
492 wrap_texture(struct gl_context *ctx, struct gl_renderbuffer_attachment *att)
494 struct texture_renderbuffer *trb;
495 const GLuint name = 0;
497 ASSERT(att->Type == GL_TEXTURE);
498 ASSERT(att->Renderbuffer == NULL);
500 trb = CALLOC_STRUCT(texture_renderbuffer);
502 _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture");
506 /* init base gl_renderbuffer fields */
507 _mesa_init_renderbuffer(&trb->Base, name);
508 /* plug in our texture_renderbuffer-specific functions */
509 trb->Base.Delete = delete_texture_wrapper;
510 trb->Base.AllocStorage = NULL; /* illegal! */
511 trb->Base.GetRow = texture_get_row;
512 trb->Base.GetValues = texture_get_values;
513 trb->Base.PutRow = texture_put_row;
514 trb->Base.PutRowRGB = texture_put_row_rgb;
515 trb->Base.PutMonoRow = texture_put_mono_row;
516 trb->Base.PutValues = texture_put_values;
517 trb->Base.PutMonoValues = texture_put_mono_values;
519 /* update attachment point */
520 _mesa_reference_renderbuffer(&att->Renderbuffer, &(trb->Base));
524 * Update the renderbuffer wrapper for rendering to a texture.
525 * For example, update the width, height of the RB based on the texture size,
526 * update the internal format info, etc.
529 update_wrapper(struct gl_context *ctx, struct gl_renderbuffer_attachment *att)
531 struct texture_renderbuffer *trb
532 = (struct texture_renderbuffer *) att->Renderbuffer;
537 trb->TexImage = _mesa_get_attachment_teximage(att);
538 ASSERT(trb->TexImage);
540 trb->Store = _mesa_get_texel_store_func(trb->TexImage->TexFormat);
542 /* we'll never draw into some textures (compressed formats) */
543 trb->Store = store_nop;
546 trb->Fetchf = trb->TexImage->FetchTexelf;
548 if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
549 trb->Yoffset = att->Zoffset;
554 trb->Zoffset = att->Zoffset;
557 trb->Base.Width = trb->TexImage->Width;
558 trb->Base.Height = trb->TexImage->Height;
559 trb->Base.InternalFormat = trb->TexImage->InternalFormat;
560 trb->Base.Format = trb->TexImage->TexFormat;
562 /* XXX may need more special cases here */
563 switch (trb->TexImage->TexFormat) {
564 case MESA_FORMAT_Z24_S8:
565 trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
566 trb->Base._BaseFormat = GL_DEPTH_STENCIL;
568 case MESA_FORMAT_S8_Z24:
569 trb->Base.DataType = GL_UNSIGNED_INT_8_24_REV_MESA;
570 trb->Base._BaseFormat = GL_DEPTH_STENCIL;
572 case MESA_FORMAT_Z24_X8:
573 trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
574 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
576 case MESA_FORMAT_X8_Z24:
577 trb->Base.DataType = GL_UNSIGNED_INT_8_24_REV_MESA;
578 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
580 case MESA_FORMAT_Z16:
581 trb->Base.DataType = GL_UNSIGNED_SHORT;
582 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
584 case MESA_FORMAT_Z32:
585 trb->Base.DataType = GL_UNSIGNED_INT;
586 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
588 /* SRGB formats pre EXT_framebuffer_sRGB don't do sRGB translations on FBO readback */
589 case MESA_FORMAT_SRGB8:
590 trb->Fetchf = _mesa_get_texel_fetch_func(MESA_FORMAT_RGB888, _mesa_get_texture_dimensions(att->Texture->Target));
591 trb->Base.DataType = CHAN_TYPE;
592 trb->Base._BaseFormat = GL_RGBA;
594 case MESA_FORMAT_SRGBA8:
595 trb->Fetchf = _mesa_get_texel_fetch_func(MESA_FORMAT_RGBA8888, _mesa_get_texture_dimensions(att->Texture->Target));
596 trb->Base.DataType = CHAN_TYPE;
597 trb->Base._BaseFormat = GL_RGBA;
599 case MESA_FORMAT_SARGB8:
600 trb->Fetchf = _mesa_get_texel_fetch_func(MESA_FORMAT_ARGB8888, _mesa_get_texture_dimensions(att->Texture->Target));
601 trb->Base.DataType = CHAN_TYPE;
602 trb->Base._BaseFormat = GL_RGBA;
605 trb->Base.DataType = CHAN_TYPE;
606 trb->Base._BaseFormat = GL_RGBA;
608 trb->Base.Data = trb->TexImage->Data;
614 * Called when rendering to a texture image begins, or when changing
615 * the dest mipmap level, cube face, etc.
616 * This is a fallback routine for software render-to-texture.
618 * Called via the glRenderbufferTexture1D/2D/3D() functions
619 * and elsewhere (such as glTexImage2D).
621 * The image we're rendering into is
622 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
623 * It'll never be NULL.
625 * \param fb the framebuffer object the texture is being bound to
626 * \param att the fb attachment point of the texture
628 * \sa _mesa_framebuffer_renderbuffer
631 _swrast_render_texture(struct gl_context *ctx,
632 struct gl_framebuffer *fb,
633 struct gl_renderbuffer_attachment *att)
637 if (!att->Renderbuffer) {
638 wrap_texture(ctx, att);
640 update_wrapper(ctx, att);
645 _swrast_finish_render_texture(struct gl_context *ctx,
646 struct gl_renderbuffer_attachment *att)
649 /* The renderbuffer texture wrapper will get deleted by the
650 * normal mechanism for deleting renderbuffers.