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
++) {
49 trb
->TexImage
->FetchTexelc(trb
->TexImage
, x
+ i
, y
, z
, rgbaOut
+ 4 * i
);
52 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
53 GLushort
*zValues
= (GLushort
*) values
;
54 for (i
= 0; i
< count
; i
++) {
56 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
57 zValues
[i
] = (GLushort
) (flt
* 0xffff);
60 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
61 GLuint
*zValues
= (GLuint
*) values
;
63 const GLdouble scale = (GLdouble) 0xffffffff;
65 for (i
= 0; i
< count
; i
++) {
67 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
69 /* this should work, but doesn't (overflow due to low precision) */
70 zValues
[i
] = (GLuint
) (flt
* scale
);
73 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
77 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
78 GLuint
*zValues
= (GLuint
*) values
;
79 for (i
= 0; i
< count
; i
++) {
81 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
82 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
86 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_row");
92 texture_get_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
93 const GLint x
[], const GLint y
[], void *values
)
95 const struct texture_renderbuffer
*trb
96 = (const struct texture_renderbuffer
*) rb
;
97 const GLint z
= trb
->Zoffset
;
100 if (rb
->DataType
== CHAN_TYPE
) {
101 GLchan
*rgbaOut
= (GLchan
*) values
;
102 for (i
= 0; i
< count
; i
++) {
103 trb
->TexImage
->FetchTexelc(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
107 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
108 GLushort
*zValues
= (GLushort
*) values
;
109 for (i
= 0; i
< count
; i
++) {
111 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
113 zValues
[i
] = (GLushort
) (flt
* 0xffff);
116 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
117 GLuint
*zValues
= (GLuint
*) values
;
118 for (i
= 0; i
< count
; i
++) {
120 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
123 zValues
[i
] = (GLuint
) (flt
* 0xffffffff);
125 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
129 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
130 GLuint
*zValues
= (GLuint
*) values
;
131 for (i
= 0; i
< count
; i
++) {
133 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
135 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
139 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_values");
145 * Put row of values into a renderbuffer that wraps a texture image.
148 texture_put_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
149 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
151 const struct texture_renderbuffer
*trb
152 = (const struct texture_renderbuffer
*) rb
;
153 const GLint z
= trb
->Zoffset
;
158 if (rb
->DataType
== CHAN_TYPE
) {
159 const GLchan
*rgba
= (const GLchan
*) values
;
160 for (i
= 0; i
< count
; i
++) {
161 if (!mask
|| mask
[i
]) {
162 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
167 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
168 const GLushort
*zValues
= (const GLushort
*) values
;
169 for (i
= 0; i
< count
; i
++) {
170 if (!mask
|| mask
[i
]) {
171 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
175 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
176 const GLuint
*zValues
= (const GLuint
*) values
;
177 for (i
= 0; i
< count
; i
++) {
178 if (!mask
|| mask
[i
]) {
179 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
183 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
184 const GLuint
*zValues
= (const GLuint
*) values
;
185 for (i
= 0; i
< count
; i
++) {
186 if (!mask
|| mask
[i
]) {
187 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
188 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
193 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
198 * Put row of RGB values into a renderbuffer that wraps a texture image.
201 texture_put_row_rgb(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
202 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
204 const struct texture_renderbuffer
*trb
205 = (const struct texture_renderbuffer
*) rb
;
206 const GLint z
= trb
->Zoffset
;
211 if (rb
->DataType
== CHAN_TYPE
) {
212 const GLchan
*rgb
= (const GLchan
*) values
;
213 for (i
= 0; i
< count
; i
++) {
214 if (!mask
|| mask
[i
]) {
215 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgb
);
220 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
221 const GLushort
*zValues
= (const GLushort
*) values
;
222 for (i
= 0; i
< count
; i
++) {
223 if (!mask
|| mask
[i
]) {
224 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
228 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
229 const GLuint
*zValues
= (const GLuint
*) values
;
230 for (i
= 0; i
< count
; i
++) {
231 if (!mask
|| mask
[i
]) {
232 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
236 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
237 const GLuint
*zValues
= (const GLuint
*) values
;
238 for (i
= 0; i
< count
; i
++) {
239 if (!mask
|| mask
[i
]) {
240 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
241 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
246 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
252 texture_put_mono_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
253 GLint x
, GLint y
, const void *value
, const GLubyte
*mask
)
255 const struct texture_renderbuffer
*trb
256 = (const struct texture_renderbuffer
*) rb
;
257 const GLint z
= trb
->Zoffset
;
262 if (rb
->DataType
== CHAN_TYPE
) {
263 const GLchan
*rgba
= (const GLchan
*) value
;
264 for (i
= 0; i
< count
; i
++) {
265 if (!mask
|| mask
[i
]) {
266 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
270 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
271 const GLushort zValue
= *((const GLushort
*) value
);
272 for (i
= 0; i
< count
; i
++) {
273 if (!mask
|| mask
[i
]) {
274 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
278 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
279 const GLuint zValue
= *((const GLuint
*) value
);
280 for (i
= 0; i
< count
; i
++) {
281 if (!mask
|| mask
[i
]) {
282 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
286 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
287 const GLuint zValue
= *((const GLuint
*) value
);
288 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
289 for (i
= 0; i
< count
; i
++) {
290 if (!mask
|| mask
[i
]) {
291 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
296 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_row");
302 texture_put_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
303 const GLint x
[], const GLint y
[], const void *values
,
306 const struct texture_renderbuffer
*trb
307 = (const struct texture_renderbuffer
*) rb
;
308 const GLint z
= trb
->Zoffset
;
311 if (rb
->DataType
== CHAN_TYPE
) {
312 const GLchan
*rgba
= (const GLchan
*) values
;
313 for (i
= 0; i
< count
; i
++) {
314 if (!mask
|| mask
[i
]) {
315 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
320 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
321 const GLushort
*zValues
= (const GLushort
*) values
;
322 for (i
= 0; i
< count
; i
++) {
323 if (!mask
|| mask
[i
]) {
324 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
328 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
329 const GLuint
*zValues
= (const GLuint
*) values
;
330 for (i
= 0; i
< count
; i
++) {
331 if (!mask
|| mask
[i
]) {
332 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
336 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
337 const GLuint
*zValues
= (const GLuint
*) values
;
338 for (i
= 0; i
< count
; i
++) {
339 if (!mask
|| mask
[i
]) {
340 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
341 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
346 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
352 texture_put_mono_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
353 GLuint count
, const GLint x
[], const GLint y
[],
354 const void *value
, const GLubyte
*mask
)
356 const struct texture_renderbuffer
*trb
357 = (const struct texture_renderbuffer
*) rb
;
358 const GLint z
= trb
->Zoffset
;
361 if (rb
->DataType
== CHAN_TYPE
) {
362 const GLchan
*rgba
= (const GLchan
*) value
;
363 for (i
= 0; i
< count
; i
++) {
364 if (!mask
|| mask
[i
]) {
365 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
369 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
370 const GLuint zValue
= *((const GLuint
*) value
);
371 for (i
= 0; i
< count
; i
++) {
372 if (!mask
|| mask
[i
]) {
373 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
377 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
378 const GLushort zValue
= *((const GLushort
*) value
);
379 for (i
= 0; i
< count
; i
++) {
380 if (!mask
|| mask
[i
]) {
381 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
385 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
386 const GLuint zValue
= *((const GLuint
*) value
);
387 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
388 for (i
= 0; i
< count
; i
++) {
389 if (!mask
|| mask
[i
]) {
390 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
395 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_values");
401 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
403 ASSERT(rb
->RefCount
== 0);
409 * This function creates a renderbuffer object which wraps a texture image.
410 * The new renderbuffer is plugged into the given attachment point.
411 * This allows rendering into the texture as if it were a renderbuffer.
414 wrap_texture(GLcontext
*ctx
, struct gl_renderbuffer_attachment
*att
)
416 struct texture_renderbuffer
*trb
;
417 const GLuint name
= 0;
419 ASSERT(att
->Type
== GL_TEXTURE
);
420 ASSERT(att
->Renderbuffer
== NULL
);
422 trb
= CALLOC_STRUCT(texture_renderbuffer
);
424 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
428 /* init base gl_renderbuffer fields */
429 _mesa_init_renderbuffer(&trb
->Base
, name
);
430 /* plug in our texture_renderbuffer-specific functions */
431 trb
->Base
.Delete
= delete_texture_wrapper
;
432 trb
->Base
.AllocStorage
= NULL
; /* illegal! */
433 trb
->Base
.GetRow
= texture_get_row
;
434 trb
->Base
.GetValues
= texture_get_values
;
435 trb
->Base
.PutRow
= texture_put_row
;
436 trb
->Base
.PutRowRGB
= texture_put_row_rgb
;
437 trb
->Base
.PutMonoRow
= texture_put_mono_row
;
438 trb
->Base
.PutValues
= texture_put_values
;
439 trb
->Base
.PutMonoValues
= texture_put_mono_values
;
441 /* update attachment point */
442 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
448 * Update the renderbuffer wrapper for rendering to a texture.
449 * For example, update the width, height of the RB based on the texture size,
450 * update the internal format info, etc.
453 update_wrapper(GLcontext
*ctx
, const struct gl_renderbuffer_attachment
*att
)
455 struct texture_renderbuffer
*trb
456 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
461 trb
->TexImage
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
462 ASSERT(trb
->TexImage
);
464 trb
->Store
= trb
->TexImage
->TexFormat
->StoreTexel
;
467 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
468 trb
->Yoffset
= att
->Zoffset
;
473 trb
->Zoffset
= att
->Zoffset
;
476 trb
->Base
.Width
= trb
->TexImage
->Width
;
477 trb
->Base
.Height
= trb
->TexImage
->Height
;
478 trb
->Base
.InternalFormat
= trb
->TexImage
->InternalFormat
;
479 /* XXX may need more special cases here */
480 if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z24_S8
) {
481 trb
->Base
._ActualFormat
= GL_DEPTH24_STENCIL8_EXT
;
482 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
484 else if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z16
) {
485 trb
->Base
._ActualFormat
= GL_DEPTH_COMPONENT
;
486 trb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
488 else if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z32
) {
489 trb
->Base
._ActualFormat
= GL_DEPTH_COMPONENT
;
490 trb
->Base
.DataType
= GL_UNSIGNED_INT
;
493 trb
->Base
._ActualFormat
= trb
->TexImage
->InternalFormat
;
494 trb
->Base
.DataType
= CHAN_TYPE
;
496 trb
->Base
._BaseFormat
= trb
->TexImage
->TexFormat
->BaseFormat
;
498 /* fix/avoid this assertion someday */
499 ASSERT(trb
->Base
._BaseFormat
== GL_RGB
||
500 trb
->Base
._BaseFormat
== GL_RGBA
||
501 trb
->Base
._BaseFormat
== GL_DEPTH_COMPONENT
);
503 trb
->Base
.Data
= trb
->TexImage
->Data
;
505 trb
->Base
.RedBits
= trb
->TexImage
->TexFormat
->RedBits
;
506 trb
->Base
.GreenBits
= trb
->TexImage
->TexFormat
->GreenBits
;
507 trb
->Base
.BlueBits
= trb
->TexImage
->TexFormat
->BlueBits
;
508 trb
->Base
.AlphaBits
= trb
->TexImage
->TexFormat
->AlphaBits
;
509 trb
->Base
.DepthBits
= trb
->TexImage
->TexFormat
->DepthBits
;
510 trb
->Base
.StencilBits
= trb
->TexImage
->TexFormat
->StencilBits
;
516 * Called when rendering to a texture image begins, or when changing
517 * the dest mipmap level, cube face, etc.
518 * This is a fallback routine for software render-to-texture.
520 * Called via the glRenderbufferTexture1D/2D/3D() functions
521 * and elsewhere (such as glTexImage2D).
523 * The image we're rendering into is
524 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
525 * It'll never be NULL.
527 * \param fb the framebuffer object the texture is being bound to
528 * \param att the fb attachment point of the texture
530 * \sa _mesa_framebuffer_renderbuffer
533 _mesa_render_texture(GLcontext
*ctx
,
534 struct gl_framebuffer
*fb
,
535 struct gl_renderbuffer_attachment
*att
)
539 if (!att
->Renderbuffer
) {
540 wrap_texture(ctx
, att
);
542 update_wrapper(ctx
, att
);
547 _mesa_finish_render_texture(GLcontext
*ctx
,
548 struct gl_renderbuffer_attachment
*att
)
551 /* The renderbuffer texture wrapper will get deleted by the
552 * normal mechanism for deleting renderbuffers.