New code for rendering to depth/stencil textures.
[mesa.git] / src / mesa / main / texrender.c
1
2 #include "context.h"
3 #include "fbobject.h"
4 #include "texrender.h"
5 #include "renderbuffer.h"
6
7
8 /*
9 * Render-to-texture code for GL_EXT_framebuffer_object
10 */
11
12
13 /**
14 * Derived from gl_renderbuffer class
15 */
16 struct texture_renderbuffer
17 {
18 struct gl_renderbuffer Base; /* Base class object */
19 struct gl_texture_image *TexImage;
20 StoreTexelFunc Store;
21 GLint Zoffset;
22 };
23
24
25 /**
26 * Get row of values from the renderbuffer that wraps a texture image.
27 */
28 static void
29 texture_get_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
30 GLint x, GLint y, void *values)
31 {
32 const struct texture_renderbuffer *trb
33 = (const struct texture_renderbuffer *) rb;
34 const GLint z = trb->Zoffset;
35 GLuint i;
36
37 ASSERT(trb->TexImage->Width == rb->Width);
38 ASSERT(trb->TexImage->Height == rb->Height);
39
40 if (rb->DataType == CHAN_TYPE) {
41 GLchan *rgbaOut = (GLchan *) values;
42 for (i = 0; i < count; i++) {
43 trb->TexImage->FetchTexelc(trb->TexImage, x + i, y, z, rgbaOut + 4 * i);
44 }
45 }
46 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
47 GLuint *zValues = (GLuint *) values;
48 for (i = 0; i < count; i++) {
49 GLfloat flt;
50 trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
51 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
52 }
53 }
54 else {
55 _mesa_problem(ctx, "invalid rb->DataType in texture_get_row");
56 }
57 }
58
59
60 static void
61 texture_get_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
62 const GLint x[], const GLint y[], void *values)
63 {
64 const struct texture_renderbuffer *trb
65 = (const struct texture_renderbuffer *) rb;
66 const GLint z = trb->Zoffset;
67 GLuint i;
68
69 if (rb->DataType == CHAN_TYPE) {
70 GLchan *rgbaOut = (GLchan *) values;
71 for (i = 0; i < count; i++) {
72 trb->TexImage->FetchTexelc(trb->TexImage, x[i], y[i], z,
73 rgbaOut + 4 * i);
74 }
75 }
76 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
77 GLuint *zValues = (GLuint *) values;
78 for (i = 0; i < count; i++) {
79 GLfloat flt;
80 trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i], z, &flt);
81 zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
82 }
83 }
84 else {
85 _mesa_problem(ctx, "invalid rb->DataType in texture_get_values");
86 }
87 }
88
89
90 /**
91 * Put row of values into a renderbuffer that wraps a texture image.
92 */
93 static void
94 texture_put_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
95 GLint x, GLint y, const void *values, const GLubyte *mask)
96 {
97 const struct texture_renderbuffer *trb
98 = (const struct texture_renderbuffer *) rb;
99 const GLint z = trb->Zoffset;
100 GLuint i;
101
102 if (rb->DataType == CHAN_TYPE) {
103 const GLchan *rgba = (const GLchan *) values;
104 for (i = 0; i < count; i++) {
105 if (!mask || mask[i]) {
106 trb->Store(trb->TexImage, x + i, y, z, rgba);
107 }
108 rgba += 4;
109 }
110 }
111 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
112 const GLuint *zValues = (const GLuint *) values;
113 for (i = 0; i < count; i++) {
114 if (!mask || mask[i]) {
115 GLfloat flt = (zValues[i] >> 8) * (1.0 / 0xffffff);
116 trb->Store(trb->TexImage, x + i, y, z, &flt);
117 }
118 }
119 }
120 else {
121 _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
122 }
123 }
124
125
126 static void
127 texture_put_mono_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
128 GLint x, GLint y, const void *value, const GLubyte *mask)
129 {
130 const struct texture_renderbuffer *trb
131 = (const struct texture_renderbuffer *) rb;
132 const GLint z = trb->Zoffset;
133 GLuint i;
134
135 if (rb->DataType == CHAN_TYPE) {
136 const GLchan *rgba = (const GLchan *) value;
137 for (i = 0; i < count; i++) {
138 if (!mask || mask[i]) {
139 trb->Store(trb->TexImage, x + i, y, z, rgba);
140 }
141 }
142 }
143 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
144 const GLuint zValue = *((const GLuint *) value);
145 const GLfloat flt = (zValue >> 8) * (1.0 / 0xffffff);
146 for (i = 0; i < count; i++) {
147 if (!mask || mask[i]) {
148 trb->Store(trb->TexImage, x + i, y, z, &flt);
149 }
150 }
151 }
152 else {
153 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_row");
154 }
155 }
156
157
158 static void
159 texture_put_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
160 const GLint x[], const GLint y[], const void *values,
161 const GLubyte *mask)
162 {
163 const struct texture_renderbuffer *trb
164 = (const struct texture_renderbuffer *) rb;
165 const GLint z = trb->Zoffset;
166 GLuint i;
167
168 if (rb->DataType == CHAN_TYPE) {
169 const GLchan *rgba = (const GLchan *) values;
170 for (i = 0; i < count; i++) {
171 if (!mask || mask[i]) {
172 trb->Store(trb->TexImage, x[i], y[i], z, rgba);
173 }
174 rgba += 4;
175 }
176 }
177 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
178 const GLuint *zValues = (const GLuint *) values;
179 for (i = 0; i < count; i++) {
180 if (!mask || mask[i]) {
181 GLfloat flt = (zValues[i] >> 8) * (1.0 / 0xffffff);
182 trb->Store(trb->TexImage, x[i], y[i], z, &flt);
183 }
184 }
185 }
186 else {
187 _mesa_problem(ctx, "invalid rb->DataType in texture_put_values");
188 }
189 }
190
191
192 static void
193 texture_put_mono_values(GLcontext *ctx, struct gl_renderbuffer *rb,
194 GLuint count, const GLint x[], const GLint y[],
195 const void *value, const GLubyte *mask)
196 {
197 const struct texture_renderbuffer *trb
198 = (const struct texture_renderbuffer *) rb;
199 const GLint z = trb->Zoffset;
200 GLuint i;
201
202 if (rb->DataType == CHAN_TYPE) {
203 const GLchan *rgba = (const GLchan *) value;
204 for (i = 0; i < count; i++) {
205 if (!mask || mask[i]) {
206 trb->Store(trb->TexImage, x[i], y[i], z, rgba);
207 }
208 }
209 }
210 else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
211 const GLuint zValue = *((const GLuint *) value);
212 const GLfloat flt = (zValue >> 8) * (1.0 / 0xffffff);
213 for (i = 0; i < count; i++) {
214 if (!mask || mask[i]) {
215 trb->Store(trb->TexImage, x[i], y[i], z, &flt);
216 }
217 }
218 }
219 else {
220 _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_values");
221 }
222 }
223
224
225 static void
226 delete_texture_wrapper(struct gl_renderbuffer *rb)
227 {
228 ASSERT(rb->RefCount == 0);
229 _mesa_free(rb);
230 }
231
232
233 /**
234 * This function creates a renderbuffer object which wraps a texture image.
235 * The new renderbuffer is plugged into the given attachment point.
236 * This allows rendering into the texture as if it were a renderbuffer.
237 */
238 static void
239 wrap_texture(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
240 {
241 struct texture_renderbuffer *trb;
242 const GLuint name = 0;
243
244 ASSERT(att->Type == GL_TEXTURE);
245 ASSERT(att->Renderbuffer == NULL);
246
247 trb = CALLOC_STRUCT(texture_renderbuffer);
248 if (!trb) {
249 _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture");
250 return;
251 }
252
253 /* init base gl_renderbuffer fields */
254 _mesa_init_renderbuffer(&trb->Base, name);
255 /* plug in our texture_renderbuffer-specific functions */
256 trb->Base.Delete = delete_texture_wrapper;
257 trb->Base.AllocStorage = NULL; /* illegal! */
258 trb->Base.GetRow = texture_get_row;
259 trb->Base.GetValues = texture_get_values;
260 trb->Base.PutRow = texture_put_row;
261 trb->Base.PutMonoRow = texture_put_mono_row;
262 trb->Base.PutValues = texture_put_values;
263 trb->Base.PutMonoValues = texture_put_mono_values;
264
265 /* update attachment point */
266 att->Renderbuffer = &(trb->Base);
267 }
268
269
270
271 /**
272 * Update the renderbuffer wrapper for rendering to a texture.
273 * For example, update the width, height of the RB based on the texture size,
274 * update the internal format info, etc.
275 */
276 static void
277 update_wrapper(GLcontext *ctx, const struct gl_renderbuffer_attachment *att)
278 {
279 struct texture_renderbuffer *trb
280 = (struct texture_renderbuffer *) att->Renderbuffer;
281
282 ASSERT(trb);
283
284 trb->TexImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
285 ASSERT(trb->TexImage);
286
287 trb->Store = trb->TexImage->TexFormat->StoreTexel;
288 ASSERT(trb->Store);
289
290 trb->Zoffset = att->Zoffset;
291
292 trb->Base.Width = trb->TexImage->Width;
293 trb->Base.Height = trb->TexImage->Height;
294 trb->Base.InternalFormat = trb->TexImage->InternalFormat;
295 /* XXX may need more special cases here */
296 if (trb->TexImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) {
297 trb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
298 trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
299 }
300 else if (trb->TexImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) {
301 trb->Base._ActualFormat = GL_DEPTH_COMPONENT;
302 trb->Base.DataType = GL_FLOAT;
303 }
304 else {
305 trb->Base._ActualFormat = trb->TexImage->InternalFormat;
306 trb->Base.DataType = CHAN_TYPE;
307 }
308 trb->Base._BaseFormat = trb->TexImage->TexFormat->BaseFormat;
309 #if 0
310 /* fix/avoid this assertion someday */
311 ASSERT(trb->Base._BaseFormat == GL_RGB ||
312 trb->Base._BaseFormat == GL_RGBA ||
313 trb->Base._BaseFormat == GL_DEPTH_COMPONENT);
314 #endif
315 trb->Base.Data = trb->TexImage->Data;
316
317 trb->Base.RedBits = trb->TexImage->TexFormat->RedBits;
318 trb->Base.GreenBits = trb->TexImage->TexFormat->GreenBits;
319 trb->Base.BlueBits = trb->TexImage->TexFormat->BlueBits;
320 trb->Base.AlphaBits = trb->TexImage->TexFormat->AlphaBits;
321 trb->Base.DepthBits = trb->TexImage->TexFormat->DepthBits;
322 }
323
324
325
326 /**
327 * Called when rendering to a texture image begins, or when changing
328 * the dest mipmap level, cube face, etc.
329 * This is a fallback routine for software render-to-texture.
330 *
331 * Called via the glRenderbufferTexture1D/2D/3D() functions
332 * and elsewhere (such as glTexImage2D).
333 *
334 * The image we're rendering into is
335 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
336 * It'll never be NULL.
337 *
338 * \param fb the framebuffer object the texture is being bound to
339 * \param att the fb attachment point of the texture
340 *
341 * \sa _mesa_framebuffer_renderbuffer
342 */
343 void
344 _mesa_render_texture(GLcontext *ctx,
345 struct gl_framebuffer *fb,
346 struct gl_renderbuffer_attachment *att)
347 {
348 if (!att->Renderbuffer) {
349 wrap_texture(ctx, att);
350 }
351 update_wrapper(ctx, att);
352 }
353
354
355 void
356 _mesa_finish_render_texture(GLcontext *ctx,
357 struct gl_renderbuffer_attachment *att)
358 {
359 /* do nothing */
360 /* The renderbuffer texture wrapper will get deleted by the
361 * normal mechanism for deleting renderbuffers.
362 */
363 }