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