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");
199 texture_put_mono_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
200 GLint x
, GLint y
, const void *value
, const GLubyte
*mask
)
202 const struct texture_renderbuffer
*trb
203 = (const struct texture_renderbuffer
*) rb
;
204 const GLint z
= trb
->Zoffset
;
209 if (rb
->DataType
== CHAN_TYPE
) {
210 const GLchan
*rgba
= (const GLchan
*) value
;
211 for (i
= 0; i
< count
; i
++) {
212 if (!mask
|| mask
[i
]) {
213 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
217 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
218 const GLushort zValue
= *((const GLushort
*) value
);
219 for (i
= 0; i
< count
; i
++) {
220 if (!mask
|| mask
[i
]) {
221 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
225 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
226 const GLuint zValue
= *((const GLuint
*) value
);
227 for (i
= 0; i
< count
; i
++) {
228 if (!mask
|| mask
[i
]) {
229 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
233 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
234 const GLuint zValue
= *((const GLuint
*) value
);
235 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
236 for (i
= 0; i
< count
; i
++) {
237 if (!mask
|| mask
[i
]) {
238 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
243 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_row");
249 texture_put_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
250 const GLint x
[], const GLint y
[], const void *values
,
253 const struct texture_renderbuffer
*trb
254 = (const struct texture_renderbuffer
*) rb
;
255 const GLint z
= trb
->Zoffset
;
258 if (rb
->DataType
== CHAN_TYPE
) {
259 const GLchan
*rgba
= (const GLchan
*) values
;
260 for (i
= 0; i
< count
; i
++) {
261 if (!mask
|| mask
[i
]) {
262 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
267 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
268 const GLushort
*zValues
= (const GLushort
*) values
;
269 for (i
= 0; i
< count
; i
++) {
270 if (!mask
|| mask
[i
]) {
271 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
275 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
276 const GLuint
*zValues
= (const GLuint
*) values
;
277 for (i
= 0; i
< count
; i
++) {
278 if (!mask
|| mask
[i
]) {
279 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
283 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
284 const GLuint
*zValues
= (const GLuint
*) values
;
285 for (i
= 0; i
< count
; i
++) {
286 if (!mask
|| mask
[i
]) {
287 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
288 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
293 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
299 texture_put_mono_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
300 GLuint count
, const GLint x
[], const GLint y
[],
301 const void *value
, const GLubyte
*mask
)
303 const struct texture_renderbuffer
*trb
304 = (const struct texture_renderbuffer
*) rb
;
305 const GLint z
= trb
->Zoffset
;
308 if (rb
->DataType
== CHAN_TYPE
) {
309 const GLchan
*rgba
= (const GLchan
*) value
;
310 for (i
= 0; i
< count
; i
++) {
311 if (!mask
|| mask
[i
]) {
312 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
316 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
317 const GLuint zValue
= *((const GLuint
*) value
);
318 for (i
= 0; i
< count
; i
++) {
319 if (!mask
|| mask
[i
]) {
320 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
324 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
325 const GLushort zValue
= *((const GLushort
*) value
);
326 for (i
= 0; i
< count
; i
++) {
327 if (!mask
|| mask
[i
]) {
328 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
332 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
333 const GLuint zValue
= *((const GLuint
*) value
);
334 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
335 for (i
= 0; i
< count
; i
++) {
336 if (!mask
|| mask
[i
]) {
337 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
342 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_values");
348 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
350 ASSERT(rb
->RefCount
== 0);
356 * This function creates a renderbuffer object which wraps a texture image.
357 * The new renderbuffer is plugged into the given attachment point.
358 * This allows rendering into the texture as if it were a renderbuffer.
361 wrap_texture(GLcontext
*ctx
, struct gl_renderbuffer_attachment
*att
)
363 struct texture_renderbuffer
*trb
;
364 const GLuint name
= 0;
366 ASSERT(att
->Type
== GL_TEXTURE
);
367 ASSERT(att
->Renderbuffer
== NULL
);
369 trb
= CALLOC_STRUCT(texture_renderbuffer
);
371 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
375 /* init base gl_renderbuffer fields */
376 _mesa_init_renderbuffer(&trb
->Base
, name
);
377 /* plug in our texture_renderbuffer-specific functions */
378 trb
->Base
.Delete
= delete_texture_wrapper
;
379 trb
->Base
.AllocStorage
= NULL
; /* illegal! */
380 trb
->Base
.GetRow
= texture_get_row
;
381 trb
->Base
.GetValues
= texture_get_values
;
382 trb
->Base
.PutRow
= texture_put_row
;
383 trb
->Base
.PutMonoRow
= texture_put_mono_row
;
384 trb
->Base
.PutValues
= texture_put_values
;
385 trb
->Base
.PutMonoValues
= texture_put_mono_values
;
387 /* update attachment point */
388 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
394 * Update the renderbuffer wrapper for rendering to a texture.
395 * For example, update the width, height of the RB based on the texture size,
396 * update the internal format info, etc.
399 update_wrapper(GLcontext
*ctx
, const struct gl_renderbuffer_attachment
*att
)
401 struct texture_renderbuffer
*trb
402 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
407 trb
->TexImage
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
408 ASSERT(trb
->TexImage
);
410 trb
->Store
= trb
->TexImage
->TexFormat
->StoreTexel
;
413 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
414 trb
->Yoffset
= att
->Zoffset
;
419 trb
->Zoffset
= att
->Zoffset
;
422 trb
->Base
.Width
= trb
->TexImage
->Width
;
423 trb
->Base
.Height
= trb
->TexImage
->Height
;
424 trb
->Base
.InternalFormat
= trb
->TexImage
->InternalFormat
;
425 /* XXX may need more special cases here */
426 if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z24_S8
) {
427 trb
->Base
._ActualFormat
= GL_DEPTH24_STENCIL8_EXT
;
428 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
430 else if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z16
) {
431 trb
->Base
._ActualFormat
= GL_DEPTH_COMPONENT
;
432 trb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
434 else if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z32
) {
435 trb
->Base
._ActualFormat
= GL_DEPTH_COMPONENT
;
436 trb
->Base
.DataType
= GL_UNSIGNED_INT
;
439 trb
->Base
._ActualFormat
= trb
->TexImage
->InternalFormat
;
440 trb
->Base
.DataType
= CHAN_TYPE
;
442 trb
->Base
._BaseFormat
= trb
->TexImage
->TexFormat
->BaseFormat
;
444 /* fix/avoid this assertion someday */
445 ASSERT(trb
->Base
._BaseFormat
== GL_RGB
||
446 trb
->Base
._BaseFormat
== GL_RGBA
||
447 trb
->Base
._BaseFormat
== GL_DEPTH_COMPONENT
);
449 trb
->Base
.Data
= trb
->TexImage
->Data
;
451 trb
->Base
.RedBits
= trb
->TexImage
->TexFormat
->RedBits
;
452 trb
->Base
.GreenBits
= trb
->TexImage
->TexFormat
->GreenBits
;
453 trb
->Base
.BlueBits
= trb
->TexImage
->TexFormat
->BlueBits
;
454 trb
->Base
.AlphaBits
= trb
->TexImage
->TexFormat
->AlphaBits
;
455 trb
->Base
.DepthBits
= trb
->TexImage
->TexFormat
->DepthBits
;
461 * Called when rendering to a texture image begins, or when changing
462 * the dest mipmap level, cube face, etc.
463 * This is a fallback routine for software render-to-texture.
465 * Called via the glRenderbufferTexture1D/2D/3D() functions
466 * and elsewhere (such as glTexImage2D).
468 * The image we're rendering into is
469 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
470 * It'll never be NULL.
472 * \param fb the framebuffer object the texture is being bound to
473 * \param att the fb attachment point of the texture
475 * \sa _mesa_framebuffer_renderbuffer
478 _mesa_render_texture(GLcontext
*ctx
,
479 struct gl_framebuffer
*fb
,
480 struct gl_renderbuffer_attachment
*att
)
484 if (!att
->Renderbuffer
) {
485 wrap_texture(ctx
, att
);
487 update_wrapper(ctx
, att
);
492 _mesa_finish_render_texture(GLcontext
*ctx
,
493 struct gl_renderbuffer_attachment
*att
)
496 /* The renderbuffer texture wrapper will get deleted by the
497 * normal mechanism for deleting renderbuffers.