s_texrender.c revision 3464ebd5
1
2#include "main/context.h"
3#include "main/colormac.h"
4#include "main/fbobject.h"
5#include "main/macros.h"
6#include "main/texfetch.h"
7#include "main/teximage.h"
8#include "main/renderbuffer.h"
9#include "swrast/swrast.h"
10
11
12/*
13 * Render-to-texture code for GL_EXT_framebuffer_object
14 */
15
16
17/**
18 * Derived from gl_renderbuffer class
19 */
20struct texture_renderbuffer
21{
22   struct gl_renderbuffer Base;   /**< Base class object */
23   struct gl_texture_image *TexImage;
24   StoreTexelFunc Store;
25   FetchTexelFuncF Fetchf;
26   GLint Yoffset;                 /**< Layer for 1D array textures. */
27   GLint Zoffset;                 /**< Layer for 2D array textures, or slice
28				   * for 3D textures
29				   */
30};
31
32
33/**
34 * Get row of values from the renderbuffer that wraps a texture image.
35 */
36static void
37texture_get_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
38                GLint x, GLint y, void *values)
39{
40   const struct texture_renderbuffer *trb
41      = (const struct texture_renderbuffer *) rb;
42   const GLint z = trb->Zoffset;
43   GLuint i;
44
45   ASSERT(trb->TexImage->Width == rb->Width);
46   ASSERT(trb->TexImage->Height == rb->Height);
47
48   y += trb->Yoffset;
49
50   if (rb->DataType == CHAN_TYPE) {
51      GLchan *rgbaOut = (GLchan *) values;
52      for (i = 0; i < count; i++) {
53         GLfloat rgba[4];
54         trb->Fetchf(trb->TexImage, x + i, y, z, rgba);
55         UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
56      }
57   }
58   else if (rb->DataType == GL_UNSIGNED_SHORT) {
59      GLushort *zValues = (GLushort *) values;
60      for (i = 0; i < count; i++) {
61         GLfloat flt;
62         trb->Fetchf(trb->TexImage, x + i, y, z, &flt);
63         zValues[i] = (GLushort) (flt * 0xffff);
64      }
65   }
66   else if (rb->DataType == GL_UNSIGNED_INT) {
67      GLuint *zValues = (GLuint *) values;
68      /*
69      const GLdouble scale = (GLdouble) 0xffffffff;
70      */
71      for (i = 0; i < count; i++) {
72         GLfloat flt;
73         trb->Fetchf(trb->TexImage, x + i, y, z, &flt);
74#if 0
75         /* this should work, but doesn't (overflow due to low precision) */
76         zValues[i] = (GLuint) (flt * scale);
77#else
78         /* temporary hack */
79         zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
80#endif
81      }
82   }
83   else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
84      GLuint *zValues = (GLuint *) values;
85      for (i = 0; i < count; i++) {
86         GLfloat flt;
87         trb->Fetchf(trb->TexImage, x + i, y, z, &flt);
88         zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
89      }
90   }
91   else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
92      GLuint *zValues = (GLuint *) values;
93      for (i = 0; i < count; i++) {
94         GLfloat flt;
95         trb->Fetchf(trb->TexImage, x + i, y, z, &flt);
96         zValues[i] = (GLuint) (flt * 0xffffff);
97      }
98   }
99   else {
100      _mesa_problem(ctx, "invalid rb->DataType in texture_get_row");
101   }
102}
103
104
105static void
106texture_get_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
107                   const GLint x[], const GLint y[], void *values)
108{
109   const struct texture_renderbuffer *trb
110      = (const struct texture_renderbuffer *) rb;
111   const GLint z = trb->Zoffset;
112   GLuint i;
113
114   if (rb->DataType == CHAN_TYPE) {
115      GLchan *rgbaOut = (GLchan *) values;
116      for (i = 0; i < count; i++) {
117         GLfloat rgba[4];
118         trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
119				    z, rgba);
120         UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
121      }
122   }
123   else if (rb->DataType == GL_UNSIGNED_SHORT) {
124      GLushort *zValues = (GLushort *) values;
125      for (i = 0; i < count; i++) {
126         GLfloat flt;
127         trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
128				    z, &flt);
129         zValues[i] = (GLushort) (flt * 0xffff);
130      }
131   }
132   else if (rb->DataType == GL_UNSIGNED_INT) {
133      GLuint *zValues = (GLuint *) values;
134      for (i = 0; i < count; i++) {
135         GLfloat flt;
136         trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
137				    z, &flt);
138#if 0
139         zValues[i] = (GLuint) (flt * 0xffffffff);
140#else
141         zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
142#endif
143      }
144   }
145   else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
146      GLuint *zValues = (GLuint *) values;
147      for (i = 0; i < count; i++) {
148         GLfloat flt;
149         trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
150				    z, &flt);
151         zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
152      }
153   }
154   else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
155      GLuint *zValues = (GLuint *) values;
156      for (i = 0; i < count; i++) {
157         GLfloat flt;
158         trb->Fetchf(trb->TexImage, x[i], y[i] + trb->Yoffset,
159				    z, &flt);
160         zValues[i] = (GLuint) (flt * 0xffffff);
161      }
162   }
163   else {
164      _mesa_problem(ctx, "invalid rb->DataType in texture_get_values");
165   }
166}
167
168
169/**
170 * Put row of values into a renderbuffer that wraps a texture image.
171 */
172static void
173texture_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
174                GLint x, GLint y, const void *values, const GLubyte *mask)
175{
176   const struct texture_renderbuffer *trb
177      = (const struct texture_renderbuffer *) rb;
178   const GLint z = trb->Zoffset;
179   GLuint i;
180
181   y += trb->Yoffset;
182
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);
188         }
189         rgba += 4;
190      }
191   }
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);
197         }
198      }
199   }
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);
205         }
206      }
207   }
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);
214         }
215      }
216   }
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);
223         }
224      }
225   }
226   else {
227      _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
228   }
229}
230
231/**
232 * Put row of RGB values into a renderbuffer that wraps a texture image.
233 */
234static void
235texture_put_row_rgb(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
236                GLint x, GLint y, const void *values, const GLubyte *mask)
237{
238   const struct texture_renderbuffer *trb
239      = (const struct texture_renderbuffer *) rb;
240   const GLint z = trb->Zoffset;
241   GLuint i;
242
243   y += trb->Yoffset;
244
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);
250         }
251         rgb += 3;
252      }
253   }
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);
259         }
260      }
261   }
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);
267         }
268      }
269   }
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);
276         }
277      }
278   }
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);
285         }
286      }
287   }
288   else {
289      _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
290   }
291}
292
293
294static void
295texture_put_mono_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
296                     GLint x, GLint y, const void *value, const GLubyte *mask)
297{
298   const struct texture_renderbuffer *trb
299      = (const struct texture_renderbuffer *) rb;
300   const GLint z = trb->Zoffset;
301   GLuint i;
302
303   y += trb->Yoffset;
304
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);
310         }
311      }
312   }
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);
318         }
319      }
320   }
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);
326         }
327      }
328   }
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);
335         }
336      }
337   }
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);
344         }
345      }
346   }
347   else {
348      _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_row");
349   }
350}
351
352
353static void
354texture_put_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
355                   const GLint x[], const GLint y[], const void *values,
356                   const GLubyte *mask)
357{
358   const struct texture_renderbuffer *trb
359      = (const struct texture_renderbuffer *) rb;
360   const GLint z = trb->Zoffset;
361   GLuint i;
362
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);
368         }
369         rgba += 4;
370      }
371   }
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);
377         }
378      }
379   }
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);
385         }
386      }
387   }
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);
394         }
395      }
396   }
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);
403         }
404      }
405   }
406   else {
407      _mesa_problem(ctx, "invalid rb->DataType in texture_put_values");
408   }
409}
410
411
412static void
413texture_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)
416{
417   const struct texture_renderbuffer *trb
418      = (const struct texture_renderbuffer *) rb;
419   const GLint z = trb->Zoffset;
420   GLuint i;
421
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);
427         }
428      }
429   }
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);
435         }
436      }
437   }
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);
443         }
444      }
445   }
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);
452         }
453      }
454   }
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);
461         }
462      }
463   }
464   else {
465      _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_values");
466   }
467}
468
469
470static void
471store_nop(struct gl_texture_image *texImage,
472          GLint col, GLint row, GLint img,
473          const void *texel)
474{
475}
476
477
478static void
479delete_texture_wrapper(struct gl_renderbuffer *rb)
480{
481   ASSERT(rb->RefCount == 0);
482   free(rb);
483}
484
485
486/**
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.
490 */
491static void
492wrap_texture(struct gl_context *ctx, struct gl_renderbuffer_attachment *att)
493{
494   struct texture_renderbuffer *trb;
495   const GLuint name = 0;
496
497   ASSERT(att->Type == GL_TEXTURE);
498   ASSERT(att->Renderbuffer == NULL);
499
500   trb = CALLOC_STRUCT(texture_renderbuffer);
501   if (!trb) {
502      _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture");
503      return;
504   }
505
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;
518
519   /* update attachment point */
520   _mesa_reference_renderbuffer(&att->Renderbuffer, &(trb->Base));
521}
522
523/**
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.
527 */
528static void
529update_wrapper(struct gl_context *ctx, struct gl_renderbuffer_attachment *att)
530{
531   struct texture_renderbuffer *trb
532      = (struct texture_renderbuffer *) att->Renderbuffer;
533
534   (void) ctx;
535   ASSERT(trb);
536
537   trb->TexImage = _mesa_get_attachment_teximage(att);
538   ASSERT(trb->TexImage);
539
540   trb->Store = _mesa_get_texel_store_func(trb->TexImage->TexFormat);
541   if (!trb->Store) {
542      /* we'll never draw into some textures (compressed formats) */
543      trb->Store = store_nop;
544   }
545
546   trb->Fetchf = trb->TexImage->FetchTexelf;
547
548   if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
549      trb->Yoffset = att->Zoffset;
550      trb->Zoffset = 0;
551   }
552   else {
553      trb->Yoffset = 0;
554      trb->Zoffset = att->Zoffset;
555   }
556
557   trb->Base.Width = trb->TexImage->Width;
558   trb->Base.Height = trb->TexImage->Height;
559   trb->Base.InternalFormat = trb->TexImage->InternalFormat;
560   trb->Base.Format = trb->TexImage->TexFormat;
561
562   /* XXX may need more special cases here */
563   switch (trb->TexImage->TexFormat) {
564   case MESA_FORMAT_Z24_S8:
565      trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
566      trb->Base._BaseFormat = GL_DEPTH_STENCIL;
567      break;
568   case MESA_FORMAT_S8_Z24:
569      trb->Base.DataType = GL_UNSIGNED_INT_8_24_REV_MESA;
570      trb->Base._BaseFormat = GL_DEPTH_STENCIL;
571      break;
572   case MESA_FORMAT_Z24_X8:
573      trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
574      trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
575      break;
576   case MESA_FORMAT_X8_Z24:
577      trb->Base.DataType = GL_UNSIGNED_INT_8_24_REV_MESA;
578      trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
579      break;
580   case MESA_FORMAT_Z16:
581      trb->Base.DataType = GL_UNSIGNED_SHORT;
582      trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
583      break;
584   case MESA_FORMAT_Z32:
585      trb->Base.DataType = GL_UNSIGNED_INT;
586      trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
587      break;
588   /* SRGB formats pre EXT_framebuffer_sRGB don't do sRGB translations on FBO readback */
589   case MESA_FORMAT_SRGB8:
590      trb->Fetchf = _mesa_get_texel_fetch_func(MESA_FORMAT_RGB888, _mesa_get_texture_dimensions(att->Texture->Target));
591      trb->Base.DataType = CHAN_TYPE;
592      trb->Base._BaseFormat = GL_RGBA;
593      break;
594   case MESA_FORMAT_SRGBA8:
595      trb->Fetchf = _mesa_get_texel_fetch_func(MESA_FORMAT_RGBA8888, _mesa_get_texture_dimensions(att->Texture->Target));
596      trb->Base.DataType = CHAN_TYPE;
597      trb->Base._BaseFormat = GL_RGBA;
598      break;
599   case MESA_FORMAT_SARGB8:
600      trb->Fetchf = _mesa_get_texel_fetch_func(MESA_FORMAT_ARGB8888, _mesa_get_texture_dimensions(att->Texture->Target));
601      trb->Base.DataType = CHAN_TYPE;
602      trb->Base._BaseFormat = GL_RGBA;
603      break;
604   default:
605      trb->Base.DataType = CHAN_TYPE;
606      trb->Base._BaseFormat = GL_RGBA;
607   }
608   trb->Base.Data = trb->TexImage->Data;
609}
610
611
612
613/**
614 * Called when rendering to a texture image begins, or when changing
615 * the dest mipmap level, cube face, etc.
616 * This is a fallback routine for software render-to-texture.
617 *
618 * Called via the glRenderbufferTexture1D/2D/3D() functions
619 * and elsewhere (such as glTexImage2D).
620 *
621 * The image we're rendering into is
622 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
623 * It'll never be NULL.
624 *
625 * \param fb  the framebuffer object the texture is being bound to
626 * \param att  the fb attachment point of the texture
627 *
628 * \sa _mesa_framebuffer_renderbuffer
629 */
630void
631_swrast_render_texture(struct gl_context *ctx,
632                       struct gl_framebuffer *fb,
633                       struct gl_renderbuffer_attachment *att)
634{
635   (void) fb;
636
637   if (!att->Renderbuffer) {
638      wrap_texture(ctx, att);
639   }
640   update_wrapper(ctx, att);
641}
642
643
644void
645_swrast_finish_render_texture(struct gl_context *ctx,
646                              struct gl_renderbuffer_attachment *att)
647{
648   /* do nothing */
649   /* The renderbuffer texture wrapper will get deleted by the
650    * normal mechanism for deleting renderbuffers.
651    */
652   (void) ctx;
653   (void) att;
654}
655