swrast: use BITFIELD64_BIT() macro to fix MSVC warnings
[mesa.git] / src / mesa / swrast / s_texrender.c
1
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"
11
12
13 /*
14 * Render-to-texture code for GL_EXT_framebuffer_object
15 */
16
17
18 /**
19 * Derived from gl_renderbuffer class
20 */
21 struct texture_renderbuffer
22 {
23 struct gl_renderbuffer Base; /**< Base class object */
24 struct swrast_texture_image *TexImage;
25 StoreTexelFunc Store;
26 FetchTexelFunc Fetch;
27 GLint Yoffset; /**< Layer for 1D array textures. */
28 GLint Zoffset; /**< Layer for 2D array textures, or slice
29 * for 3D textures
30 */
31 };
32
33
34 /** cast wrapper */
35 static inline struct texture_renderbuffer *
36 texture_renderbuffer(struct gl_renderbuffer *rb)
37 {
38 return (struct texture_renderbuffer *) rb;
39 }
40
41
42
43 /**
44 * Get row of values from the renderbuffer that wraps a texture image.
45 */
46 static void
47 texture_get_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
48 GLint x, GLint y, void *values)
49 {
50 struct texture_renderbuffer *trb = texture_renderbuffer(rb);
51 const GLint z = trb->Zoffset;
52 GLuint i;
53
54 ASSERT(trb->TexImage->Base.Width == rb->Width);
55 ASSERT(trb->TexImage->Base.Height == rb->Height);
56
57 y += trb->Yoffset;
58
59 if (rb->DataType == CHAN_TYPE) {
60 GLchan *rgbaOut = (GLchan *) values;
61 for (i = 0; i < count; i++) {
62 GLfloat rgba[4];
63 trb->Fetch(trb->TexImage, x + i, y, z, rgba);
64 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
65 }
66 }
67 else if (rb->DataType == GL_UNSIGNED_SHORT) {
68 GLushort *zValues = (GLushort *) values;
69 for (i = 0; i < count; i++) {
70 GLfloat flt;
71 trb->Fetch(trb->TexImage, x + i, y, z, &flt);
72 zValues[i] = (GLushort) (flt * 0xffff);
73 }
74 }
75 else if (rb->DataType == GL_UNSIGNED_INT) {
76 GLuint *zValues = (GLuint *) values;
77 /*
78 const GLdouble scale = (GLdouble) 0xffffffff;
79 */
80 for (i = 0; i < count; i++) {
81 GLfloat flt;
82 trb->Fetch(trb->TexImage, x + i, y, z, &flt);
83 #if 0
84 /* this should work, but doesn't (overflow due to low precision) */
85 zValues[i] = (GLuint) (flt * scale);
86 #else
87 /* temporary hack */
88 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
89 #endif
90 }
91 }
92 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
93 GLuint *zValues = (GLuint *) values;
94 for (i = 0; i < count; i++) {
95 GLfloat flt;
96 trb->Fetch(trb->TexImage, x + i, y, z, &flt);
97 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
98 }
99 }
100 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
101 GLuint *zValues = (GLuint *) values;
102 for (i = 0; i < count; i++) {
103 GLfloat flt;
104 trb->Fetch(trb->TexImage, x + i, y, z, &flt);
105 zValues[i] = (GLuint) (flt * 0xffffff);
106 }
107 }
108 else {
109 _mesa_problem(ctx, "invalid rb->DataType in texture_get_row");
110 }
111 }
112
113
114 static void
115 texture_get_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
116 const GLint x[], const GLint y[], void *values)
117 {
118 struct texture_renderbuffer *trb = texture_renderbuffer(rb);
119 const GLint z = trb->Zoffset;
120 GLuint i;
121
122 if (rb->DataType == CHAN_TYPE) {
123 GLchan *rgbaOut = (GLchan *) values;
124 for (i = 0; i < count; i++) {
125 GLfloat rgba[4];
126 trb->Fetch(trb->TexImage, x[i], y[i] + trb->Yoffset,
127 z, rgba);
128 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
129 }
130 }
131 else if (rb->DataType == GL_UNSIGNED_SHORT) {
132 GLushort *zValues = (GLushort *) values;
133 for (i = 0; i < count; i++) {
134 GLfloat flt;
135 trb->Fetch(trb->TexImage, x[i], y[i] + trb->Yoffset,
136 z, &flt);
137 zValues[i] = (GLushort) (flt * 0xffff);
138 }
139 }
140 else if (rb->DataType == GL_UNSIGNED_INT) {
141 GLuint *zValues = (GLuint *) values;
142 for (i = 0; i < count; i++) {
143 GLfloat flt;
144 trb->Fetch(trb->TexImage, x[i], y[i] + trb->Yoffset,
145 z, &flt);
146 #if 0
147 zValues[i] = (GLuint) (flt * 0xffffffff);
148 #else
149 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
150 #endif
151 }
152 }
153 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
154 GLuint *zValues = (GLuint *) values;
155 for (i = 0; i < count; i++) {
156 GLfloat flt;
157 trb->Fetch(trb->TexImage, x[i], y[i] + trb->Yoffset,
158 z, &flt);
159 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
160 }
161 }
162 else if (rb->DataType == GL_UNSIGNED_INT_8_24_REV_MESA) {
163 GLuint *zValues = (GLuint *) values;
164 for (i = 0; i < count; i++) {
165 GLfloat flt;
166 trb->Fetch(trb->TexImage, x[i], y[i] + trb->Yoffset,
167 z, &flt);
168 zValues[i] = (GLuint) (flt * 0xffffff);
169 }
170 }
171 else {
172 _mesa_problem(ctx, "invalid rb->DataType in texture_get_values");
173 }
174 }
175
176
177 /**
178 * Put row of values into a renderbuffer that wraps a texture image.
179 */
180 static void
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)
183 {
184 struct texture_renderbuffer *trb = texture_renderbuffer(rb);
185 const GLint z = trb->Zoffset;
186 GLuint i;
187
188 y += trb->Yoffset;
189
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);
195 }
196 rgba += 4;
197 }
198 }
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);
204 }
205 }
206 }
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);
212 }
213 }
214 }
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);
221 }
222 }
223 }
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);
230 }
231 }
232 }
233 else {
234 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
235 }
236 }
237
238
239 static void
240 texture_put_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
241 const GLint x[], const GLint y[], const void *values,
242 const GLubyte *mask)
243 {
244 struct texture_renderbuffer *trb = texture_renderbuffer(rb);
245 const GLint z = trb->Zoffset;
246 GLuint i;
247
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);
253 }
254 rgba += 4;
255 }
256 }
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);
262 }
263 }
264 }
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);
270 }
271 }
272 }
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);
279 }
280 }
281 }
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);
288 }
289 }
290 }
291 else {
292 _mesa_problem(ctx, "invalid rb->DataType in texture_put_values");
293 }
294 }
295
296
297 static void
298 store_nop(struct swrast_texture_image *texImage,
299 GLint col, GLint row, GLint img,
300 const void *texel)
301 {
302 }
303
304
305 static void
306 delete_texture_wrapper(struct gl_renderbuffer *rb)
307 {
308 ASSERT(rb->RefCount == 0);
309 free(rb);
310 }
311
312
313 /**
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.
317 */
318 static void
319 wrap_texture(struct gl_context *ctx, struct gl_renderbuffer_attachment *att)
320 {
321 struct texture_renderbuffer *trb;
322 const GLuint name = 0;
323
324 ASSERT(att->Type == GL_TEXTURE);
325 ASSERT(att->Renderbuffer == NULL);
326
327 trb = CALLOC_STRUCT(texture_renderbuffer);
328 if (!trb) {
329 _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture");
330 return;
331 }
332
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;
342
343 /* update attachment point */
344 _mesa_reference_renderbuffer(&att->Renderbuffer, &(trb->Base));
345 }
346
347 /**
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.
351 */
352 static void
353 update_wrapper(struct gl_context *ctx, struct gl_renderbuffer_attachment *att)
354 {
355 struct texture_renderbuffer *trb
356 = (struct texture_renderbuffer *) att->Renderbuffer;
357
358 (void) ctx;
359 ASSERT(trb);
360
361 trb->TexImage = swrast_texture_image(_mesa_get_attachment_teximage(att));
362 ASSERT(trb->TexImage);
363
364 trb->Store = _mesa_get_texel_store_func(trb->TexImage->Base.TexFormat);
365 if (!trb->Store) {
366 /* we'll never draw into some textures (compressed formats) */
367 trb->Store = store_nop;
368 }
369
370 if (!trb->TexImage->FetchTexel) {
371 _mesa_update_fetch_functions(trb->TexImage->Base.TexObject);
372 }
373 trb->Fetch = trb->TexImage->FetchTexel;
374 assert(trb->Fetch);
375
376 if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
377 trb->Yoffset = att->Zoffset;
378 trb->Zoffset = 0;
379 }
380 else {
381 trb->Yoffset = 0;
382 trb->Zoffset = att->Zoffset;
383 }
384
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;
390
391 /* Set the gl_renderbuffer::Data field so that mapping the buffer
392 * in renderbuffer.c succeeds.
393 */
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);
399 }
400 else {
401 trb->Base.Data = trb->TexImage->Buffer;
402 }
403
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;
409 break;
410 case MESA_FORMAT_S8_Z24:
411 trb->Base.DataType = GL_UNSIGNED_INT_8_24_REV_MESA;
412 trb->Base._BaseFormat = GL_DEPTH_STENCIL;
413 break;
414 case MESA_FORMAT_Z24_X8:
415 trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
416 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
417 break;
418 case MESA_FORMAT_X8_Z24:
419 trb->Base.DataType = GL_UNSIGNED_INT_8_24_REV_MESA;
420 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
421 break;
422 case MESA_FORMAT_Z16:
423 trb->Base.DataType = GL_UNSIGNED_SHORT;
424 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
425 break;
426 case MESA_FORMAT_Z32:
427 trb->Base.DataType = GL_UNSIGNED_INT;
428 trb->Base._BaseFormat = GL_DEPTH_COMPONENT;
429 break;
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;
435 break;
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;
440 break;
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;
445 break;
446 default:
447 trb->Base.DataType = CHAN_TYPE;
448 trb->Base._BaseFormat = GL_RGBA;
449 }
450 }
451
452
453
454 /**
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.
458 *
459 * Called via the glRenderbufferTexture1D/2D/3D() functions
460 * and elsewhere (such as glTexImage2D).
461 *
462 * The image we're rendering into is
463 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
464 * It'll never be NULL.
465 *
466 * \param fb the framebuffer object the texture is being bound to
467 * \param att the fb attachment point of the texture
468 *
469 * \sa _mesa_framebuffer_renderbuffer
470 */
471 void
472 _swrast_render_texture(struct gl_context *ctx,
473 struct gl_framebuffer *fb,
474 struct gl_renderbuffer_attachment *att)
475 {
476 (void) fb;
477
478 if (!att->Renderbuffer) {
479 wrap_texture(ctx, att);
480 }
481 update_wrapper(ctx, att);
482 }
483
484
485 void
486 _swrast_finish_render_texture(struct gl_context *ctx,
487 struct gl_renderbuffer_attachment *att)
488 {
489 /* do nothing */
490 /* The renderbuffer texture wrapper will get deleted by the
491 * normal mechanism for deleting renderbuffers.
492 */
493 (void) ctx;
494 (void) att;
495 }