8 #include "renderbuffer.h"
12 * Render-to-texture code for GL_EXT_framebuffer_object
17 * Derived from gl_renderbuffer class
19 struct texture_renderbuffer
21 struct gl_renderbuffer Base
; /**< Base class object */
22 struct gl_texture_image
*TexImage
;
24 FetchTexelFuncF Fetchf
;
25 GLint Yoffset
; /**< Layer for 1D array textures. */
26 GLint Zoffset
; /**< Layer for 2D array textures, or slice
33 * Get row of values from the renderbuffer that wraps a texture image.
36 texture_get_row(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
37 GLint x
, GLint y
, void *values
)
39 const struct texture_renderbuffer
*trb
40 = (const struct texture_renderbuffer
*) rb
;
41 const GLint z
= trb
->Zoffset
;
44 ASSERT(trb
->TexImage
->Width
== rb
->Width
);
45 ASSERT(trb
->TexImage
->Height
== rb
->Height
);
49 if (rb
->DataType
== CHAN_TYPE
) {
50 GLchan
*rgbaOut
= (GLchan
*) values
;
51 for (i
= 0; i
< count
; i
++) {
53 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
54 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
57 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
58 GLushort
*zValues
= (GLushort
*) values
;
59 for (i
= 0; i
< count
; i
++) {
61 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
62 zValues
[i
] = (GLushort
) (flt
* 0xffff);
65 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
66 GLuint
*zValues
= (GLuint
*) values
;
68 const GLdouble scale = (GLdouble) 0xffffffff;
70 for (i
= 0; i
< count
; i
++) {
72 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
74 /* this should work, but doesn't (overflow due to low precision) */
75 zValues
[i
] = (GLuint
) (flt
* scale
);
78 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
82 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
83 GLuint
*zValues
= (GLuint
*) values
;
84 for (i
= 0; i
< count
; i
++) {
86 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
87 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
90 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
91 GLuint
*zValues
= (GLuint
*) values
;
92 for (i
= 0; i
< count
; i
++) {
94 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
95 zValues
[i
] = (GLuint
) (flt
* 0xffffff);
99 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_row");
105 texture_get_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
106 const GLint x
[], const GLint y
[], void *values
)
108 const struct texture_renderbuffer
*trb
109 = (const struct texture_renderbuffer
*) rb
;
110 const GLint z
= trb
->Zoffset
;
113 if (rb
->DataType
== CHAN_TYPE
) {
114 GLchan
*rgbaOut
= (GLchan
*) values
;
115 for (i
= 0; i
< count
; i
++) {
117 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
119 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
122 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
123 GLushort
*zValues
= (GLushort
*) values
;
124 for (i
= 0; i
< count
; i
++) {
126 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
128 zValues
[i
] = (GLushort
) (flt
* 0xffff);
131 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
132 GLuint
*zValues
= (GLuint
*) values
;
133 for (i
= 0; i
< count
; i
++) {
135 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
138 zValues
[i
] = (GLuint
) (flt
* 0xffffffff);
140 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
144 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
145 GLuint
*zValues
= (GLuint
*) values
;
146 for (i
= 0; i
< count
; i
++) {
148 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
150 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
153 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
154 GLuint
*zValues
= (GLuint
*) values
;
155 for (i
= 0; i
< count
; i
++) {
157 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
159 zValues
[i
] = (GLuint
) (flt
* 0xffffff);
163 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_values");
169 * Put row of values into a renderbuffer that wraps a texture image.
172 texture_put_row(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
173 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
175 const struct texture_renderbuffer
*trb
176 = (const struct texture_renderbuffer
*) rb
;
177 const GLint z
= trb
->Zoffset
;
182 if (rb
->DataType
== CHAN_TYPE
) {
183 const GLchan
*rgba
= (const GLchan
*) values
;
184 for (i
= 0; i
< count
; i
++) {
185 if (!mask
|| mask
[i
]) {
186 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
191 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
192 const GLushort
*zValues
= (const GLushort
*) values
;
193 for (i
= 0; i
< count
; i
++) {
194 if (!mask
|| mask
[i
]) {
195 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
199 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
200 const GLuint
*zValues
= (const GLuint
*) values
;
201 for (i
= 0; i
< count
; i
++) {
202 if (!mask
|| mask
[i
]) {
203 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
207 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
208 const GLuint
*zValues
= (const GLuint
*) values
;
209 for (i
= 0; i
< count
; i
++) {
210 if (!mask
|| mask
[i
]) {
211 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
212 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
216 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
217 const GLuint
*zValues
= (const GLuint
*) values
;
218 for (i
= 0; i
< count
; i
++) {
219 if (!mask
|| mask
[i
]) {
220 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
221 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
226 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
231 * Put row of RGB values into a renderbuffer that wraps a texture image.
234 texture_put_row_rgb(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
235 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
237 const struct texture_renderbuffer
*trb
238 = (const struct texture_renderbuffer
*) rb
;
239 const GLint z
= trb
->Zoffset
;
244 if (rb
->DataType
== CHAN_TYPE
) {
245 const GLchan
*rgb
= (const GLchan
*) values
;
246 for (i
= 0; i
< count
; i
++) {
247 if (!mask
|| mask
[i
]) {
248 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgb
);
253 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
254 const GLushort
*zValues
= (const GLushort
*) values
;
255 for (i
= 0; i
< count
; i
++) {
256 if (!mask
|| mask
[i
]) {
257 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
261 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
262 const GLuint
*zValues
= (const GLuint
*) values
;
263 for (i
= 0; i
< count
; i
++) {
264 if (!mask
|| mask
[i
]) {
265 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
269 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
270 const GLuint
*zValues
= (const GLuint
*) values
;
271 for (i
= 0; i
< count
; i
++) {
272 if (!mask
|| mask
[i
]) {
273 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
274 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
278 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
279 const GLuint
*zValues
= (const GLuint
*) values
;
280 for (i
= 0; i
< count
; i
++) {
281 if (!mask
|| mask
[i
]) {
282 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
283 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
288 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
294 texture_put_mono_row(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
295 GLint x
, GLint y
, const void *value
, const GLubyte
*mask
)
297 const struct texture_renderbuffer
*trb
298 = (const struct texture_renderbuffer
*) rb
;
299 const GLint z
= trb
->Zoffset
;
304 if (rb
->DataType
== CHAN_TYPE
) {
305 const GLchan
*rgba
= (const GLchan
*) value
;
306 for (i
= 0; i
< count
; i
++) {
307 if (!mask
|| mask
[i
]) {
308 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
312 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
313 const GLushort zValue
= *((const GLushort
*) value
);
314 for (i
= 0; i
< count
; i
++) {
315 if (!mask
|| mask
[i
]) {
316 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
320 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
321 const GLuint zValue
= *((const GLuint
*) value
);
322 for (i
= 0; i
< count
; i
++) {
323 if (!mask
|| mask
[i
]) {
324 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
328 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
329 const GLuint zValue
= *((const GLuint
*) value
);
330 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
331 for (i
= 0; i
< count
; i
++) {
332 if (!mask
|| mask
[i
]) {
333 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
337 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
338 const GLuint zValue
= *((const GLuint
*) value
);
339 const GLfloat flt
= (GLfloat
) ((zValue
& 0xffffff) * (1.0 / 0xffffff));
340 for (i
= 0; i
< count
; i
++) {
341 if (!mask
|| mask
[i
]) {
342 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
347 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_row");
353 texture_put_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
354 const GLint x
[], const GLint y
[], const void *values
,
357 const struct texture_renderbuffer
*trb
358 = (const struct texture_renderbuffer
*) rb
;
359 const GLint z
= trb
->Zoffset
;
362 if (rb
->DataType
== CHAN_TYPE
) {
363 const GLchan
*rgba
= (const GLchan
*) values
;
364 for (i
= 0; i
< count
; i
++) {
365 if (!mask
|| mask
[i
]) {
366 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
371 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
372 const GLushort
*zValues
= (const GLushort
*) values
;
373 for (i
= 0; i
< count
; i
++) {
374 if (!mask
|| mask
[i
]) {
375 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
379 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
380 const GLuint
*zValues
= (const GLuint
*) values
;
381 for (i
= 0; i
< count
; i
++) {
382 if (!mask
|| mask
[i
]) {
383 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
387 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
388 const GLuint
*zValues
= (const GLuint
*) values
;
389 for (i
= 0; i
< count
; i
++) {
390 if (!mask
|| mask
[i
]) {
391 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
392 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
396 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
397 const GLuint
*zValues
= (const GLuint
*) values
;
398 for (i
= 0; i
< count
; i
++) {
399 if (!mask
|| mask
[i
]) {
400 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
401 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
406 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
412 texture_put_mono_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
413 GLuint count
, const GLint x
[], const GLint y
[],
414 const void *value
, const GLubyte
*mask
)
416 const struct texture_renderbuffer
*trb
417 = (const struct texture_renderbuffer
*) rb
;
418 const GLint z
= trb
->Zoffset
;
421 if (rb
->DataType
== CHAN_TYPE
) {
422 const GLchan
*rgba
= (const GLchan
*) value
;
423 for (i
= 0; i
< count
; i
++) {
424 if (!mask
|| mask
[i
]) {
425 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
429 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
430 const GLuint zValue
= *((const GLuint
*) value
);
431 for (i
= 0; i
< count
; i
++) {
432 if (!mask
|| mask
[i
]) {
433 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
437 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
438 const GLushort zValue
= *((const GLushort
*) value
);
439 for (i
= 0; i
< count
; i
++) {
440 if (!mask
|| mask
[i
]) {
441 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
445 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
446 const GLuint zValue
= *((const GLuint
*) value
);
447 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
448 for (i
= 0; i
< count
; i
++) {
449 if (!mask
|| mask
[i
]) {
450 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
454 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
455 const GLuint zValue
= *((const GLuint
*) value
);
456 const GLfloat flt
= (GLfloat
) ((zValue
& 0xffffff) * (1.0 / 0xffffff));
457 for (i
= 0; i
< count
; i
++) {
458 if (!mask
|| mask
[i
]) {
459 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
464 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_values");
470 store_nop(struct gl_texture_image
*texImage
,
471 GLint col
, GLint row
, GLint img
,
478 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
480 ASSERT(rb
->RefCount
== 0);
486 * This function creates a renderbuffer object which wraps a texture image.
487 * The new renderbuffer is plugged into the given attachment point.
488 * This allows rendering into the texture as if it were a renderbuffer.
491 wrap_texture(struct gl_context
*ctx
, struct gl_renderbuffer_attachment
*att
)
493 struct texture_renderbuffer
*trb
;
494 const GLuint name
= 0;
496 ASSERT(att
->Type
== GL_TEXTURE
);
497 ASSERT(att
->Renderbuffer
== NULL
);
499 trb
= CALLOC_STRUCT(texture_renderbuffer
);
501 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
505 /* init base gl_renderbuffer fields */
506 _mesa_init_renderbuffer(&trb
->Base
, name
);
507 /* plug in our texture_renderbuffer-specific functions */
508 trb
->Base
.Delete
= delete_texture_wrapper
;
509 trb
->Base
.AllocStorage
= NULL
; /* illegal! */
510 trb
->Base
.GetRow
= texture_get_row
;
511 trb
->Base
.GetValues
= texture_get_values
;
512 trb
->Base
.PutRow
= texture_put_row
;
513 trb
->Base
.PutRowRGB
= texture_put_row_rgb
;
514 trb
->Base
.PutMonoRow
= texture_put_mono_row
;
515 trb
->Base
.PutValues
= texture_put_values
;
516 trb
->Base
.PutMonoValues
= texture_put_mono_values
;
518 /* update attachment point */
519 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
523 * Update the renderbuffer wrapper for rendering to a texture.
524 * For example, update the width, height of the RB based on the texture size,
525 * update the internal format info, etc.
528 update_wrapper(struct gl_context
*ctx
, const struct gl_renderbuffer_attachment
*att
)
530 struct texture_renderbuffer
*trb
531 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
536 trb
->TexImage
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
537 ASSERT(trb
->TexImage
);
539 trb
->Store
= _mesa_get_texel_store_func(trb
->TexImage
->TexFormat
);
541 /* we'll never draw into some textures (compressed formats) */
542 trb
->Store
= store_nop
;
545 trb
->Fetchf
= trb
->TexImage
->FetchTexelf
;
547 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
548 trb
->Yoffset
= att
->Zoffset
;
553 trb
->Zoffset
= att
->Zoffset
;
556 trb
->Base
.Width
= trb
->TexImage
->Width
;
557 trb
->Base
.Height
= trb
->TexImage
->Height
;
558 trb
->Base
.InternalFormat
= trb
->TexImage
->InternalFormat
;
559 trb
->Base
.Format
= trb
->TexImage
->TexFormat
;
561 /* XXX may need more special cases here */
562 switch (trb
->TexImage
->TexFormat
) {
563 case MESA_FORMAT_Z24_S8
:
564 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
565 trb
->Base
._BaseFormat
= GL_DEPTH_STENCIL
;
567 case MESA_FORMAT_S8_Z24
:
568 trb
->Base
.DataType
= GL_UNSIGNED_INT_8_24_REV_MESA
;
569 trb
->Base
._BaseFormat
= GL_DEPTH_STENCIL
;
571 case MESA_FORMAT_Z24_X8
:
572 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
573 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
575 case MESA_FORMAT_X8_Z24
:
576 trb
->Base
.DataType
= GL_UNSIGNED_INT_8_24_REV_MESA
;
577 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
579 case MESA_FORMAT_Z16
:
580 trb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
581 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
583 case MESA_FORMAT_Z32
:
584 trb
->Base
.DataType
= GL_UNSIGNED_INT
;
585 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
587 /* SRGB formats pre EXT_framebuffer_sRGB don't do sRGB translations on FBO readback */
588 case MESA_FORMAT_SRGB8
:
589 trb
->Fetchf
= _mesa_get_texel_fetch_func(MESA_FORMAT_RGB888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
590 trb
->Base
.DataType
= CHAN_TYPE
;
591 trb
->Base
._BaseFormat
= GL_RGBA
;
593 case MESA_FORMAT_SRGBA8
:
594 trb
->Fetchf
= _mesa_get_texel_fetch_func(MESA_FORMAT_RGBA8888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
595 trb
->Base
.DataType
= CHAN_TYPE
;
596 trb
->Base
._BaseFormat
= GL_RGBA
;
598 case MESA_FORMAT_SARGB8
:
599 trb
->Fetchf
= _mesa_get_texel_fetch_func(MESA_FORMAT_ARGB8888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
600 trb
->Base
.DataType
= CHAN_TYPE
;
601 trb
->Base
._BaseFormat
= GL_RGBA
;
604 trb
->Base
.DataType
= CHAN_TYPE
;
605 trb
->Base
._BaseFormat
= GL_RGBA
;
607 trb
->Base
.Data
= trb
->TexImage
->Data
;
613 * Called when rendering to a texture image begins, or when changing
614 * the dest mipmap level, cube face, etc.
615 * This is a fallback routine for software render-to-texture.
617 * Called via the glRenderbufferTexture1D/2D/3D() functions
618 * and elsewhere (such as glTexImage2D).
620 * The image we're rendering into is
621 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
622 * It'll never be NULL.
624 * \param fb the framebuffer object the texture is being bound to
625 * \param att the fb attachment point of the texture
627 * \sa _mesa_framebuffer_renderbuffer
630 _mesa_render_texture(struct gl_context
*ctx
,
631 struct gl_framebuffer
*fb
,
632 struct gl_renderbuffer_attachment
*att
)
636 if (!att
->Renderbuffer
) {
637 wrap_texture(ctx
, att
);
639 update_wrapper(ctx
, att
);
644 _mesa_finish_render_texture(struct gl_context
*ctx
,
645 struct gl_renderbuffer_attachment
*att
)
648 /* The renderbuffer texture wrapper will get deleted by the
649 * normal mechanism for deleting renderbuffers.