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_context.h"
10 #include "swrast/s_texfetch.h"
14 * Render-to-texture code for GL_EXT_framebuffer_object
19 * Derived from gl_renderbuffer class
21 struct texture_renderbuffer
23 struct gl_renderbuffer Base
; /**< Base class object */
24 struct swrast_texture_image
*TexImage
;
27 GLint Yoffset
; /**< Layer for 1D array textures. */
28 GLint Zoffset
; /**< Layer for 2D array textures, or slice
35 static inline struct texture_renderbuffer
*
36 texture_renderbuffer(struct gl_renderbuffer
*rb
)
38 return (struct texture_renderbuffer
*) rb
;
44 * Get row of values from the renderbuffer that wraps a texture image.
47 texture_get_row(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
48 GLint x
, GLint y
, void *values
)
50 struct texture_renderbuffer
*trb
= texture_renderbuffer(rb
);
51 const GLint z
= trb
->Zoffset
;
54 ASSERT(trb
->TexImage
->Base
.Width
== rb
->Width
);
55 ASSERT(trb
->TexImage
->Base
.Height
== rb
->Height
);
59 if (rb
->DataType
== CHAN_TYPE
) {
60 GLchan
*rgbaOut
= (GLchan
*) values
;
61 for (i
= 0; i
< count
; i
++) {
63 trb
->Fetch(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
64 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
67 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
68 GLushort
*zValues
= (GLushort
*) values
;
69 for (i
= 0; i
< count
; i
++) {
71 trb
->Fetch(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
72 zValues
[i
] = (GLushort
) (flt
* 0xffff);
75 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
76 GLuint
*zValues
= (GLuint
*) values
;
78 const GLdouble scale = (GLdouble) 0xffffffff;
80 for (i
= 0; i
< count
; i
++) {
82 trb
->Fetch(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
84 /* this should work, but doesn't (overflow due to low precision) */
85 zValues
[i
] = (GLuint
) (flt
* scale
);
88 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
92 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
93 GLuint
*zValues
= (GLuint
*) values
;
94 for (i
= 0; i
< count
; i
++) {
96 trb
->Fetch(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
97 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
100 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
101 GLuint
*zValues
= (GLuint
*) values
;
102 for (i
= 0; i
< count
; i
++) {
104 trb
->Fetch(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
105 zValues
[i
] = (GLuint
) (flt
* 0xffffff);
109 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_row");
115 texture_get_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
116 const GLint x
[], const GLint y
[], void *values
)
118 struct texture_renderbuffer
*trb
= texture_renderbuffer(rb
);
119 const GLint z
= trb
->Zoffset
;
122 if (rb
->DataType
== CHAN_TYPE
) {
123 GLchan
*rgbaOut
= (GLchan
*) values
;
124 for (i
= 0; i
< count
; i
++) {
126 trb
->Fetch(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
128 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut
+ 4 * i
, rgba
);
131 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
132 GLushort
*zValues
= (GLushort
*) values
;
133 for (i
= 0; i
< count
; i
++) {
135 trb
->Fetch(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
137 zValues
[i
] = (GLushort
) (flt
* 0xffff);
140 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
141 GLuint
*zValues
= (GLuint
*) values
;
142 for (i
= 0; i
< count
; i
++) {
144 trb
->Fetch(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
147 zValues
[i
] = (GLuint
) (flt
* 0xffffffff);
149 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
153 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
154 GLuint
*zValues
= (GLuint
*) values
;
155 for (i
= 0; i
< count
; i
++) {
157 trb
->Fetch(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
159 zValues
[i
] = ((GLuint
) (flt
* 0xffffff)) << 8;
162 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
163 GLuint
*zValues
= (GLuint
*) values
;
164 for (i
= 0; i
< count
; i
++) {
166 trb
->Fetch(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
,
168 zValues
[i
] = (GLuint
) (flt
* 0xffffff);
172 _mesa_problem(ctx
, "invalid rb->DataType in texture_get_values");
178 * Put row of values into a renderbuffer that wraps a texture image.
181 texture_put_row(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
182 GLint x
, GLint y
, const void *values
, const GLubyte
*mask
)
184 struct texture_renderbuffer
*trb
= texture_renderbuffer(rb
);
185 const GLint z
= trb
->Zoffset
;
190 if (rb
->DataType
== CHAN_TYPE
) {
191 const GLchan
*rgba
= (const GLchan
*) values
;
192 for (i
= 0; i
< count
; i
++) {
193 if (!mask
|| mask
[i
]) {
194 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, rgba
);
199 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
200 const GLushort
*zValues
= (const GLushort
*) 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
) {
208 const GLuint
*zValues
= (const GLuint
*) values
;
209 for (i
= 0; i
< count
; i
++) {
210 if (!mask
|| mask
[i
]) {
211 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, zValues
+ i
);
215 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
216 const GLuint
*zValues
= (const GLuint
*) values
;
217 for (i
= 0; i
< count
; i
++) {
218 if (!mask
|| mask
[i
]) {
219 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
220 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
224 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
225 const GLuint
*zValues
= (const GLuint
*) values
;
226 for (i
= 0; i
< count
; i
++) {
227 if (!mask
|| mask
[i
]) {
228 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
229 trb
->Store(trb
->TexImage
, x
+ i
, y
, z
, &flt
);
234 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_row");
240 texture_put_values(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, GLuint count
,
241 const GLint x
[], const GLint y
[], const void *values
,
244 struct texture_renderbuffer
*trb
= texture_renderbuffer(rb
);
245 const GLint z
= trb
->Zoffset
;
248 if (rb
->DataType
== CHAN_TYPE
) {
249 const GLchan
*rgba
= (const GLchan
*) values
;
250 for (i
= 0; i
< count
; i
++) {
251 if (!mask
|| mask
[i
]) {
252 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, rgba
);
257 else if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
258 const GLushort
*zValues
= (const GLushort
*) values
;
259 for (i
= 0; i
< count
; i
++) {
260 if (!mask
|| mask
[i
]) {
261 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
265 else if (rb
->DataType
== GL_UNSIGNED_INT
) {
266 const GLuint
*zValues
= (const GLuint
*) values
;
267 for (i
= 0; i
< count
; i
++) {
268 if (!mask
|| mask
[i
]) {
269 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, zValues
+ i
);
273 else if (rb
->DataType
== GL_UNSIGNED_INT_24_8_EXT
) {
274 const GLuint
*zValues
= (const GLuint
*) values
;
275 for (i
= 0; i
< count
; i
++) {
276 if (!mask
|| mask
[i
]) {
277 GLfloat flt
= (GLfloat
) ((zValues
[i
] >> 8) * (1.0 / 0xffffff));
278 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
282 else if (rb
->DataType
== GL_UNSIGNED_INT_8_24_REV_MESA
) {
283 const GLuint
*zValues
= (const GLuint
*) values
;
284 for (i
= 0; i
< count
; i
++) {
285 if (!mask
|| mask
[i
]) {
286 GLfloat flt
= (GLfloat
) ((zValues
[i
] & 0xffffff) * (1.0 / 0xffffff));
287 trb
->Store(trb
->TexImage
, x
[i
], y
[i
] + trb
->Yoffset
, z
, &flt
);
292 _mesa_problem(ctx
, "invalid rb->DataType in texture_put_values");
298 store_nop(struct swrast_texture_image
*texImage
,
299 GLint col
, GLint row
, GLint img
,
306 delete_texture_wrapper(struct gl_renderbuffer
*rb
)
308 ASSERT(rb
->RefCount
== 0);
314 * This function creates a renderbuffer object which wraps a texture image.
315 * The new renderbuffer is plugged into the given attachment point.
316 * This allows rendering into the texture as if it were a renderbuffer.
319 wrap_texture(struct gl_context
*ctx
, struct gl_renderbuffer_attachment
*att
)
321 struct texture_renderbuffer
*trb
;
322 const GLuint name
= 0;
324 ASSERT(att
->Type
== GL_TEXTURE
);
325 ASSERT(att
->Renderbuffer
== NULL
);
327 trb
= CALLOC_STRUCT(texture_renderbuffer
);
329 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "wrap_texture");
333 /* init base gl_renderbuffer fields */
334 _mesa_init_renderbuffer(&trb
->Base
, name
);
335 /* plug in our texture_renderbuffer-specific functions */
336 trb
->Base
.Delete
= delete_texture_wrapper
;
337 trb
->Base
.AllocStorage
= NULL
; /* illegal! */
338 trb
->Base
.GetRow
= texture_get_row
;
339 trb
->Base
.GetValues
= texture_get_values
;
340 trb
->Base
.PutRow
= texture_put_row
;
341 trb
->Base
.PutValues
= texture_put_values
;
343 /* update attachment point */
344 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &(trb
->Base
));
348 * Update the renderbuffer wrapper for rendering to a texture.
349 * For example, update the width, height of the RB based on the texture size,
350 * update the internal format info, etc.
353 update_wrapper(struct gl_context
*ctx
, struct gl_renderbuffer_attachment
*att
)
355 struct texture_renderbuffer
*trb
356 = (struct texture_renderbuffer
*) att
->Renderbuffer
;
361 trb
->TexImage
= swrast_texture_image(_mesa_get_attachment_teximage(att
));
362 ASSERT(trb
->TexImage
);
364 trb
->Store
= _mesa_get_texel_store_func(trb
->TexImage
->Base
.TexFormat
);
366 /* we'll never draw into some textures (compressed formats) */
367 trb
->Store
= store_nop
;
370 if (!trb
->TexImage
->FetchTexel
) {
371 _mesa_update_fetch_functions(trb
->TexImage
->Base
.TexObject
);
373 trb
->Fetch
= trb
->TexImage
->FetchTexel
;
376 if (att
->Texture
->Target
== GL_TEXTURE_1D_ARRAY_EXT
) {
377 trb
->Yoffset
= att
->Zoffset
;
382 trb
->Zoffset
= att
->Zoffset
;
385 trb
->Base
.Width
= trb
->TexImage
->Base
.Width
;
386 trb
->Base
.Height
= trb
->TexImage
->Base
.Height
;
387 trb
->Base
.RowStride
= trb
->TexImage
->RowStride
;
388 trb
->Base
.InternalFormat
= trb
->TexImage
->Base
.InternalFormat
;
389 trb
->Base
.Format
= trb
->TexImage
->Base
.TexFormat
;
391 /* Set the gl_renderbuffer::Data field so that mapping the buffer
392 * in renderbuffer.c succeeds.
394 if (att
->Texture
->Target
== GL_TEXTURE_3D
||
395 att
->Texture
->Target
== GL_TEXTURE_2D_ARRAY_EXT
) {
396 trb
->Base
.Data
= trb
->TexImage
->Buffer
+
397 trb
->TexImage
->ImageOffsets
[trb
->Zoffset
] *
398 _mesa_get_format_bytes(trb
->TexImage
->Base
.TexFormat
);
401 trb
->Base
.Data
= trb
->TexImage
->Buffer
;
404 /* XXX may need more special cases here */
405 switch (trb
->TexImage
->Base
.TexFormat
) {
406 case MESA_FORMAT_Z24_S8
:
407 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
408 trb
->Base
._BaseFormat
= GL_DEPTH_STENCIL
;
410 case MESA_FORMAT_S8_Z24
:
411 trb
->Base
.DataType
= GL_UNSIGNED_INT_8_24_REV_MESA
;
412 trb
->Base
._BaseFormat
= GL_DEPTH_STENCIL
;
414 case MESA_FORMAT_Z24_X8
:
415 trb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
416 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
418 case MESA_FORMAT_X8_Z24
:
419 trb
->Base
.DataType
= GL_UNSIGNED_INT_8_24_REV_MESA
;
420 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
422 case MESA_FORMAT_Z16
:
423 trb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
424 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
426 case MESA_FORMAT_Z32
:
427 trb
->Base
.DataType
= GL_UNSIGNED_INT
;
428 trb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
430 /* SRGB formats pre EXT_framebuffer_sRGB don't do sRGB translations on FBO readback */
431 case MESA_FORMAT_SRGB8
:
432 trb
->Fetch
= _mesa_get_texel_fetch_func(MESA_FORMAT_RGB888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
433 trb
->Base
.DataType
= CHAN_TYPE
;
434 trb
->Base
._BaseFormat
= GL_RGBA
;
436 case MESA_FORMAT_SRGBA8
:
437 trb
->Fetch
= _mesa_get_texel_fetch_func(MESA_FORMAT_RGBA8888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
438 trb
->Base
.DataType
= CHAN_TYPE
;
439 trb
->Base
._BaseFormat
= GL_RGBA
;
441 case MESA_FORMAT_SARGB8
:
442 trb
->Fetch
= _mesa_get_texel_fetch_func(MESA_FORMAT_ARGB8888
, _mesa_get_texture_dimensions(att
->Texture
->Target
));
443 trb
->Base
.DataType
= CHAN_TYPE
;
444 trb
->Base
._BaseFormat
= GL_RGBA
;
447 trb
->Base
.DataType
= CHAN_TYPE
;
448 trb
->Base
._BaseFormat
= GL_RGBA
;
455 * Called when rendering to a texture image begins, or when changing
456 * the dest mipmap level, cube face, etc.
457 * This is a fallback routine for software render-to-texture.
459 * Called via the glRenderbufferTexture1D/2D/3D() functions
460 * and elsewhere (such as glTexImage2D).
462 * The image we're rendering into is
463 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
464 * It'll never be NULL.
466 * \param fb the framebuffer object the texture is being bound to
467 * \param att the fb attachment point of the texture
469 * \sa _mesa_framebuffer_renderbuffer
472 _swrast_render_texture(struct gl_context
*ctx
,
473 struct gl_framebuffer
*fb
,
474 struct gl_renderbuffer_attachment
*att
)
478 if (!att
->Renderbuffer
) {
479 wrap_texture(ctx
, att
);
481 update_wrapper(ctx
, att
);
486 _swrast_finish_render_texture(struct gl_context
*ctx
,
487 struct gl_renderbuffer_attachment
*att
)
490 /* The renderbuffer texture wrapper will get deleted by the
491 * normal mechanism for deleting renderbuffers.