6 #include "renderbuffer.h"
10 * Render-to-texture code for GL_EXT_framebuffer_object
15 * Derived from gl_renderbuffer class
17 struct texture_renderbuffer
19 struct gl_renderbuffer Base
; /**< Base class object */
20 struct gl_texture_image
*TexImage
;
22 GLint Yoffset
; /**< Layer for 1D array textures. */
23 GLint Zoffset
; /**< Layer for 2D array textures, or slice
30 * Get row of values from the renderbuffer that wraps a texture image.
33 texture_get_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
34 GLint x
, GLint y
, void *values
)
36 const struct texture_renderbuffer
*trb
37 = (const struct texture_renderbuffer
*) rb
;
38 const GLint z
= trb
->Zoffset
;
41 ASSERT(trb
->TexImage
->Width
== rb
->Width
);
42 ASSERT(trb
->TexImage
->Height
== rb
->Height
);
46 if (rb
->DataType
== CHAN_TYPE
) {
47 GLchan
*rgbaOut
= (GLchan
*) values
;
48 for (i
= 0; i
< count
; i
++) {
50 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
51 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
54 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
55 GLushort
*zValues
= (GLushort
*) values
;
56 for (i
= 0; i
< count
; i
++) {
58 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
59 zValues
[i
] = (GLushort
) (flt
* 0xffff);
62 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
63 GLuint
*zValues
= (GLuint
*) values
;
65 const GLdouble scale = (GLdouble) 0xffffffff;
67 for (i
= 0; i
< count
; i
++) {
69 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
71 /* this should work, but doesn't (overflow due to low precision) */
72 zValues
[i
] = (GLuint
) (flt
* scale
);
75 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
79 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
80 GLuint
*zValues
= (GLuint
*) values
;
81 for (i
= 0; i
< count
; i
++) {
83 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
84 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
87 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
88 GLuint
*zValues
= (GLuint
*) values
;
89 for (i
= 0; i
< count
; i
++) {
91 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
92 zValues
[i
] = (GLuint
) (flt
* 0xffffff);
96 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_row");
102 texture_get_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
103 const GLint x
[], const GLint y
[], void *values
)
105 const struct texture_renderbuffer
*trb
106 = (const struct texture_renderbuffer
*) rb
;
107 const GLint z
= trb
->Zoffset
;
110 if (rb
->DataType
== CHAN_TYPE
) {
111 GLchan
*rgbaOut
= (GLchan
*) values
;
112 for (i
= 0; i
< count
; i
++) {
114 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
116 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
119 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
120 GLushort
*zValues
= (GLushort
*) values
;
121 for (i
= 0; i
< count
; i
++) {
123 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
125 zValues
[i
] = (GLushort
) (flt
* 0xffff);
128 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
129 GLuint
*zValues
= (GLuint
*) values
;
130 for (i
= 0; i
< count
; i
++) {
132 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
135 zValues
[i
] = (GLuint
) (flt
* 0xffffffff);
137 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
141 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
142 GLuint
*zValues
= (GLuint
*) values
;
143 for (i
= 0; i
< count
; i
++) {
145 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
147 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
150 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
151 GLuint
*zValues
= (GLuint
*) values
;
152 for (i
= 0; i
< count
; i
++) {
154 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
156 zValues
[i
] = (GLuint
) (flt
* 0xffffff);
160 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_values");
166 * Put row of values into a renderbuffer that wraps a texture image.
169 texture_put_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
170 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
172 const struct texture_renderbuffer
*trb
173 = (const struct texture_renderbuffer
*) rb
;
174 const GLint z
= trb
->Zoffset
;
179 if (rb
->DataType
== CHAN_TYPE
) {
180 const GLchan
*rgba
= (const GLchan
*) values
;
181 for (i
= 0; i
< count
; i
++) {
182 if (!mask
|| mask
[i
]) {
183 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
188 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
189 const GLushort
*zValues
= (const GLushort
*) values
;
190 for (i
= 0; i
< count
; i
++) {
191 if (!mask
|| mask
[i
]) {
192 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
196 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
197 const GLuint
*zValues
= (const GLuint
*) values
;
198 for (i
= 0; i
< count
; i
++) {
199 if (!mask
|| mask
[i
]) {
200 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
204 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
205 const GLuint
*zValues
= (const GLuint
*) values
;
206 for (i
= 0; i
< count
; i
++) {
207 if (!mask
|| mask
[i
]) {
208 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
209 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
213 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
214 const GLuint
*zValues
= (const GLuint
*) values
;
215 for (i
= 0; i
< count
; i
++) {
216 if (!mask
|| mask
[i
]) {
217 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
218 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
223 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
228 * Put row of RGB values into a renderbuffer that wraps a texture image.
231 texture_put_row_rgb(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
232 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
234 const struct texture_renderbuffer
*trb
235 = (const struct texture_renderbuffer
*) rb
;
236 const GLint z
= trb
->Zoffset
;
241 if (rb
->DataType
== CHAN_TYPE
) {
242 const GLchan
*rgb
= (const GLchan
*) values
;
243 for (i
= 0; i
< count
; i
++) {
244 if (!mask
|| mask
[i
]) {
245 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgb
);
250 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
251 const GLushort
*zValues
= (const GLushort
*) values
;
252 for (i
= 0; i
< count
; i
++) {
253 if (!mask
|| mask
[i
]) {
254 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
258 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
259 const GLuint
*zValues
= (const GLuint
*) values
;
260 for (i
= 0; i
< count
; i
++) {
261 if (!mask
|| mask
[i
]) {
262 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
266 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
267 const GLuint
*zValues
= (const GLuint
*) values
;
268 for (i
= 0; i
< count
; i
++) {
269 if (!mask
|| mask
[i
]) {
270 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
271 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
275 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
276 const GLuint
*zValues
= (const GLuint
*) values
;
277 for (i
= 0; i
< count
; i
++) {
278 if (!mask
|| mask
[i
]) {
279 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
280 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
285 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
291 texture_put_mono_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
292 GLint x
, GLint y
, const void *value
, const GLubyte
*mask
)
294 const struct texture_renderbuffer
*trb
295 = (const struct texture_renderbuffer
*) rb
;
296 const GLint z
= trb
->Zoffset
;
301 if (rb
->DataType
== CHAN_TYPE
) {
302 const GLchan
*rgba
= (const GLchan
*) value
;
303 for (i
= 0; i
< count
; i
++) {
304 if (!mask
|| mask
[i
]) {
305 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
309 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
310 const GLushort zValue
= *((const GLushort
*) value
);
311 for (i
= 0; i
< count
; i
++) {
312 if (!mask
|| mask
[i
]) {
313 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
317 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
318 const GLuint zValue
= *((const GLuint
*) value
);
319 for (i
= 0; i
< count
; i
++) {
320 if (!mask
|| mask
[i
]) {
321 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
325 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
326 const GLuint zValue
= *((const GLuint
*) value
);
327 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
328 for (i
= 0; i
< count
; i
++) {
329 if (!mask
|| mask
[i
]) {
330 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
334 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
335 const GLuint zValue
= *((const GLuint
*) value
);
336 const GLfloat flt
= (GLfloat
) ((zValue
& 0xffffff) * (1.0 / 0xffffff));
337 for (i
= 0; i
< count
; i
++) {
338 if (!mask
|| mask
[i
]) {
339 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
344 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_row");
350 texture_put_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
351 const GLint x
[], const GLint y
[], const void *values
,
354 const struct texture_renderbuffer
*trb
355 = (const struct texture_renderbuffer
*) rb
;
356 const GLint z
= trb
->Zoffset
;
359 if (rb
->DataType
== CHAN_TYPE
) {
360 const GLchan
*rgba
= (const GLchan
*) values
;
361 for (i
= 0; i
< count
; i
++) {
362 if (!mask
|| mask
[i
]) {
363 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
368 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
369 const GLushort
*zValues
= (const GLushort
*) values
;
370 for (i
= 0; i
< count
; i
++) {
371 if (!mask
|| mask
[i
]) {
372 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
376 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
377 const GLuint
*zValues
= (const GLuint
*) values
;
378 for (i
= 0; i
< count
; i
++) {
379 if (!mask
|| mask
[i
]) {
380 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
384 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
385 const GLuint
*zValues
= (const GLuint
*) values
;
386 for (i
= 0; i
< count
; i
++) {
387 if (!mask
|| mask
[i
]) {
388 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
389 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
393 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
394 const GLuint
*zValues
= (const GLuint
*) values
;
395 for (i
= 0; i
< count
; i
++) {
396 if (!mask
|| mask
[i
]) {
397 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
398 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
403 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
409 texture_put_mono_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
410 GLuint count
, const GLint x
[], const GLint y
[],
411 const void *value
, const GLubyte
*mask
)
413 const struct texture_renderbuffer
*trb
414 = (const struct texture_renderbuffer
*) rb
;
415 const GLint z
= trb
->Zoffset
;
418 if (rb
->DataType
== CHAN_TYPE
) {
419 const GLchan
*rgba
= (const GLchan
*) value
;
420 for (i
= 0; i
< count
; i
++) {
421 if (!mask
|| mask
[i
]) {
422 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
426 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
427 const GLuint zValue
= *((const GLuint
*) value
);
428 for (i
= 0; i
< count
; i
++) {
429 if (!mask
|| mask
[i
]) {
430 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
434 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
435 const GLushort zValue
= *((const GLushort
*) value
);
436 for (i
= 0; i
< count
; i
++) {
437 if (!mask
|| mask
[i
]) {
438 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
442 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
443 const GLuint zValue
= *((const GLuint
*) value
);
444 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
445 for (i
= 0; i
< count
; i
++) {
446 if (!mask
|| mask
[i
]) {
447 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
451 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
452 const GLuint zValue
= *((const GLuint
*) value
);
453 const GLfloat flt
= (GLfloat
) ((zValue
& 0xffffff) * (1.0 / 0xffffff));
454 for (i
= 0; i
< count
; i
++) {
455 if (!mask
|| mask
[i
]) {
456 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
461 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_values");
467 store_nop(struct gl_texture_image
*texImage
,
468 GLint col
, GLint row
, GLint img
,
475 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
477 ASSERT(rb
->RefCount
== 0);
483 * This function creates a renderbuffer object which wraps a texture image.
484 * The new renderbuffer is plugged into the given attachment point.
485 * This allows rendering into the texture as if it were a renderbuffer.
488 wrap_texture(GLcontext
*ctx
, struct gl_renderbuffer_attachment
*att
)
490 struct texture_renderbuffer
*trb
;
491 const GLuint name
= 0;
493 ASSERT(att
->Type
== GL_TEXTURE
);
494 ASSERT(att
->Renderbuffer
== NULL
);
496 trb
= CALLOC_STRUCT(texture_renderbuffer
);
498 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
502 /* init base gl_renderbuffer fields */
503 _mesa_init_renderbuffer(&trb
->Base
, name
);
504 /* plug in our texture_renderbuffer-specific functions */
505 trb
->Base
.Delete
= delete_texture_wrapper
;
506 trb
->Base
.AllocStorage
= NULL
; /* illegal! */
507 trb
->Base
.GetRow
= texture_get_row
;
508 trb
->Base
.GetValues
= texture_get_values
;
509 trb
->Base
.PutRow
= texture_put_row
;
510 trb
->Base
.PutRowRGB
= texture_put_row_rgb
;
511 trb
->Base
.PutMonoRow
= texture_put_mono_row
;
512 trb
->Base
.PutValues
= texture_put_values
;
513 trb
->Base
.PutMonoValues
= texture_put_mono_values
;
515 /* update attachment point */
516 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
522 * Update the renderbuffer wrapper for rendering to a texture.
523 * For example, update the width, height of the RB based on the texture size,
524 * update the internal format info, etc.
527 update_wrapper(GLcontext
*ctx
, const struct gl_renderbuffer_attachment
*att
)
529 struct texture_renderbuffer
*trb
530 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
535 trb
->TexImage
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
536 ASSERT(trb
->TexImage
);
538 trb
->Store
= _mesa_get_texel_store_func(trb
->TexImage
->TexFormat
);
540 /* we'll never draw into some textures (compressed formats) */
541 trb
->Store
= store_nop
;
544 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
545 trb
->Yoffset
= att
->Zoffset
;
550 trb
->Zoffset
= att
->Zoffset
;
553 trb
->Base
.Width
= trb
->TexImage
->Width
;
554 trb
->Base
.Height
= trb
->TexImage
->Height
;
555 trb
->Base
.InternalFormat
= trb
->TexImage
->InternalFormat
;
556 trb
->Base
.Format
= trb
->TexImage
->TexFormat
;
558 /* XXX may need more special cases here */
559 switch (trb
->TexImage
->TexFormat
) {
560 case MESA_FORMAT_Z24_S8
:
561 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
562 trb
->Base
._BaseFormat
= GL_DEPTH_STENCIL
;
564 case MESA_FORMAT_S8_Z24
:
565 trb
->Base
.DataType
= GL_UNSIGNED_INT_8_24_REV_MESA
;
566 trb
->Base
._BaseFormat
= GL_DEPTH_STENCIL
;
568 case MESA_FORMAT_Z24_X8
:
569 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
570 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
572 case MESA_FORMAT_X8_Z24
:
573 trb
->Base
.DataType
= GL_UNSIGNED_INT_8_24_REV_MESA
;
574 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
576 case MESA_FORMAT_Z16
:
577 trb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
578 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
580 case MESA_FORMAT_Z32
:
581 trb
->Base
.DataType
= GL_UNSIGNED_INT
;
582 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
585 trb
->Base
.DataType
= CHAN_TYPE
;
586 trb
->Base
._BaseFormat
= GL_RGBA
;
588 trb
->Base
.Data
= trb
->TexImage
->Data
;
594 * Called when rendering to a texture image begins, or when changing
595 * the dest mipmap level, cube face, etc.
596 * This is a fallback routine for software render-to-texture.
598 * Called via the glRenderbufferTexture1D/2D/3D() functions
599 * and elsewhere (such as glTexImage2D).
601 * The image we're rendering into is
602 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
603 * It'll never be NULL.
605 * \param fb the framebuffer object the texture is being bound to
606 * \param att the fb attachment point of the texture
608 * \sa _mesa_framebuffer_renderbuffer
611 _mesa_render_texture(GLcontext
*ctx
,
612 struct gl_framebuffer
*fb
,
613 struct gl_renderbuffer_attachment
*att
)
617 if (!att
->Renderbuffer
) {
618 wrap_texture(ctx
, att
);
620 update_wrapper(ctx
, att
);
625 _mesa_finish_render_texture(GLcontext
*ctx
,
626 struct gl_renderbuffer_attachment
*att
)
629 /* The renderbuffer texture wrapper will get deleted by the
630 * normal mechanism for deleting renderbuffers.