e95240f2293fe5e94e3d4e988fb2038211aeca55
[profile/ivi/mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_fbo.c
1 /*
2  * Copyright (C) 2009 Francisco Jerez.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26
27 #include "nouveau_driver.h"
28 #include "nouveau_fbo.h"
29 #include "nouveau_context.h"
30 #include "nouveau_texture.h"
31
32 #include "main/framebuffer.h"
33 #include "main/renderbuffer.h"
34 #include "main/fbobject.h"
35 #include "main/mfeatures.h"
36
37 static GLboolean
38 set_renderbuffer_format(struct gl_renderbuffer *rb, GLenum internalFormat)
39 {
40         struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
41
42         rb->InternalFormat  = internalFormat;
43
44         switch (internalFormat) {
45         case GL_RGB:
46         case GL_RGB8:
47                 rb->_BaseFormat  = GL_RGB;
48                 rb->Format = MESA_FORMAT_XRGB8888;
49                 s->cpp = 4;
50                 break;
51         case GL_RGBA:
52         case GL_RGBA8:
53                 rb->_BaseFormat  = GL_RGBA;
54                 rb->Format = MESA_FORMAT_ARGB8888;
55                 s->cpp = 4;
56                 break;
57         case GL_RGB5:
58                 rb->_BaseFormat  = GL_RGB;
59                 rb->Format = MESA_FORMAT_RGB565;
60                 s->cpp = 2;
61                 break;
62         case GL_DEPTH_COMPONENT16:
63                 rb->_BaseFormat  = GL_DEPTH_COMPONENT;
64                 rb->Format = MESA_FORMAT_Z16;
65                 s->cpp = 2;
66                 break;
67         case GL_DEPTH_COMPONENT:
68         case GL_DEPTH_COMPONENT24:
69         case GL_STENCIL_INDEX8_EXT:
70         case GL_DEPTH24_STENCIL8_EXT:
71                 rb->_BaseFormat  = GL_DEPTH_STENCIL;
72                 rb->Format = MESA_FORMAT_Z24_S8;
73                 s->cpp = 4;
74                 break;
75         default:
76                 return GL_FALSE;
77         }
78
79         s->format = rb->Format;
80
81         return GL_TRUE;
82 }
83
84 static GLboolean
85 nouveau_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
86                              GLenum internalFormat,
87                              GLuint width, GLuint height)
88 {
89         struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
90
91         if (!set_renderbuffer_format(rb, internalFormat))
92                 return GL_FALSE;
93
94         rb->Width = width;
95         rb->Height = height;
96
97         nouveau_surface_alloc(ctx, s, TILED, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP,
98                               rb->Format, width, height);
99
100         context_dirty(ctx, FRAMEBUFFER);
101         return GL_TRUE;
102 }
103
104 static void
105 nouveau_renderbuffer_del(struct gl_context *ctx, struct gl_renderbuffer *rb)
106 {
107         struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
108
109         nouveau_surface_ref(NULL, s);
110         _mesa_delete_renderbuffer(ctx, rb);
111 }
112
113 static struct gl_renderbuffer *
114 nouveau_renderbuffer_new(struct gl_context *ctx, GLuint name)
115 {
116         struct gl_renderbuffer *rb;
117
118         rb = (struct gl_renderbuffer *)
119                 CALLOC_STRUCT(nouveau_renderbuffer);
120         if (!rb)
121                 return NULL;
122
123         _mesa_init_renderbuffer(rb, name);
124
125         rb->AllocStorage = nouveau_renderbuffer_storage;
126         rb->Delete = nouveau_renderbuffer_del;
127
128         return rb;
129 }
130
131 static void
132 nouveau_renderbuffer_map(struct gl_context *ctx,
133                          struct gl_renderbuffer *rb,
134                          GLuint x, GLuint y, GLuint w, GLuint h,
135                          GLbitfield mode,
136                          GLubyte **out_map,
137                          GLint *out_stride)
138 {
139         struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
140         GLubyte *map;
141         int stride;
142         int flags = 0;
143
144         if (mode & GL_MAP_READ_BIT)
145                 flags |= NOUVEAU_BO_RD;
146         if (mode & GL_MAP_WRITE_BIT)
147                 flags |= NOUVEAU_BO_WR;
148
149         nouveau_bo_map(s->bo, flags, context_client(ctx));
150
151         map = s->bo->map;
152         stride = s->pitch;
153
154         if (rb->Name == 0) {
155                 map += stride * (rb->Height - 1);
156                 stride = -stride;
157         }
158
159         map += x * s->cpp;
160         map += (int)y * stride;
161
162         *out_map = map;
163         *out_stride = stride;
164 }
165
166 static void
167 nouveau_renderbuffer_unmap(struct gl_context *ctx,
168                            struct gl_renderbuffer *rb)
169 {
170 }
171
172 static GLboolean
173 nouveau_renderbuffer_dri_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
174                                  GLenum internalFormat,
175                                  GLuint width, GLuint height)
176 {
177         if (!set_renderbuffer_format(rb, internalFormat))
178                 return GL_FALSE;
179
180         rb->Width = width;
181         rb->Height = height;
182
183         return GL_TRUE;
184 }
185
186 struct gl_renderbuffer *
187 nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable)
188 {
189         struct gl_renderbuffer *rb;
190
191         rb = nouveau_renderbuffer_new(NULL, 0);
192         if (!rb)
193                 return NULL;
194
195         rb->AllocStorage = nouveau_renderbuffer_dri_storage;
196
197         if (!set_renderbuffer_format(rb, format)) {
198                 nouveau_renderbuffer_del(rb);
199                 return NULL;
200         }
201
202         return rb;
203 }
204
205 static struct gl_framebuffer *
206 nouveau_framebuffer_new(struct gl_context *ctx, GLuint name)
207 {
208         struct nouveau_framebuffer *nfb;
209
210         nfb = CALLOC_STRUCT(nouveau_framebuffer);
211         if (!nfb)
212                 return NULL;
213
214         _mesa_initialize_user_framebuffer(&nfb->base, name);
215
216         return &nfb->base;
217 }
218
219 struct gl_framebuffer *
220 nouveau_framebuffer_dri_new(const struct gl_config *visual)
221 {
222         struct nouveau_framebuffer *nfb;
223
224         nfb = CALLOC_STRUCT(nouveau_framebuffer);
225         if (!nfb)
226                 return NULL;
227
228         _mesa_initialize_window_framebuffer(&nfb->base, visual);
229         nfb->need_front = !visual->doubleBufferMode;
230
231         return &nfb->base;
232 }
233
234 static void
235 nouveau_bind_framebuffer(struct gl_context *ctx, GLenum target,
236                          struct gl_framebuffer *dfb,
237                          struct gl_framebuffer *rfb)
238 {
239         context_dirty(ctx, FRAMEBUFFER);
240 }
241
242 static void
243 nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
244                                  GLenum attachment, struct gl_renderbuffer *rb)
245 {
246         _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
247
248         context_dirty(ctx, FRAMEBUFFER);
249 }
250
251 static GLenum
252 get_tex_format(struct gl_texture_image *ti)
253 {
254         switch (ti->TexFormat) {
255         case MESA_FORMAT_ARGB8888:
256                 return GL_RGBA8;
257         case MESA_FORMAT_XRGB8888:
258                 return GL_RGB8;
259         case MESA_FORMAT_RGB565:
260                 return GL_RGB5;
261         default:
262                 return GL_NONE;
263         }
264 }
265
266 static void
267 nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
268                        struct gl_renderbuffer_attachment *att)
269 {
270         struct gl_renderbuffer *rb = att->Renderbuffer;
271         struct gl_texture_image *ti =
272                 att->Texture->Image[att->CubeMapFace][att->TextureLevel];
273
274         /* Allocate a renderbuffer object for the texture if we
275          * haven't already done so. */
276         if (!rb) {
277                 rb = nouveau_renderbuffer_new(ctx, ~0);
278                 assert(rb);
279
280                 rb->AllocStorage = NULL;
281                 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
282         }
283
284         /* Update the renderbuffer fields from the texture. */
285         set_renderbuffer_format(rb, get_tex_format(ti));
286         rb->Width = ti->Width;
287         rb->Height = ti->Height;
288         nouveau_surface_ref(&to_nouveau_teximage(ti)->surface,
289                             &to_nouveau_renderbuffer(rb)->surface);
290
291         context_dirty(ctx, FRAMEBUFFER);
292 }
293
294 static void
295 nouveau_finish_render_texture(struct gl_context *ctx,
296                               struct gl_renderbuffer_attachment *att)
297 {
298         texture_dirty(att->Texture);
299 }
300
301 void
302 nouveau_fbo_functions_init(struct dd_function_table *functions)
303 {
304 #if FEATURE_EXT_framebuffer_object
305         functions->NewFramebuffer = nouveau_framebuffer_new;
306         functions->NewRenderbuffer = nouveau_renderbuffer_new;
307         functions->MapRenderbuffer = nouveau_renderbuffer_map;
308         functions->UnmapRenderbuffer = nouveau_renderbuffer_unmap;
309         functions->BindFramebuffer = nouveau_bind_framebuffer;
310         functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer;
311         functions->RenderTexture = nouveau_render_texture;
312         functions->FinishRenderTexture = nouveau_finish_render_texture;
313 #endif
314 }