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;
88 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_row");
94 texture_get_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
95 const GLint x
[], const GLint y
[], void *values
)
97 const struct texture_renderbuffer
*trb
98 = (const struct texture_renderbuffer
*) rb
;
99 const GLint z
= trb
->Zoffset
;
102 if (rb
->DataType
== CHAN_TYPE
) {
103 GLchan
*rgbaOut
= (GLchan
*) values
;
104 for (i
= 0; i
< count
; i
++) {
106 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
108 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
111 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
112 GLushort
*zValues
= (GLushort
*) values
;
113 for (i
= 0; i
< count
; i
++) {
115 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
117 zValues
[i
] = (GLushort
) (flt
* 0xffff);
120 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
121 GLuint
*zValues
= (GLuint
*) values
;
122 for (i
= 0; i
< count
; i
++) {
124 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
127 zValues
[i
] = (GLuint
) (flt
* 0xffffffff);
129 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
133 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
134 GLuint
*zValues
= (GLuint
*) values
;
135 for (i
= 0; i
< count
; i
++) {
137 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
139 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
143 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_values");
149 * Put row of values into a renderbuffer that wraps a texture image.
152 texture_put_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
153 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
155 const struct texture_renderbuffer
*trb
156 = (const struct texture_renderbuffer
*) rb
;
157 const GLint z
= trb
->Zoffset
;
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
);
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
);
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
);
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
);
197 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
202 * Put row of RGB values into a renderbuffer that wraps a texture image.
205 texture_put_row_rgb(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
206 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
208 const struct texture_renderbuffer
*trb
209 = (const struct texture_renderbuffer
*) rb
;
210 const GLint z
= trb
->Zoffset
;
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
);
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
);
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
);
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
);
250 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
256 texture_put_mono_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
257 GLint x
, GLint y
, const void *value
, const GLubyte
*mask
)
259 const struct texture_renderbuffer
*trb
260 = (const struct texture_renderbuffer
*) rb
;
261 const GLint z
= trb
->Zoffset
;
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
);
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
);
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
);
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
);
300 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_row");
306 texture_put_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
307 const GLint x
[], const GLint y
[], const void *values
,
310 const struct texture_renderbuffer
*trb
311 = (const struct texture_renderbuffer
*) rb
;
312 const GLint z
= trb
->Zoffset
;
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
);
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
);
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
);
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
);
350 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
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
)
360 const struct texture_renderbuffer
*trb
361 = (const struct texture_renderbuffer
*) rb
;
362 const GLint z
= trb
->Zoffset
;
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
);
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
);
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
);
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
);
399 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_values");
405 store_nop(struct gl_texture_image
*texImage
,
406 GLint col
, GLint row
, GLint img
,
413 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
415 ASSERT(rb
->RefCount
== 0);
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.
426 wrap_texture(GLcontext
*ctx
, struct gl_renderbuffer_attachment
*att
)
428 struct texture_renderbuffer
*trb
;
429 const GLuint name
= 0;
431 ASSERT(att
->Type
== GL_TEXTURE
);
432 ASSERT(att
->Renderbuffer
== NULL
);
434 trb
= CALLOC_STRUCT(texture_renderbuffer
);
436 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
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
;
453 /* update attachment point */
454 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
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.
465 update_wrapper(GLcontext
*ctx
, const struct gl_renderbuffer_attachment
*att
)
467 struct texture_renderbuffer
*trb
468 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
473 trb
->TexImage
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
474 ASSERT(trb
->TexImage
);
476 trb
->Store
= _mesa_get_texel_store_func(trb
->TexImage
->TexFormat
);
478 /* we'll never draw into some textures (compressed formats) */
479 trb
->Store
= store_nop
;
482 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
483 trb
->Yoffset
= att
->Zoffset
;
488 trb
->Zoffset
= att
->Zoffset
;
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
;
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
;
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
;
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
;
516 trb
->Base
.Format
= trb
->TexImage
->TexFormat
;
517 trb
->Base
.DataType
= CHAN_TYPE
;
518 trb
->Base
._BaseFormat
= GL_RGBA
;
520 trb
->Base
.Data
= trb
->TexImage
->Data
;
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.
530 * Called via the glRenderbufferTexture1D/2D/3D() functions
531 * and elsewhere (such as glTexImage2D).
533 * The image we're rendering into is
534 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
535 * It'll never be NULL.
537 * \param fb the framebuffer object the texture is being bound to
538 * \param att the fb attachment point of the texture
540 * \sa _mesa_framebuffer_renderbuffer
543 _mesa_render_texture(GLcontext
*ctx
,
544 struct gl_framebuffer
*fb
,
545 struct gl_renderbuffer_attachment
*att
)
549 if (!att
->Renderbuffer
) {
550 wrap_texture(ctx
, att
);
552 update_wrapper(ctx
, att
);
557 _mesa_finish_render_texture(GLcontext
*ctx
,
558 struct gl_renderbuffer_attachment
*att
)
561 /* The renderbuffer texture wrapper will get deleted by the
562 * normal mechanism for deleting renderbuffers.