gallium/draw: initial code to properly support llvm in the draw module
[mesa.git] / src / mesa / main / texrender.c
1
2 #include "context.h"
3 #include "colormac.h"
4 #include "fbobject.h"
5 #include "texfetch.h"
6 #include "texrender.h"
7 #include "renderbuffer.h"
8
9
10 /*
11 * Render-to-texture code for GL_EXT_framebuffer_object
12 */
13
14
15 /**
16 * Derived from gl_renderbuffer class
17 */
18 struct texture_renderbuffer
19 {
20 struct gl_renderbuffer Base; /**< Base class object */
21 struct gl_texture_image *TexImage;
22 StoreTexelFunc Store;
23 GLint Yoffset; /**< Layer for 1D array textures. */
24 GLint Zoffset; /**< Layer for 2D array textures, or slice
25 * for 3D textures
26 */
27 };
28
29
30 /**
31 * Get row of values from the renderbuffer that wraps a texture image.
32 */
33 static void
34 texture_get_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
35 GLint x, GLint y, void *values)
36 {
37 const struct texture_renderbuffer *trb
38 = (const struct texture_renderbuffer *) rb;
39 const GLint z = trb->Zoffset;
40 GLuint i;
41
42 ASSERT(trb->TexImage->Width == rb->Width);
43 ASSERT(trb->TexImage->Height == rb->Height);
44
45 y += trb->Yoffset;
46
47 if (rb->DataType == CHAN_TYPE) {
48 GLchan *rgbaOut = (GLchan *) values;
49 for (i = 0; i < count; i++) {
50 GLfloat rgba[4];
51 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, rgba);
52 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
53 }
54 }
55 else if (rb->DataType == GL_UNSIGNED_SHORT) {
56 GLushort *zValues = (GLushort *) values;
57 for (i = 0; i < count; i++) {
58 GLfloat flt;
59 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
60 zValues[i] = (GLushort) (flt * 0xffff);
61 }
62 }
63 else if (rb->DataType == GL_UNSIGNED_INT) {
64 GLuint *zValues = (GLuint *) values;
65 /*
66 const GLdouble scale = (GLdouble) 0xffffffff;
67 */
68 for (i = 0; i < count; i++) {
69 GLfloat flt;
70 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
71 #if 0
72 /* this should work, but doesn't (overflow due to low precision) */
73 zValues[i] = (GLuint) (flt * scale);
74 #else
75 /* temporary hack */
76 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
77 #endif
78 }
79 }
80 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
81 GLuint *zValues = (GLuint *) values;
82 for (i = 0; i < count; i++) {
83 GLfloat flt;
84 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
85 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
86 }
87 }
88 else {
89 _mesa_problem(ctx, "invalid rb->DataType in texture_get_row");
90 }
91 }
92
93
94 static void
95 texture_get_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
96 const GLint x[], const GLint y[], void *values)
97 {
98 const struct texture_renderbuffer *trb
99 = (const struct texture_renderbuffer *) rb;
100 const GLint z = trb->Zoffset;
101 GLuint i;
102
103 if (rb->DataType == CHAN_TYPE) {
104 GLchan *rgbaOut = (GLchan *) values;
105 for (i = 0; i < count; i++) {
106 GLfloat rgba[4];
107 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
108 z, rgba);
109 UNCLAMPED_FLOAT_TO_RGBA_CHAN(rgbaOut + 4 * i, rgba);
110 }
111 }
112 else if (rb->DataType == GL_UNSIGNED_SHORT) {
113 GLushort *zValues = (GLushort *) values;
114 for (i = 0; i < count; i++) {
115 GLfloat flt;
116 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
117 z, &flt);
118 zValues[i] = (GLushort) (flt * 0xffff);
119 }
120 }
121 else if (rb->DataType == GL_UNSIGNED_INT) {
122 GLuint *zValues = (GLuint *) values;
123 for (i = 0; i < count; i++) {
124 GLfloat flt;
125 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
126 z, &flt);
127 #if 0
128 zValues[i] = (GLuint) (flt * 0xffffffff);
129 #else
130 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
131 #endif
132 }
133 }
134 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
135 GLuint *zValues = (GLuint *) values;
136 for (i = 0; i < count; i++) {
137 GLfloat flt;
138 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
139 z, &flt);
140 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
141 }
142 }
143 else {
144 _mesa_problem(ctx, "invalid rb->DataType in texture_get_values");
145 }
146 }
147
148
149 /**
150 * Put row of values into a renderbuffer that wraps a texture image.
151 */
152 static void
153 texture_put_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
154 GLint x, GLint y, const void *values, const GLubyte *mask)
155 {
156 const struct texture_renderbuffer *trb
157 = (const struct texture_renderbuffer *) rb;
158 const GLint z = trb->Zoffset;
159 GLuint i;
160
161 y += trb->Yoffset;
162
163 if (rb->DataType == CHAN_TYPE) {
164 const GLchan *rgba = (const GLchan *) values;
165 for (i = 0; i < count; i++) {
166 if (!mask || mask[i]) {
167 trb->Store(trb->TexImage, x + i, y, z, rgba);
168 }
169 rgba += 4;
170 }
171 }
172 else if (rb->DataType == GL_UNSIGNED_SHORT) {
173 const GLushort *zValues = (const GLushort *) values;
174 for (i = 0; i < count; i++) {
175 if (!mask || mask[i]) {
176 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
177 }
178 }
179 }
180 else if (rb->DataType == GL_UNSIGNED_INT) {
181 const GLuint *zValues = (const GLuint *) values;
182 for (i = 0; i < count; i++) {
183 if (!mask || mask[i]) {
184 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
185 }
186 }
187 }
188 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
189 const GLuint *zValues = (const GLuint *) values;
190 for (i = 0; i < count; i++) {
191 if (!mask || mask[i]) {
192 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
193 trb->Store(trb->TexImage, x + i, y, z, &flt);
194 }
195 }
196 }
197 else {
198 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
199 }
200 }
201
202 /**
203 * Put row of RGB values into a renderbuffer that wraps a texture image.
204 */
205 static void
206 texture_put_row_rgb(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
207 GLint x, GLint y, const void *values, const GLubyte *mask)
208 {
209 const struct texture_renderbuffer *trb
210 = (const struct texture_renderbuffer *) rb;
211 const GLint z = trb->Zoffset;
212 GLuint i;
213
214 y += trb->Yoffset;
215
216 if (rb->DataType == CHAN_TYPE) {
217 const GLchan *rgb = (const GLchan *) values;
218 for (i = 0; i < count; i++) {
219 if (!mask || mask[i]) {
220 trb->Store(trb->TexImage, x + i, y, z, rgb);
221 }
222 rgb += 3;
223 }
224 }
225 else if (rb->DataType == GL_UNSIGNED_SHORT) {
226 const GLushort *zValues = (const GLushort *) values;
227 for (i = 0; i < count; i++) {
228 if (!mask || mask[i]) {
229 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
230 }
231 }
232 }
233 else if (rb->DataType == GL_UNSIGNED_INT) {
234 const GLuint *zValues = (const GLuint *) values;
235 for (i = 0; i < count; i++) {
236 if (!mask || mask[i]) {
237 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
238 }
239 }
240 }
241 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
242 const GLuint *zValues = (const GLuint *) values;
243 for (i = 0; i < count; i++) {
244 if (!mask || mask[i]) {
245 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
246 trb->Store(trb->TexImage, x + i, y, z, &flt);
247 }
248 }
249 }
250 else {
251 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
252 }
253 }
254
255
256 static void
257 texture_put_mono_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
258 GLint x, GLint y, const void *value, const GLubyte *mask)
259 {
260 const struct texture_renderbuffer *trb
261 = (const struct texture_renderbuffer *) rb;
262 const GLint z = trb->Zoffset;
263 GLuint i;
264
265 y += trb->Yoffset;
266
267 if (rb->DataType == CHAN_TYPE) {
268 const GLchan *rgba = (const GLchan *) value;
269 for (i = 0; i < count; i++) {
270 if (!mask || mask[i]) {
271 trb->Store(trb->TexImage, x + i, y, z, rgba);
272 }
273 }
274 }
275 else if (rb->DataType == GL_UNSIGNED_SHORT) {
276 const GLushort zValue = *((const GLushort *) value);
277 for (i = 0; i < count; i++) {
278 if (!mask || mask[i]) {
279 trb->Store(trb->TexImage, x + i, y, z, &zValue);
280 }
281 }
282 }
283 else if (rb->DataType == GL_UNSIGNED_INT) {
284 const GLuint zValue = *((const GLuint *) value);
285 for (i = 0; i < count; i++) {
286 if (!mask || mask[i]) {
287 trb->Store(trb->TexImage, x + i, y, z, &zValue);
288 }
289 }
290 }
291 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
292 const GLuint zValue = *((const GLuint *) value);
293 const GLfloat flt = (GLfloat) ((zValue >> 8) * (1.0 / 0xffffff));
294 for (i = 0; i < count; i++) {
295 if (!mask || mask[i]) {
296 trb->Store(trb->TexImage, x + i, y, z, &flt);
297 }
298 }
299 }
300 else {
301 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_row");
302 }
303 }
304
305
306 static void
307 texture_put_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
308 const GLint x[], const GLint y[], const void *values,
309 const GLubyte *mask)
310 {
311 const struct texture_renderbuffer *trb
312 = (const struct texture_renderbuffer *) rb;
313 const GLint z = trb->Zoffset;
314 GLuint i;
315
316 if (rb->DataType == CHAN_TYPE) {
317 const GLchan *rgba = (const GLchan *) values;
318 for (i = 0; i < count; i++) {
319 if (!mask || mask[i]) {
320 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
321 }
322 rgba += 4;
323 }
324 }
325 else if (rb->DataType == GL_UNSIGNED_SHORT) {
326 const GLushort *zValues = (const GLushort *) values;
327 for (i = 0; i < count; i++) {
328 if (!mask || mask[i]) {
329 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, zValues + i);
330 }
331 }
332 }
333 else if (rb->DataType == GL_UNSIGNED_INT) {
334 const GLuint *zValues = (const GLuint *) values;
335 for (i = 0; i < count; i++) {
336 if (!mask || mask[i]) {
337 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, zValues + i);
338 }
339 }
340 }
341 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
342 const GLuint *zValues = (const GLuint *) values;
343 for (i = 0; i < count; i++) {
344 if (!mask || mask[i]) {
345 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
346 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
347 }
348 }
349 }
350 else {
351 _mesa_problem(ctx, "invalid rb->DataType in texture_put_values");
352 }
353 }
354
355
356 static void
357 texture_put_mono_values(GLcontext *ctx, struct gl_renderbuffer *rb,
358 GLuint count, const GLint x[], const GLint y[],
359 const void *value, const GLubyte *mask)
360 {
361 const struct texture_renderbuffer *trb
362 = (const struct texture_renderbuffer *) rb;
363 const GLint z = trb->Zoffset;
364 GLuint i;
365
366 if (rb->DataType == CHAN_TYPE) {
367 const GLchan *rgba = (const GLchan *) value;
368 for (i = 0; i < count; i++) {
369 if (!mask || mask[i]) {
370 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
371 }
372 }
373 }
374 else if (rb->DataType == GL_UNSIGNED_INT) {
375 const GLuint zValue = *((const GLuint *) value);
376 for (i = 0; i < count; i++) {
377 if (!mask || mask[i]) {
378 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
379 }
380 }
381 }
382 else if (rb->DataType == GL_UNSIGNED_SHORT) {
383 const GLushort zValue = *((const GLushort *) value);
384 for (i = 0; i < count; i++) {
385 if (!mask || mask[i]) {
386 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
387 }
388 }
389 }
390 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
391 const GLuint zValue = *((const GLuint *) value);
392 const GLfloat flt = (GLfloat) ((zValue >> 8) * (1.0 / 0xffffff));
393 for (i = 0; i < count; i++) {
394 if (!mask || mask[i]) {
395 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
396 }
397 }
398 }
399 else {
400 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_values");
401 }
402 }
403
404
405 static void
406 store_nop(struct gl_texture_image *texImage,
407 GLint col, GLint row, GLint img,
408 const void *texel)
409 {
410 }
411
412
413 static void
414 delete_texture_wrapper(struct gl_renderbuffer *rb)
415 {
416 ASSERT(rb->RefCount == 0);
417 free(rb);
418 }
419
420
421 /**
422 * This function creates a renderbuffer object which wraps a texture image.
423 * The new renderbuffer is plugged into the given attachment point.
424 * This allows rendering into the texture as if it were a renderbuffer.
425 */
426 static void
427 wrap_texture(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
428 {
429 struct texture_renderbuffer *trb;
430 const GLuint name = 0;
431
432 ASSERT(att->Type == GL_TEXTURE);
433 ASSERT(att->Renderbuffer == NULL);
434
435 trb = CALLOC_STRUCT(texture_renderbuffer);
436 if (!trb) {
437 _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture");
438 return;
439 }
440
441 /* init base gl_renderbuffer fields */
442 _mesa_init_renderbuffer(&trb->Base, name);
443 /* plug in our texture_renderbuffer-specific functions */
444 trb->Base.Delete = delete_texture_wrapper;
445 trb->Base.AllocStorage = NULL; /* illegal! */
446 trb->Base.GetRow = texture_get_row;
447 trb->Base.GetValues = texture_get_values;
448 trb->Base.PutRow = texture_put_row;
449 trb->Base.PutRowRGB = texture_put_row_rgb;
450 trb->Base.PutMonoRow = texture_put_mono_row;
451 trb->Base.PutValues = texture_put_values;
452 trb->Base.PutMonoValues = texture_put_mono_values;
453
454 /* update attachment point */
455 _mesa_reference_renderbuffer(&att->Renderbuffer, &(trb->Base));
456 }
457
458
459
460 /**
461 * Update the renderbuffer wrapper for rendering to a texture.
462 * For example, update the width, height of the RB based on the texture size,
463 * update the internal format info, etc.
464 */
465 static void
466 update_wrapper(GLcontext *ctx, const struct gl_renderbuffer_attachment *att)
467 {
468 struct texture_renderbuffer *trb
469 = (struct texture_renderbuffer *) att->Renderbuffer;
470
471 (void) ctx;
472 ASSERT(trb);
473
474 trb->TexImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
475 ASSERT(trb->TexImage);
476
477 trb->Store = _mesa_get_texel_store_func(trb->TexImage->TexFormat);
478 if (!trb->Store) {
479 /* we'll never draw into some textures (compressed formats) */
480 trb->Store = store_nop;
481 }
482
483 if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
484 trb->Yoffset = att->Zoffset;
485 trb->Zoffset = 0;
486 }
487 else {
488 trb->Yoffset = 0;
489 trb->Zoffset = att->Zoffset;
490 }
491
492 trb->Base.Width = trb->TexImage->Width;
493 trb->Base.Height = trb->TexImage->Height;
494 trb->Base.InternalFormat = trb->TexImage->InternalFormat;
495 /* XXX may need more special cases here */
496 if (trb->TexImage->TexFormat == MESA_FORMAT_Z24_S8) {
497 trb->Base.Format = MESA_FORMAT_Z24_S8;
498 trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
499 }
500 else if (trb->TexImage->TexFormat == MESA_FORMAT_Z16) {
501 trb->Base.Format = MESA_FORMAT_Z16;
502 trb->Base.DataType = GL_UNSIGNED_SHORT;
503 }
504 else if (trb->TexImage->TexFormat == MESA_FORMAT_Z32) {
505 trb->Base.Format = MESA_FORMAT_Z32;
506 trb->Base.DataType = GL_UNSIGNED_INT;
507 }
508 else {
509 trb->Base.Format = trb->TexImage->TexFormat;
510 trb->Base.DataType = CHAN_TYPE;
511 }
512 trb->Base.Data = trb->TexImage->Data;
513 trb->Base._BaseFormat = _mesa_base_fbo_format(ctx, trb->Base.InternalFormat);
514 }
515
516
517
518 /**
519 * Called when rendering to a texture image begins, or when changing
520 * the dest mipmap level, cube face, etc.
521 * This is a fallback routine for software render-to-texture.
522 *
523 * Called via the glRenderbufferTexture1D/2D/3D() functions
524 * and elsewhere (such as glTexImage2D).
525 *
526 * The image we're rendering into is
527 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
528 * It'll never be NULL.
529 *
530 * \param fb the framebuffer object the texture is being bound to
531 * \param att the fb attachment point of the texture
532 *
533 * \sa _mesa_framebuffer_renderbuffer
534 */
535 void
536 _mesa_render_texture(GLcontext *ctx,
537 struct gl_framebuffer *fb,
538 struct gl_renderbuffer_attachment *att)
539 {
540 (void) fb;
541
542 if (!att->Renderbuffer) {
543 wrap_texture(ctx, att);
544 }
545 update_wrapper(ctx, att);
546 }
547
548
549 void
550 _mesa_finish_render_texture(GLcontext *ctx,
551 struct gl_renderbuffer_attachment *att)
552 {
553 /* do nothing */
554 /* The renderbuffer texture wrapper will get deleted by the
555 * normal mechanism for deleting renderbuffers.
556 */
557 (void) ctx;
558 (void) att;
559 }