mesa: add missing texture_put_row_rgb() function in texrender.c
[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 * Put row of RGB values into a renderbuffer that wraps a texture image.
199 */
200 static void
201 texture_put_row_rgb(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
202 GLint x, GLint y, const void *values, const GLubyte *mask)
203 {
204 const struct texture_renderbuffer *trb
205 = (const struct texture_renderbuffer *) rb;
206 const GLint z = trb->Zoffset;
207 GLuint i;
208
209 y += trb->Yoffset;
210
211 if (rb->DataType == CHAN_TYPE) {
212 const GLchan *rgb = (const GLchan *) values;
213 for (i = 0; i < count; i++) {
214 if (!mask || mask[i]) {
215 trb->Store(trb->TexImage, x + i, y, z, rgb);
216 }
217 rgb += 3;
218 }
219 }
220 else if (rb->DataType == GL_UNSIGNED_SHORT) {
221 const GLushort *zValues = (const GLushort *) values;
222 for (i = 0; i < count; i++) {
223 if (!mask || mask[i]) {
224 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
225 }
226 }
227 }
228 else if (rb->DataType == GL_UNSIGNED_INT) {
229 const GLuint *zValues = (const GLuint *) values;
230 for (i = 0; i < count; i++) {
231 if (!mask || mask[i]) {
232 trb->Store(trb->TexImage, x + i, y, z, zValues + i);
233 }
234 }
235 }
236 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
237 const GLuint *zValues = (const GLuint *) values;
238 for (i = 0; i < count; i++) {
239 if (!mask || mask[i]) {
240 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
241 trb->Store(trb->TexImage, x + i, y, z, &flt);
242 }
243 }
244 }
245 else {
246 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
247 }
248 }
249
250
251 static void
252 texture_put_mono_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
253 GLint x, GLint y, const void *value, const GLubyte *mask)
254 {
255 const struct texture_renderbuffer *trb
256 = (const struct texture_renderbuffer *) rb;
257 const GLint z = trb->Zoffset;
258 GLuint i;
259
260 y += trb->Yoffset;
261
262 if (rb->DataType == CHAN_TYPE) {
263 const GLchan *rgba = (const GLchan *) value;
264 for (i = 0; i < count; i++) {
265 if (!mask || mask[i]) {
266 trb->Store(trb->TexImage, x + i, y, z, rgba);
267 }
268 }
269 }
270 else if (rb->DataType == GL_UNSIGNED_SHORT) {
271 const GLushort zValue = *((const GLushort *) value);
272 for (i = 0; i < count; i++) {
273 if (!mask || mask[i]) {
274 trb->Store(trb->TexImage, x + i, y, z, &zValue);
275 }
276 }
277 }
278 else if (rb->DataType == GL_UNSIGNED_INT) {
279 const GLuint zValue = *((const GLuint *) value);
280 for (i = 0; i < count; i++) {
281 if (!mask || mask[i]) {
282 trb->Store(trb->TexImage, x + i, y, z, &zValue);
283 }
284 }
285 }
286 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
287 const GLuint zValue = *((const GLuint *) value);
288 const GLfloat flt = (GLfloat) ((zValue >> 8) * (1.0 / 0xffffff));
289 for (i = 0; i < count; i++) {
290 if (!mask || mask[i]) {
291 trb->Store(trb->TexImage, x + i, y, z, &flt);
292 }
293 }
294 }
295 else {
296 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_row");
297 }
298 }
299
300
301 static void
302 texture_put_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
303 const GLint x[], const GLint y[], const void *values,
304 const GLubyte *mask)
305 {
306 const struct texture_renderbuffer *trb
307 = (const struct texture_renderbuffer *) rb;
308 const GLint z = trb->Zoffset;
309 GLuint i;
310
311 if (rb->DataType == CHAN_TYPE) {
312 const GLchan *rgba = (const GLchan *) values;
313 for (i = 0; i < count; i++) {
314 if (!mask || mask[i]) {
315 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
316 }
317 rgba += 4;
318 }
319 }
320 else if (rb->DataType == GL_UNSIGNED_SHORT) {
321 const GLushort *zValues = (const GLushort *) values;
322 for (i = 0; i < count; i++) {
323 if (!mask || mask[i]) {
324 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, zValues + i);
325 }
326 }
327 }
328 else if (rb->DataType == GL_UNSIGNED_INT) {
329 const GLuint *zValues = (const GLuint *) values;
330 for (i = 0; i < count; i++) {
331 if (!mask || mask[i]) {
332 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, zValues + i);
333 }
334 }
335 }
336 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
337 const GLuint *zValues = (const GLuint *) values;
338 for (i = 0; i < count; i++) {
339 if (!mask || mask[i]) {
340 GLfloat flt = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
341 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
342 }
343 }
344 }
345 else {
346 _mesa_problem(ctx, "invalid rb->DataType in texture_put_values");
347 }
348 }
349
350
351 static void
352 texture_put_mono_values(GLcontext *ctx, struct gl_renderbuffer *rb,
353 GLuint count, const GLint x[], const GLint y[],
354 const void *value, const GLubyte *mask)
355 {
356 const struct texture_renderbuffer *trb
357 = (const struct texture_renderbuffer *) rb;
358 const GLint z = trb->Zoffset;
359 GLuint i;
360
361 if (rb->DataType == CHAN_TYPE) {
362 const GLchan *rgba = (const GLchan *) value;
363 for (i = 0; i < count; i++) {
364 if (!mask || mask[i]) {
365 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
366 }
367 }
368 }
369 else if (rb->DataType == GL_UNSIGNED_INT) {
370 const GLuint zValue = *((const GLuint *) value);
371 for (i = 0; i < count; i++) {
372 if (!mask || mask[i]) {
373 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
374 }
375 }
376 }
377 else if (rb->DataType == GL_UNSIGNED_SHORT) {
378 const GLushort zValue = *((const GLushort *) value);
379 for (i = 0; i < count; i++) {
380 if (!mask || mask[i]) {
381 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
382 }
383 }
384 }
385 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
386 const GLuint zValue = *((const GLuint *) value);
387 const GLfloat flt = (GLfloat) ((zValue >> 8) * (1.0 / 0xffffff));
388 for (i = 0; i < count; i++) {
389 if (!mask || mask[i]) {
390 trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
391 }
392 }
393 }
394 else {
395 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_values");
396 }
397 }
398
399
400 static void
401 delete_texture_wrapper(struct gl_renderbuffer *rb)
402 {
403 ASSERT(rb->RefCount == 0);
404 _mesa_free(rb);
405 }
406
407
408 /**
409 * This function creates a renderbuffer object which wraps a texture image.
410 * The new renderbuffer is plugged into the given attachment point.
411 * This allows rendering into the texture as if it were a renderbuffer.
412 */
413 static void
414 wrap_texture(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
415 {
416 struct texture_renderbuffer *trb;
417 const GLuint name = 0;
418
419 ASSERT(att->Type == GL_TEXTURE);
420 ASSERT(att->Renderbuffer == NULL);
421
422 trb = CALLOC_STRUCT(texture_renderbuffer);
423 if (!trb) {
424 _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture");
425 return;
426 }
427
428 /* init base gl_renderbuffer fields */
429 _mesa_init_renderbuffer(&trb->Base, name);
430 /* plug in our texture_renderbuffer-specific functions */
431 trb->Base.Delete = delete_texture_wrapper;
432 trb->Base.AllocStorage = NULL; /* illegal! */
433 trb->Base.GetRow = texture_get_row;
434 trb->Base.GetValues = texture_get_values;
435 trb->Base.PutRow = texture_put_row;
436 trb->Base.PutRowRGB = texture_put_row_rgb;
437 trb->Base.PutMonoRow = texture_put_mono_row;
438 trb->Base.PutValues = texture_put_values;
439 trb->Base.PutMonoValues = texture_put_mono_values;
440
441 /* update attachment point */
442 _mesa_reference_renderbuffer(&att->Renderbuffer, &(trb->Base));
443 }
444
445
446
447 /**
448 * Update the renderbuffer wrapper for rendering to a texture.
449 * For example, update the width, height of the RB based on the texture size,
450 * update the internal format info, etc.
451 */
452 static void
453 update_wrapper(GLcontext *ctx, const struct gl_renderbuffer_attachment *att)
454 {
455 struct texture_renderbuffer *trb
456 = (struct texture_renderbuffer *) att->Renderbuffer;
457
458 (void) ctx;
459 ASSERT(trb);
460
461 trb->TexImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
462 ASSERT(trb->TexImage);
463
464 trb->Store = trb->TexImage->TexFormat->StoreTexel;
465 ASSERT(trb->Store);
466
467 if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
468 trb->Yoffset = att->Zoffset;
469 trb->Zoffset = 0;
470 }
471 else {
472 trb->Yoffset = 0;
473 trb->Zoffset = att->Zoffset;
474 }
475
476 trb->Base.Width = trb->TexImage->Width;
477 trb->Base.Height = trb->TexImage->Height;
478 trb->Base.InternalFormat = trb->TexImage->InternalFormat;
479 /* XXX may need more special cases here */
480 if (trb->TexImage->TexFormat->MesaFormat == MESA_FORMAT_Z24_S8) {
481 trb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
482 trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
483 }
484 else if (trb->TexImage->TexFormat->MesaFormat == MESA_FORMAT_Z16) {
485 trb->Base._ActualFormat = GL_DEPTH_COMPONENT;
486 trb->Base.DataType = GL_UNSIGNED_SHORT;
487 }
488 else if (trb->TexImage->TexFormat->MesaFormat == MESA_FORMAT_Z32) {
489 trb->Base._ActualFormat = GL_DEPTH_COMPONENT;
490 trb->Base.DataType = GL_UNSIGNED_INT;
491 }
492 else {
493 trb->Base._ActualFormat = trb->TexImage->InternalFormat;
494 trb->Base.DataType = CHAN_TYPE;
495 }
496 trb->Base._BaseFormat = trb->TexImage->TexFormat->BaseFormat;
497 #if 0
498 /* fix/avoid this assertion someday */
499 ASSERT(trb->Base._BaseFormat == GL_RGB ||
500 trb->Base._BaseFormat == GL_RGBA ||
501 trb->Base._BaseFormat == GL_DEPTH_COMPONENT);
502 #endif
503 trb->Base.Data = trb->TexImage->Data;
504
505 trb->Base.RedBits = trb->TexImage->TexFormat->RedBits;
506 trb->Base.GreenBits = trb->TexImage->TexFormat->GreenBits;
507 trb->Base.BlueBits = trb->TexImage->TexFormat->BlueBits;
508 trb->Base.AlphaBits = trb->TexImage->TexFormat->AlphaBits;
509 trb->Base.DepthBits = trb->TexImage->TexFormat->DepthBits;
510 }
511
512
513
514 /**
515 * Called when rendering to a texture image begins, or when changing
516 * the dest mipmap level, cube face, etc.
517 * This is a fallback routine for software render-to-texture.
518 *
519 * Called via the glRenderbufferTexture1D/2D/3D() functions
520 * and elsewhere (such as glTexImage2D).
521 *
522 * The image we're rendering into is
523 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
524 * It'll never be NULL.
525 *
526 * \param fb the framebuffer object the texture is being bound to
527 * \param att the fb attachment point of the texture
528 *
529 * \sa _mesa_framebuffer_renderbuffer
530 */
531 void
532 _mesa_render_texture(GLcontext *ctx,
533 struct gl_framebuffer *fb,
534 struct gl_renderbuffer_attachment *att)
535 {
536 (void) fb;
537
538 if (!att->Renderbuffer) {
539 wrap_texture(ctx, att);
540 }
541 update_wrapper(ctx, att);
542 }
543
544
545 void
546 _mesa_finish_render_texture(GLcontext *ctx,
547 struct gl_renderbuffer_attachment *att)
548 {
549 /* do nothing */
550 /* The renderbuffer texture wrapper will get deleted by the
551 * normal mechanism for deleting renderbuffers.
552 */
553 (void) ctx;
554 (void) att;
555 }