merge from texman branch
[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 static void
27 texture_get_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
28 GLint x, GLint y, void *values)
29 {
30 const struct texture_renderbuffer *trb
31 = (const struct texture_renderbuffer *) rb;
32 const GLint z = trb->Zoffset;
33 GLchan *rgbaOut = (GLchan *) values;
34 GLuint i;
35 for (i = 0; i < count; i++) {
36 trb->TexImage->FetchTexelc(trb->TexImage, x + i, y, z, rgbaOut + 4 * i);
37 }
38 }
39
40 static void
41 texture_get_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
42 const GLint x[], const GLint y[], void *values)
43 {
44 const struct texture_renderbuffer *trb
45 = (const struct texture_renderbuffer *) rb;
46 const GLint z = trb->Zoffset;
47 GLchan *rgbaOut = (GLchan *) values;
48 GLuint i;
49 for (i = 0; i < count; i++) {
50 trb->TexImage->FetchTexelc(trb->TexImage, x[i], y[i], z,
51 rgbaOut + 4 * i);
52 }
53 }
54
55 static void
56 texture_put_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
57 GLint x, GLint y, const void *values, const GLubyte *mask)
58 {
59 const struct texture_renderbuffer *trb
60 = (const struct texture_renderbuffer *) rb;
61 const GLint z = trb->Zoffset;
62 const GLchan *rgba = (const GLchan *) values;
63 GLuint i;
64 for (i = 0; i < count; i++) {
65 if (!mask || mask[i]) {
66 trb->Store(trb->TexImage, x + i, y, z, rgba);
67 }
68 rgba += 4;
69 }
70 }
71
72 static void
73 texture_put_mono_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
74 GLint x, GLint y, const void *value, const GLubyte *mask)
75 {
76 const struct texture_renderbuffer *trb
77 = (const struct texture_renderbuffer *) rb;
78 const GLint z = trb->Zoffset;
79 const GLchan *rgba = (const GLchan *) value;
80 GLuint i;
81 for (i = 0; i < count; i++) {
82 if (!mask || mask[i]) {
83 trb->Store(trb->TexImage, x + i, y, z, rgba);
84 }
85 }
86 }
87
88 static void
89 texture_put_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
90 const GLint x[], const GLint y[], const void *values,
91 const GLubyte *mask)
92 {
93 const struct texture_renderbuffer *trb
94 = (const struct texture_renderbuffer *) rb;
95 const GLint z = trb->Zoffset;
96 const GLchan *rgba = (const GLchan *) values;
97 GLuint i;
98 for (i = 0; i < count; i++) {
99 if (!mask || mask[i]) {
100 trb->Store(trb->TexImage, x[i], y[i], z, rgba);
101 }
102 rgba += 4;
103 }
104 }
105
106 static void
107 texture_put_mono_values(GLcontext *ctx, struct gl_renderbuffer *rb,
108 GLuint count, const GLint x[], const GLint y[],
109 const void *value, const GLubyte *mask)
110 {
111 const struct texture_renderbuffer *trb
112 = (const struct texture_renderbuffer *) rb;
113 const GLint z = trb->Zoffset;
114 const GLchan *rgba = (const GLchan *) value;
115 GLuint i;
116 for (i = 0; i < count; i++) {
117 if (!mask || mask[i]) {
118 trb->Store(trb->TexImage, x[i], y[i], z, rgba);
119 }
120 }
121 }
122
123
124 static void
125 delete_texture_wrapper(struct gl_renderbuffer *rb)
126 {
127 ASSERT(rb->RefCount == 0);
128 _mesa_free(rb);
129 }
130
131
132 /**
133 * If a render buffer attachment specifies a texture image, we'll use
134 * this function to make a gl_renderbuffer wrapper around the texture image.
135 * This allows other parts of Mesa to access the texture image as if it
136 * was a renderbuffer.
137 */
138 static void
139 wrap_texture(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
140 {
141 struct texture_renderbuffer *trb;
142 const GLuint name = 0;
143
144 ASSERT(att->Type == GL_TEXTURE);
145 ASSERT(att->Renderbuffer == NULL);
146 /*
147 ASSERT(att->Complete);
148 */
149
150 trb = CALLOC_STRUCT(texture_renderbuffer);
151 if (!trb) {
152 _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture");
153 return;
154 }
155
156 _mesa_init_renderbuffer(&trb->Base, name);
157
158 trb->TexImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
159 assert(trb->TexImage);
160
161 trb->Store = trb->TexImage->TexFormat->StoreTexel;
162 assert(trb->Store);
163
164 trb->Zoffset = att->Zoffset;
165
166 trb->Base.Width = trb->TexImage->Width;
167 trb->Base.Height = trb->TexImage->Height;
168 trb->Base.InternalFormat = trb->TexImage->InternalFormat; /* XXX fix? */
169 trb->Base._BaseFormat = trb->TexImage->TexFormat->BaseFormat;
170 #if 0
171 /* fix/avoid this assertion someday */
172 assert(trb->Base._BaseFormat == GL_RGB ||
173 trb->Base._BaseFormat == GL_RGBA ||
174 trb->Base._BaseFormat == GL_DEPTH_COMPONENT);
175 #endif
176 trb->Base.DataType = GL_UNSIGNED_BYTE; /* XXX fix! */
177 trb->Base.Data = trb->TexImage->Data;
178
179 trb->Base.GetRow = texture_get_row;
180 trb->Base.GetValues = texture_get_values;
181 trb->Base.PutRow = texture_put_row;
182 trb->Base.PutMonoRow = texture_put_mono_row;
183 trb->Base.PutValues = texture_put_values;
184 trb->Base.PutMonoValues = texture_put_mono_values;
185
186 trb->Base.Delete = delete_texture_wrapper;
187 trb->Base.AllocStorage = NULL; /* illegal! */
188
189 /* XXX fix these */
190 trb->Base.RedBits = trb->TexImage->TexFormat->RedBits;
191 trb->Base.GreenBits = trb->TexImage->TexFormat->GreenBits;
192 trb->Base.BlueBits = trb->TexImage->TexFormat->BlueBits;
193 trb->Base.AlphaBits = trb->TexImage->TexFormat->AlphaBits;
194 trb->Base.DepthBits = trb->TexImage->TexFormat->DepthBits;
195
196 att->Renderbuffer = &(trb->Base);
197 trb->Base.RefCount++;
198 }
199
200
201
202 /**
203 * Called when rendering to a texture image begins, or when changing
204 * the dest mipmap level, cube face, etc.
205 * This is a fallback routine for software render-to-texture.
206 *
207 * Called via the glRenderbufferTexture1D/2D/3D() functions
208 * and elsewhere (such as glTexImage2D).
209 *
210 * The image we're rendering into is
211 * att->Texture->Image[att->CubeMapFace][att->TextureLevel];
212 * It'll never be NULL.
213 *
214 * \param fb the framebuffer object the texture is being bound to
215 * \param att the fb attachment point of the texture
216 *
217 * \sa _mesa_framebuffer_renderbuffer
218 */
219 void
220 _mesa_render_texture(GLcontext *ctx,
221 struct gl_framebuffer *fb,
222 struct gl_renderbuffer_attachment *att)
223 {
224 struct gl_texture_image *newImage
225 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
226 struct texture_renderbuffer *trb
227 = (struct texture_renderbuffer *) att->Renderbuffer;
228 struct gl_texture_image *oldImage = trb ? trb->TexImage : NULL;
229
230 (void) fb;
231
232 ASSERT(newImage);
233
234 if (oldImage != newImage) {
235 if (trb) {
236 /* get rid of old wrapper */
237 /* XXX also if Zoffset changes? */
238 trb->Base.Delete(&trb->Base);
239 }
240 wrap_texture(ctx, att);
241 }
242 }
243
244
245 void
246 _mesa_finish_render_texture(GLcontext *ctx,
247 struct gl_renderbuffer_attachment *att)
248 {
249 /* do nothing */
250 /* The renderbuffer texture wrapper will get deleted by the
251 * normal mechanism for deleting renderbuffers.
252 */
253 }