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_INT
) {
53 GLuint
*zValues
= (GLuint
*) values
;
55 const GLdouble scale = (GLdouble) 0xffffffff;
57 for (i
= 0; i
< count
; i
++) {
59 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
61 /* this should work, but doesn't (overflow due to low precision) */
62 zValues
[i
] = (GLuint
) (flt
* scale
);
65 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
69 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
70 GLuint
*zValues
= (GLuint
*) values
;
71 for (i
= 0; i
< count
; i
++) {
73 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
74 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
78 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_row");
84 texture_get_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
85 const GLint x
[], const GLint y
[], void *values
)
87 const struct texture_renderbuffer
*trb
88 = (const struct texture_renderbuffer
*) rb
;
89 const GLint z
= trb
->Zoffset
;
92 if (rb
->DataType
== CHAN_TYPE
) {
93 GLchan
*rgbaOut
= (GLchan
*) values
;
94 for (i
= 0; i
< count
; i
++) {
95 trb
->TexImage
->FetchTexelc(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
99 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
100 GLuint
*zValues
= (GLuint
*) values
;
101 for (i
= 0; i
< count
; i
++) {
103 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
106 zValues
[i
] = (GLuint
) (flt
* 0xffffffff);
108 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
112 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
113 GLuint
*zValues
= (GLuint
*) values
;
114 for (i
= 0; i
< count
; i
++) {
116 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
118 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
122 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_values");
128 * Put row of values into a renderbuffer that wraps a texture image.
131 texture_put_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
132 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
134 const struct texture_renderbuffer
*trb
135 = (const struct texture_renderbuffer
*) rb
;
136 const GLint z
= trb
->Zoffset
;
141 if (rb
->DataType
== CHAN_TYPE
) {
142 const GLchan
*rgba
= (const GLchan
*) values
;
143 for (i
= 0; i
< count
; i
++) {
144 if (!mask
|| mask
[i
]) {
145 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
150 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
151 const GLuint
*zValues
= (const GLuint
*) values
;
152 for (i
= 0; i
< count
; i
++) {
153 if (!mask
|| mask
[i
]) {
154 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
158 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
159 const GLuint
*zValues
= (const GLuint
*) values
;
160 for (i
= 0; i
< count
; i
++) {
161 if (!mask
|| mask
[i
]) {
162 GLfloat flt
= (zValues
[i
] >> 8) * (1.0 / 0xffffff);
163 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
168 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
174 texture_put_mono_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
175 GLint x
, GLint y
, const void *value
, const GLubyte
*mask
)
177 const struct texture_renderbuffer
*trb
178 = (const struct texture_renderbuffer
*) rb
;
179 const GLint z
= trb
->Zoffset
;
184 if (rb
->DataType
== CHAN_TYPE
) {
185 const GLchan
*rgba
= (const GLchan
*) value
;
186 for (i
= 0; i
< count
; i
++) {
187 if (!mask
|| mask
[i
]) {
188 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
192 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
193 const GLuint zValue
= *((const GLuint
*) value
);
194 for (i
= 0; i
< count
; i
++) {
195 if (!mask
|| mask
[i
]) {
196 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
200 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
201 const GLuint zValue
= *((const GLuint
*) value
);
202 const GLfloat flt
= (zValue
>> 8) * (1.0 / 0xffffff);
203 for (i
= 0; i
< count
; i
++) {
204 if (!mask
|| mask
[i
]) {
205 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
210 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_row");
216 texture_put_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
217 const GLint x
[], const GLint y
[], const void *values
,
220 const struct texture_renderbuffer
*trb
221 = (const struct texture_renderbuffer
*) rb
;
222 const GLint z
= trb
->Zoffset
;
225 if (rb
->DataType
== CHAN_TYPE
) {
226 const GLchan
*rgba
= (const GLchan
*) values
;
227 for (i
= 0; i
< count
; i
++) {
228 if (!mask
|| mask
[i
]) {
229 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
234 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
235 const GLuint
*zValues
= (const GLuint
*) values
;
236 for (i
= 0; i
< count
; i
++) {
237 if (!mask
|| mask
[i
]) {
238 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
,
243 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
244 const GLuint
*zValues
= (const GLuint
*) values
;
245 for (i
= 0; i
< count
; i
++) {
246 if (!mask
|| mask
[i
]) {
247 GLfloat flt
= (zValues
[i
] >> 8) * (1.0 / 0xffffff);
248 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
253 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
259 texture_put_mono_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
260 GLuint count
, const GLint x
[], const GLint y
[],
261 const void *value
, const GLubyte
*mask
)
263 const struct texture_renderbuffer
*trb
264 = (const struct texture_renderbuffer
*) rb
;
265 const GLint z
= trb
->Zoffset
;
268 if (rb
->DataType
== CHAN_TYPE
) {
269 const GLchan
*rgba
= (const GLchan
*) value
;
270 for (i
= 0; i
< count
; i
++) {
271 if (!mask
|| mask
[i
]) {
272 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
276 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
277 const GLuint zValue
= *((const GLuint
*) value
);
278 for (i
= 0; i
< count
; i
++) {
279 if (!mask
|| mask
[i
]) {
280 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
284 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
285 const GLuint zValue
= *((const GLuint
*) value
);
286 const GLfloat flt
= (zValue
>> 8) * (1.0 / 0xffffff);
287 for (i
= 0; i
< count
; i
++) {
288 if (!mask
|| mask
[i
]) {
289 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
294 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_values");
300 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
302 ASSERT(rb
->RefCount
== 0);
308 * This function creates a renderbuffer object which wraps a texture image.
309 * The new renderbuffer is plugged into the given attachment point.
310 * This allows rendering into the texture as if it were a renderbuffer.
313 wrap_texture(GLcontext
*ctx
, struct gl_renderbuffer_attachment
*att
)
315 struct texture_renderbuffer
*trb
;
316 const GLuint name
= 0;
318 ASSERT(att
->Type
== GL_TEXTURE
);
319 ASSERT(att
->Renderbuffer
== NULL
);
321 trb
= CALLOC_STRUCT(texture_renderbuffer
);
323 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
327 /* init base gl_renderbuffer fields */
328 _mesa_init_renderbuffer(&trb
->Base
, name
);
329 /* plug in our texture_renderbuffer-specific functions */
330 trb
->Base
.Delete
= delete_texture_wrapper
;
331 trb
->Base
.AllocStorage
= NULL
; /* illegal! */
332 trb
->Base
.GetRow
= texture_get_row
;
333 trb
->Base
.GetValues
= texture_get_values
;
334 trb
->Base
.PutRow
= texture_put_row
;
335 trb
->Base
.PutMonoRow
= texture_put_mono_row
;
336 trb
->Base
.PutValues
= texture_put_values
;
337 trb
->Base
.PutMonoValues
= texture_put_mono_values
;
339 /* update attachment point */
340 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
346 * Update the renderbuffer wrapper for rendering to a texture.
347 * For example, update the width, height of the RB based on the texture size,
348 * update the internal format info, etc.
351 update_wrapper(GLcontext
*ctx
, const struct gl_renderbuffer_attachment
*att
)
353 struct texture_renderbuffer
*trb
354 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
359 trb
->TexImage
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
360 ASSERT(trb
->TexImage
);
362 trb
->Store
= trb
->TexImage
->TexFormat
->StoreTexel
;
365 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
366 trb
->Yoffset
= att
->Zoffset
;
371 trb
->Zoffset
= att
->Zoffset
;
374 trb
->Base
.Width
= trb
->TexImage
->Width
;
375 trb
->Base
.Height
= trb
->TexImage
->Height
;
376 trb
->Base
.InternalFormat
= trb
->TexImage
->InternalFormat
;
377 /* XXX may need more special cases here */
378 if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z24_S8
) {
379 trb
->Base
._ActualFormat
= GL_DEPTH24_STENCIL8_EXT
;
380 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
382 else if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z16
) {
383 trb
->Base
._ActualFormat
= GL_DEPTH_COMPONENT
;
384 trb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
386 else if (trb
->TexImage
->TexFormat
->MesaFormat
== MESA_FORMAT_Z32
) {
387 trb
->Base
._ActualFormat
= GL_DEPTH_COMPONENT
;
388 trb
->Base
.DataType
= GL_UNSIGNED_INT
;
391 trb
->Base
._ActualFormat
= trb
->TexImage
->InternalFormat
;
392 trb
->Base
.DataType
= CHAN_TYPE
;
394 trb
->Base
._BaseFormat
= trb
->TexImage
->TexFormat
->BaseFormat
;
396 /* fix/avoid this assertion someday */
397 ASSERT(trb
->Base
._BaseFormat
== GL_RGB
||
398 trb
->Base
._BaseFormat
== GL_RGBA
||
399 trb
->Base
._BaseFormat
== GL_DEPTH_COMPONENT
);
401 trb
->Base
.Data
= trb
->TexImage
->Data
;
403 trb
->Base
.RedBits
= trb
->TexImage
->TexFormat
->RedBits
;
404 trb
->Base
.GreenBits
= trb
->TexImage
->TexFormat
->GreenBits
;
405 trb
->Base
.BlueBits
= trb
->TexImage
->TexFormat
->BlueBits
;
406 trb
->Base
.AlphaBits
= trb
->TexImage
->TexFormat
->AlphaBits
;
407 trb
->Base
.DepthBits
= trb
->TexImage
->TexFormat
->DepthBits
;
413 * Called when rendering to a texture image begins, or when changing
414 * the dest mipmap level, cube face, etc.
415 * This is a fallback routine for software render-to-texture.
417 * Called via the glRenderbufferTexture1D/2D/3D() functions
418 * and elsewhere (such as glTexImage2D).
420 * The image we're rendering into is
421 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
422 * It'll never be NULL.
424 * \param fb the framebuffer object the texture is being bound to
425 * \param att the fb attachment point of the texture
427 * \sa _mesa_framebuffer_renderbuffer
430 _mesa_render_texture(GLcontext
*ctx
,
431 struct gl_framebuffer
*fb
,
432 struct gl_renderbuffer_attachment
*att
)
436 if (!att
->Renderbuffer
) {
437 wrap_texture(ctx
, att
);
439 update_wrapper(ctx
, att
);
444 _mesa_finish_render_texture(GLcontext
*ctx
,
445 struct gl_renderbuffer_attachment
*att
)
448 /* The renderbuffer texture wrapper will get deleted by the
449 * normal mechanism for deleting renderbuffers.