2 #include "main/context.h"
3 #include "main/colormac.h"
4 #include "main/fbobject.h"
5 #include "main/macros.h"
6 #include "main/teximage.h"
7 #include "main/renderbuffer.h"
8 #include "swrast/swrast.h"
9 #include "swrast/s_texfetch.h"
13 * Render-to-texture code for GL_EXT_framebuffer_object
18 * Derived from gl_renderbuffer class
20 struct texture_renderbuffer
22 struct gl_renderbuffer Base
; /**< Base class object */
23 struct gl_texture_image
*TexImage
;
25 FetchTexelFuncF Fetchf
;
26 GLint Yoffset
; /**< Layer for 1D array textures. */
27 GLint Zoffset
; /**< Layer for 2D array textures, or slice
34 * Get row of values from the renderbuffer that wraps a texture image.
37 texture_get_row(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
38 GLint x
, GLint y
, void *values
)
40 const struct texture_renderbuffer
*trb
41 = (const struct texture_renderbuffer
*) rb
;
42 const GLint z
= trb
->Zoffset
;
45 ASSERT(trb
->TexImage
->Width
== rb
->Width
);
46 ASSERT(trb
->TexImage
->Height
== rb
->Height
);
50 if (rb
->DataType
== CHAN_TYPE
) {
51 GLchan
*rgbaOut
= (GLchan
*) values
;
52 for (i
= 0; i
< count
; i
++) {
54 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
55 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
58 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
59 GLushort
*zValues
= (GLushort
*) values
;
60 for (i
= 0; i
< count
; i
++) {
62 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
63 zValues
[i
] = (GLushort
) (flt
* 0xffff);
66 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
67 GLuint
*zValues
= (GLuint
*) values
;
69 const GLdouble scale = (GLdouble) 0xffffffff;
71 for (i
= 0; i
< count
; i
++) {
73 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
75 /* this should work, but doesn't (overflow due to low precision) */
76 zValues
[i
] = (GLuint
) (flt
* scale
);
79 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
83 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
84 GLuint
*zValues
= (GLuint
*) values
;
85 for (i
= 0; i
< count
; i
++) {
87 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
88 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
91 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
92 GLuint
*zValues
= (GLuint
*) values
;
93 for (i
= 0; i
< count
; i
++) {
95 trb
->Fetchf(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
96 zValues
[i
] = (GLuint
) (flt
* 0xffffff);
100 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_row");
106 texture_get_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
107 const GLint x
[], const GLint y
[], void *values
)
109 const struct texture_renderbuffer
*trb
110 = (const struct texture_renderbuffer
*) rb
;
111 const GLint z
= trb
->Zoffset
;
114 if (rb
->DataType
== CHAN_TYPE
) {
115 GLchan
*rgbaOut
= (GLchan
*) values
;
116 for (i
= 0; i
< count
; i
++) {
118 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
120 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
123 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
124 GLushort
*zValues
= (GLushort
*) values
;
125 for (i
= 0; i
< count
; i
++) {
127 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
129 zValues
[i
] = (GLushort
) (flt
* 0xffff);
132 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
133 GLuint
*zValues
= (GLuint
*) values
;
134 for (i
= 0; i
< count
; i
++) {
136 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
139 zValues
[i
] = (GLuint
) (flt
* 0xffffffff);
141 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
145 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
146 GLuint
*zValues
= (GLuint
*) values
;
147 for (i
= 0; i
< count
; i
++) {
149 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
151 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
154 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
155 GLuint
*zValues
= (GLuint
*) values
;
156 for (i
= 0; i
< count
; i
++) {
158 trb
->Fetchf(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
160 zValues
[i
] = (GLuint
) (flt
* 0xffffff);
164 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_values");
170 * Put row of values into a renderbuffer that wraps a texture image.
173 texture_put_row(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
174 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
176 const struct texture_renderbuffer
*trb
177 = (const struct texture_renderbuffer
*) rb
;
178 const GLint z
= trb
->Zoffset
;
183 if (rb
->DataType
== CHAN_TYPE
) {
184 const GLchan
*rgba
= (const GLchan
*) values
;
185 for (i
= 0; i
< count
; i
++) {
186 if (!mask
|| mask
[i
]) {
187 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
192 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
193 const GLushort
*zValues
= (const GLushort
*) values
;
194 for (i
= 0; i
< count
; i
++) {
195 if (!mask
|| mask
[i
]) {
196 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
200 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
201 const GLuint
*zValues
= (const GLuint
*) values
;
202 for (i
= 0; i
< count
; i
++) {
203 if (!mask
|| mask
[i
]) {
204 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
208 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
209 const GLuint
*zValues
= (const GLuint
*) values
;
210 for (i
= 0; i
< count
; i
++) {
211 if (!mask
|| mask
[i
]) {
212 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
213 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
217 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
218 const GLuint
*zValues
= (const GLuint
*) values
;
219 for (i
= 0; i
< count
; i
++) {
220 if (!mask
|| mask
[i
]) {
221 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
222 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
227 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
232 * Put row of RGB values into a renderbuffer that wraps a texture image.
235 texture_put_row_rgb(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
236 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
238 const struct texture_renderbuffer
*trb
239 = (const struct texture_renderbuffer
*) rb
;
240 const GLint z
= trb
->Zoffset
;
245 if (rb
->DataType
== CHAN_TYPE
) {
246 const GLchan
*rgb
= (const GLchan
*) values
;
247 for (i
= 0; i
< count
; i
++) {
248 if (!mask
|| mask
[i
]) {
249 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgb
);
254 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
255 const GLushort
*zValues
= (const GLushort
*) values
;
256 for (i
= 0; i
< count
; i
++) {
257 if (!mask
|| mask
[i
]) {
258 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
262 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
263 const GLuint
*zValues
= (const GLuint
*) values
;
264 for (i
= 0; i
< count
; i
++) {
265 if (!mask
|| mask
[i
]) {
266 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
270 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
271 const GLuint
*zValues
= (const GLuint
*) values
;
272 for (i
= 0; i
< count
; i
++) {
273 if (!mask
|| mask
[i
]) {
274 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
275 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
279 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
280 const GLuint
*zValues
= (const GLuint
*) values
;
281 for (i
= 0; i
< count
; i
++) {
282 if (!mask
|| mask
[i
]) {
283 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
284 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
289 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
295 texture_put_mono_row(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
296 GLint x
, GLint y
, const void *value
, const GLubyte
*mask
)
298 const struct texture_renderbuffer
*trb
299 = (const struct texture_renderbuffer
*) rb
;
300 const GLint z
= trb
->Zoffset
;
305 if (rb
->DataType
== CHAN_TYPE
) {
306 const GLchan
*rgba
= (const GLchan
*) value
;
307 for (i
= 0; i
< count
; i
++) {
308 if (!mask
|| mask
[i
]) {
309 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
313 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
314 const GLushort zValue
= *((const GLushort
*) value
);
315 for (i
= 0; i
< count
; i
++) {
316 if (!mask
|| mask
[i
]) {
317 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
321 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
322 const GLuint zValue
= *((const GLuint
*) value
);
323 for (i
= 0; i
< count
; i
++) {
324 if (!mask
|| mask
[i
]) {
325 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &zValue
);
329 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
330 const GLuint zValue
= *((const GLuint
*) value
);
331 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
332 for (i
= 0; i
< count
; i
++) {
333 if (!mask
|| mask
[i
]) {
334 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
338 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
339 const GLuint zValue
= *((const GLuint
*) value
);
340 const GLfloat flt
= (GLfloat
) ((zValue
& 0xffffff) * (1.0 / 0xffffff));
341 for (i
= 0; i
< count
; i
++) {
342 if (!mask
|| mask
[i
]) {
343 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
348 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_row");
354 texture_put_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
355 const GLint x
[], const GLint y
[], const void *values
,
358 const struct texture_renderbuffer
*trb
359 = (const struct texture_renderbuffer
*) rb
;
360 const GLint z
= trb
->Zoffset
;
363 if (rb
->DataType
== CHAN_TYPE
) {
364 const GLchan
*rgba
= (const GLchan
*) values
;
365 for (i
= 0; i
< count
; i
++) {
366 if (!mask
|| mask
[i
]) {
367 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
372 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
373 const GLushort
*zValues
= (const GLushort
*) values
;
374 for (i
= 0; i
< count
; i
++) {
375 if (!mask
|| mask
[i
]) {
376 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
380 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
381 const GLuint
*zValues
= (const GLuint
*) values
;
382 for (i
= 0; i
< count
; i
++) {
383 if (!mask
|| mask
[i
]) {
384 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
388 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
389 const GLuint
*zValues
= (const GLuint
*) values
;
390 for (i
= 0; i
< count
; i
++) {
391 if (!mask
|| mask
[i
]) {
392 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
393 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
397 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
398 const GLuint
*zValues
= (const GLuint
*) values
;
399 for (i
= 0; i
< count
; i
++) {
400 if (!mask
|| mask
[i
]) {
401 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
402 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
407 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
413 texture_put_mono_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
414 GLuint count
, const GLint x
[], const GLint y
[],
415 const void *value
, const GLubyte
*mask
)
417 const struct texture_renderbuffer
*trb
418 = (const struct texture_renderbuffer
*) rb
;
419 const GLint z
= trb
->Zoffset
;
422 if (rb
->DataType
== CHAN_TYPE
) {
423 const GLchan
*rgba
= (const GLchan
*) value
;
424 for (i
= 0; i
< count
; i
++) {
425 if (!mask
|| mask
[i
]) {
426 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
430 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
431 const GLuint zValue
= *((const GLuint
*) value
);
432 for (i
= 0; i
< count
; i
++) {
433 if (!mask
|| mask
[i
]) {
434 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
438 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
439 const GLushort zValue
= *((const GLushort
*) value
);
440 for (i
= 0; i
< count
; i
++) {
441 if (!mask
|| mask
[i
]) {
442 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &zValue
);
446 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
447 const GLuint zValue
= *((const GLuint
*) value
);
448 const GLfloat flt
= (GLfloat
) ((zValue
>> 8) * (1.0 / 0xffffff));
449 for (i
= 0; i
< count
; i
++) {
450 if (!mask
|| mask
[i
]) {
451 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
455 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
456 const GLuint zValue
= *((const GLuint
*) value
);
457 const GLfloat flt
= (GLfloat
) ((zValue
& 0xffffff) * (1.0 / 0xffffff));
458 for (i
= 0; i
< count
; i
++) {
459 if (!mask
|| mask
[i
]) {
460 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
465 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_mono_values");
471 store_nop(struct gl_texture_image
*texImage
,
472 GLint col
, GLint row
, GLint img
,
479 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
481 ASSERT(rb
->RefCount
== 0);
487 * This function creates a renderbuffer object which wraps a texture image.
488 * The new renderbuffer is plugged into the given attachment point.
489 * This allows rendering into the texture as if it were a renderbuffer.
492 wrap_texture(struct gl_context
*ctx
, struct gl_renderbuffer_attachment
*att
)
494 struct texture_renderbuffer
*trb
;
495 const GLuint name
= 0;
497 ASSERT(att
->Type
== GL_TEXTURE
);
498 ASSERT(att
->Renderbuffer
== NULL
);
500 trb
= CALLOC_STRUCT(texture_renderbuffer
);
502 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
506 /* init base gl_renderbuffer fields */
507 _mesa_init_renderbuffer(&trb
->Base
, name
);
508 /* plug in our texture_renderbuffer-specific functions */
509 trb
->Base
.Delete
= delete_texture_wrapper
;
510 trb
->Base
.AllocStorage
= NULL
; /* illegal! */
511 trb
->Base
.GetRow
= texture_get_row
;
512 trb
->Base
.GetValues
= texture_get_values
;
513 trb
->Base
.PutRow
= texture_put_row
;
514 trb
->Base
.PutRowRGB
= texture_put_row_rgb
;
515 trb
->Base
.PutMonoRow
= texture_put_mono_row
;
516 trb
->Base
.PutValues
= texture_put_values
;
517 trb
->Base
.PutMonoValues
= texture_put_mono_values
;
519 /* update attachment point */
520 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
524 * Update the renderbuffer wrapper for rendering to a texture.
525 * For example, update the width, height of the RB based on the texture size,
526 * update the internal format info, etc.
529 update_wrapper(struct gl_context
*ctx
, struct gl_renderbuffer_attachment
*att
)
531 struct texture_renderbuffer
*trb
532 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
537 trb
->TexImage
= _mesa_get_attachment_teximage(att
);
538 ASSERT(trb
->TexImage
);
540 trb
->Store
= _mesa_get_texel_store_func(trb
->TexImage
->TexFormat
);
542 /* we'll never draw into some textures (compressed formats) */
543 trb
->Store
= store_nop
;
546 if (!trb
->TexImage
->FetchTexelf
) {
547 _mesa_update_fetch_functions(trb
->TexImage
->TexObject
);
549 trb
->Fetchf
= trb
->TexImage
->FetchTexelf
;
552 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
553 trb
->Yoffset
= att
->Zoffset
;
558 trb
->Zoffset
= att
->Zoffset
;
561 trb
->Base
.Width
= trb
->TexImage
->Width
;
562 trb
->Base
.Height
= trb
->TexImage
->Height
;
563 trb
->Base
.InternalFormat
= trb
->TexImage
->InternalFormat
;
564 trb
->Base
.Format
= trb
->TexImage
->TexFormat
;
566 /* XXX may need more special cases here */
567 switch (trb
->TexImage
->TexFormat
) {
568 case MESA_FORMAT_Z24_S8
:
569 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
570 trb
->Base
._BaseFormat
= GL_DEPTH_STENCIL
;
572 case MESA_FORMAT_S8_Z24
:
573 trb
->Base
.DataType
= GL_UNSIGNED_INT_8_24_REV_MESA
;
574 trb
->Base
._BaseFormat
= GL_DEPTH_STENCIL
;
576 case MESA_FORMAT_Z24_X8
:
577 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
578 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
580 case MESA_FORMAT_X8_Z24
:
581 trb
->Base
.DataType
= GL_UNSIGNED_INT_8_24_REV_MESA
;
582 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
584 case MESA_FORMAT_Z16
:
585 trb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
586 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
588 case MESA_FORMAT_Z32
:
589 trb
->Base
.DataType
= GL_UNSIGNED_INT
;
590 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
592 /* SRGB formats pre EXT_framebuffer_sRGB don't do sRGB translations on FBO readback */
593 case MESA_FORMAT_SRGB8
:
594 trb
->Fetchf
= _mesa_get_texel_fetch_func(MESA_FORMAT_RGB888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
595 trb
->Base
.DataType
= CHAN_TYPE
;
596 trb
->Base
._BaseFormat
= GL_RGBA
;
598 case MESA_FORMAT_SRGBA8
:
599 trb
->Fetchf
= _mesa_get_texel_fetch_func(MESA_FORMAT_RGBA8888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
600 trb
->Base
.DataType
= CHAN_TYPE
;
601 trb
->Base
._BaseFormat
= GL_RGBA
;
603 case MESA_FORMAT_SARGB8
:
604 trb
->Fetchf
= _mesa_get_texel_fetch_func(MESA_FORMAT_ARGB8888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
605 trb
->Base
.DataType
= CHAN_TYPE
;
606 trb
->Base
._BaseFormat
= GL_RGBA
;
609 trb
->Base
.DataType
= CHAN_TYPE
;
610 trb
->Base
._BaseFormat
= GL_RGBA
;
612 trb
->Base
.Data
= trb
->TexImage
->Data
;
618 * Called when rendering to a texture image begins, or when changing
619 * the dest mipmap level, cube face, etc.
620 * This is a fallback routine for software render-to-texture.
622 * Called via the glRenderbufferTexture1D/2D/3D() functions
623 * and elsewhere (such as glTexImage2D).
625 * The image we're rendering into is
626 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
627 * It'll never be NULL.
629 * \param fb the framebuffer object the texture is being bound to
630 * \param att the fb attachment point of the texture
632 * \sa _mesa_framebuffer_renderbuffer
635 _swrast_render_texture(struct gl_context
*ctx
,
636 struct gl_framebuffer
*fb
,
637 struct gl_renderbuffer_attachment
*att
)
641 if (!att
->Renderbuffer
) {
642 wrap_texture(ctx
, att
);
644 update_wrapper(ctx
, att
);
649 _swrast_finish_render_texture(struct gl_context
*ctx
,
650 struct gl_renderbuffer_attachment
*att
)
653 /* The renderbuffer texture wrapper will get deleted by the
654 * normal mechanism for deleting renderbuffers.