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