7 #include "renderbuffer.h"
11 * Render-to-texture code for GL_EXT_framebuffer_object
16 * Derived from gl_renderbuffer class
18 struct texture_renderbuffer
20 struct gl_renderbuffer Base
; /**< Base class object */
21 struct gl_texture_image
*TexImage
;
23 GLint Yoffset
; /**< Layer for 1D array textures. */
24 GLint Zoffset
; /**< Layer for 2D array textures, or slice
31 * Get row of values from the renderbuffer that wraps a texture image.
34 texture_get_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
35 GLint x
, GLint y
, void *values
)
37 const struct texture_renderbuffer
*trb
38 = (const struct texture_renderbuffer
*) rb
;
39 const GLint z
= trb
->Zoffset
;
42 ASSERT(trb
->TexImage
->Width
== rb
->Width
);
43 ASSERT(trb
->TexImage
->Height
== rb
->Height
);
47 if (rb
->DataType
== CHAN_TYPE
) {
48 GLchan
*rgbaOut
= (GLchan
*) values
;
49 for (i
= 0; i
< count
; i
++) {
51 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
52 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
55 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
56 GLushort
*zValues
= (GLushort
*) values
;
57 for (i
= 0; i
< count
; i
++) {
59 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
60 zValues
[i
] = (GLushort
) (flt
* 0xffff);
63 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
64 GLuint
*zValues
= (GLuint
*) values
;
66 const GLdouble scale = (GLdouble) 0xffffffff;
68 for (i
= 0; i
< count
; i
++) {
70 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
72 /* this should work, but doesn't (overflow due to low precision) */
73 zValues
[i
] = (GLuint
) (flt
* scale
);
76 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
80 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
81 GLuint
*zValues
= (GLuint
*) values
;
82 for (i
= 0; i
< count
; i
++) {
84 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
85 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
89 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_row");
95 texture_get_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
96 const GLint x
[], const GLint y
[], void *values
)
98 const struct texture_renderbuffer
*trb
99 = (const struct texture_renderbuffer
*) rb
;
100 const GLint z
= trb
->Zoffset
;
103 if (rb
->DataType
== CHAN_TYPE
) {
104 GLchan
*rgbaOut
= (GLchan
*) values
;
105 for (i
= 0; i
< count
; i
++) {
107 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
109 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
112 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
113 GLushort
*zValues
= (GLushort
*) values
;
114 for (i
= 0; i
< count
; i
++) {
116 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
118 zValues
[i
] = (GLushort
) (flt
* 0xffff);
121 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
122 GLuint
*zValues
= (GLuint
*) values
;
123 for (i
= 0; i
< count
; i
++) {
125 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
128 zValues
[i
] = (GLuint
) (flt
* 0xffffffff);
130 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
134 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
135 GLuint
*zValues
= (GLuint
*) values
;
136 for (i
= 0; i
< count
; i
++) {
138 trb
->TexImage
->FetchTexelf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
140 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
144 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_values");
150 * Put row of values into a renderbuffer that wraps a texture image.
153 texture_put_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
154 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
156 const struct texture_renderbuffer
*trb
157 = (const struct texture_renderbuffer
*) rb
;
158 const GLint z
= trb
->Zoffset
;
163 if (rb
->DataType
== CHAN_TYPE
) {
164 const GLchan
*rgba
= (const GLchan
*) values
;
165 for (i
= 0; i
< count
; i
++) {
166 if (!mask
|| mask
[i
]) {
167 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
172 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
173 const GLushort
*zValues
= (const GLushort
*) values
;
174 for (i
= 0; i
< count
; i
++) {
175 if (!mask
|| mask
[i
]) {
176 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
180 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
181 const GLuint
*zValues
= (const GLuint
*) values
;
182 for (i
= 0; i
< count
; i
++) {
183 if (!mask
|| mask
[i
]) {
184 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
188 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
189 const GLuint
*zValues
= (const GLuint
*) values
;
190 for (i
= 0; i
< count
; i
++) {
191 if (!mask
|| mask
[i
]) {
192 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
193 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
198 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
203 * Put row of RGB values into a renderbuffer that wraps a texture image.
206 texture_put_row_rgb(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
207 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
209 const struct texture_renderbuffer
*trb
210 = (const struct texture_renderbuffer
*) rb
;
211 const GLint z
= trb
->Zoffset
;
216 if (rb
->DataType
== CHAN_TYPE
) {
217 const GLchan
*rgb
= (const GLchan
*) values
;
218 for (i
= 0; i
< count
; i
++) {
219 if (!mask
|| mask
[i
]) {
220 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgb
);
225 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
226 const GLushort
*zValues
= (const GLushort
*) values
;
227 for (i
= 0; i
< count
; i
++) {
228 if (!mask
|| mask
[i
]) {
229 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
233 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
234 const GLuint
*zValues
= (const GLuint
*) values
;
235 for (i
= 0; i
< count
; i
++) {
236 if (!mask
|| mask
[i
]) {
237 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
241 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
242 const GLuint
*zValues
= (const GLuint
*) values
;
243 for (i
= 0; i
< count
; i
++) {
244 if (!mask
|| mask
[i
]) {
245 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
246 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
251 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
257 texture_put_mono_row(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
258 GLint x
, GLint y
, const void *value
, const GLubyte
*mask
)
260 const struct texture_renderbuffer
*trb
261 = (const struct texture_renderbuffer
*) rb
;
262 const GLint z
= trb
->Zoffset
;
267 if (rb
->DataType
== CHAN_TYPE
) {
268 const GLchan
*rgba
= (const GLchan
*) value
;
269 for (i
= 0; i
< count
; i
++) {
270 if (!mask
|| mask
[i
]) {
271 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
275 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
276 const GLushort zValue
= *((const GLushort
*) value
);
277 for (i
= 0; i
< count
; i
++) {
278 if (!mask
|| mask
[i
]) {
279 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
283 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
284 const GLuint zValue
= *((const GLuint
*) value
);
285 for (i
= 0; i
< count
; i
++) {
286 if (!mask
|| mask
[i
]) {
287 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
291 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
292 const GLuint zValue
= *((const GLuint
*) value
);
293 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
294 for (i
= 0; i
< count
; i
++) {
295 if (!mask
|| mask
[i
]) {
296 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
301 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_row");
307 texture_put_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
308 const GLint x
[], const GLint y
[], const void *values
,
311 const struct texture_renderbuffer
*trb
312 = (const struct texture_renderbuffer
*) rb
;
313 const GLint z
= trb
->Zoffset
;
316 if (rb
->DataType
== CHAN_TYPE
) {
317 const GLchan
*rgba
= (const GLchan
*) values
;
318 for (i
= 0; i
< count
; i
++) {
319 if (!mask
|| mask
[i
]) {
320 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
325 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
326 const GLushort
*zValues
= (const GLushort
*) values
;
327 for (i
= 0; i
< count
; i
++) {
328 if (!mask
|| mask
[i
]) {
329 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
333 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
334 const GLuint
*zValues
= (const GLuint
*) values
;
335 for (i
= 0; i
< count
; i
++) {
336 if (!mask
|| mask
[i
]) {
337 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
341 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
342 const GLuint
*zValues
= (const GLuint
*) values
;
343 for (i
= 0; i
< count
; i
++) {
344 if (!mask
|| mask
[i
]) {
345 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
346 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
351 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
357 texture_put_mono_values(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
358 GLuint count
, const GLint x
[], const GLint y
[],
359 const void *value
, const GLubyte
*mask
)
361 const struct texture_renderbuffer
*trb
362 = (const struct texture_renderbuffer
*) rb
;
363 const GLint z
= trb
->Zoffset
;
366 if (rb
->DataType
== CHAN_TYPE
) {
367 const GLchan
*rgba
= (const GLchan
*) value
;
368 for (i
= 0; i
< count
; i
++) {
369 if (!mask
|| mask
[i
]) {
370 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
374 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
375 const GLuint zValue
= *((const GLuint
*) value
);
376 for (i
= 0; i
< count
; i
++) {
377 if (!mask
|| mask
[i
]) {
378 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
382 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
383 const GLushort zValue
= *((const GLushort
*) value
);
384 for (i
= 0; i
< count
; i
++) {
385 if (!mask
|| mask
[i
]) {
386 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
390 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
391 const GLuint zValue
= *((const GLuint
*) value
);
392 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
393 for (i
= 0; i
< count
; i
++) {
394 if (!mask
|| mask
[i
]) {
395 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
400 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_values");
406 store_nop(struct gl_texture_image
*texImage
,
407 GLint col
, GLint row
, GLint img
,
414 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
416 ASSERT(rb
->RefCount
== 0);
422 * This function creates a renderbuffer object which wraps a texture image.
423 * The new renderbuffer is plugged into the given attachment point.
424 * This allows rendering into the texture as if it were a renderbuffer.
427 wrap_texture(GLcontext
*ctx
, struct gl_renderbuffer_attachment
*att
)
429 struct texture_renderbuffer
*trb
;
430 const GLuint name
= 0;
432 ASSERT(att
->Type
== GL_TEXTURE
);
433 ASSERT(att
->Renderbuffer
== NULL
);
435 trb
= CALLOC_STRUCT(texture_renderbuffer
);
437 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
441 /* init base gl_renderbuffer fields */
442 _mesa_init_renderbuffer(&trb
->Base
, name
);
443 /* plug in our texture_renderbuffer-specific functions */
444 trb
->Base
.Delete
= delete_texture_wrapper
;
445 trb
->Base
.AllocStorage
= NULL
; /* illegal! */
446 trb
->Base
.GetRow
= texture_get_row
;
447 trb
->Base
.GetValues
= texture_get_values
;
448 trb
->Base
.PutRow
= texture_put_row
;
449 trb
->Base
.PutRowRGB
= texture_put_row_rgb
;
450 trb
->Base
.PutMonoRow
= texture_put_mono_row
;
451 trb
->Base
.PutValues
= texture_put_values
;
452 trb
->Base
.PutMonoValues
= texture_put_mono_values
;
454 /* update attachment point */
455 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
461 * Update the renderbuffer wrapper for rendering to a texture.
462 * For example, update the width, height of the RB based on the texture size,
463 * update the internal format info, etc.
466 update_wrapper(GLcontext
*ctx
, const struct gl_renderbuffer_attachment
*att
)
468 struct texture_renderbuffer
*trb
469 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
475 trb
->TexImage
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
476 ASSERT(trb
->TexImage
);
478 trb
->Store
= _mesa_get_texel_store_func(trb
->TexImage
->TexFormat
);
480 /* we'll never draw into some textures (compressed formats) */
481 trb
->Store
= store_nop
;
484 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
485 trb
->Yoffset
= att
->Zoffset
;
490 trb
->Zoffset
= att
->Zoffset
;
493 texFormat
= trb
->TexImage
->TexFormat
;
495 trb
->Base
.Width
= trb
->TexImage
->Width
;
496 trb
->Base
.Height
= trb
->TexImage
->Height
;
497 trb
->Base
.InternalFormat
= trb
->TexImage
->InternalFormat
;
498 /* XXX may need more special cases here */
499 if (trb
->TexImage
->TexFormat
== MESA_FORMAT_Z24_S8
) {
500 trb
->Base
.Format
= MESA_FORMAT_Z24_S8
;
501 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
503 else if (trb
->TexImage
->TexFormat
== MESA_FORMAT_Z16
) {
504 trb
->Base
.Format
= MESA_FORMAT_Z16
;
505 trb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
507 else if (trb
->TexImage
->TexFormat
== MESA_FORMAT_Z32
) {
508 trb
->Base
.Format
= MESA_FORMAT_Z32
;
509 trb
->Base
.DataType
= GL_UNSIGNED_INT
;
512 trb
->Base
.Format
= trb
->TexImage
->TexFormat
;
513 trb
->Base
.DataType
= CHAN_TYPE
;
515 trb
->Base
.Data
= trb
->TexImage
->Data
;
516 trb
->Base
._BaseFormat
= _mesa_base_fbo_format(ctx
, trb
->Base
.InternalFormat
);
522 * Called when rendering to a texture image begins, or when changing
523 * the dest mipmap level, cube face, etc.
524 * This is a fallback routine for software render-to-texture.
526 * Called via the glRenderbufferTexture1D/2D/3D() functions
527 * and elsewhere (such as glTexImage2D).
529 * The image we're rendering into is
530 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
531 * It'll never be NULL.
533 * \param fb the framebuffer object the texture is being bound to
534 * \param att the fb attachment point of the texture
536 * \sa _mesa_framebuffer_renderbuffer
539 _mesa_render_texture(GLcontext
*ctx
,
540 struct gl_framebuffer
*fb
,
541 struct gl_renderbuffer_attachment
*att
)
545 if (!att
->Renderbuffer
) {
546 wrap_texture(ctx
, att
);
548 update_wrapper(ctx
, att
);
553 _mesa_finish_render_texture(GLcontext
*ctx
,
554 struct gl_renderbuffer_attachment
*att
)
557 /* The renderbuffer texture wrapper will get deleted by the
558 * normal mechanism for deleting renderbuffers.