Tizen 2.0 Release
[profile/ivi/osmesa.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                 rb->DataType = GL_UNSIGNED_BYTE;
50                 s->cpp = 4;
51                 break;
52         case GL_RGBA:
53         case GL_RGBA8:
54                 rb->_BaseFormat  = GL_RGBA;
55                 rb->Format = MESA_FORMAT_ARGB8888;
56                 rb->DataType = GL_UNSIGNED_BYTE;
57                 s->cpp = 4;
58                 break;
59         case GL_RGB5:
60                 rb->_BaseFormat  = GL_RGB;
61                 rb->Format = MESA_FORMAT_RGB565;
62                 rb->DataType = GL_UNSIGNED_BYTE;
63                 s->cpp = 2;
64                 break;
65         case GL_DEPTH_COMPONENT16:
66                 rb->_BaseFormat  = GL_DEPTH_COMPONENT;
67                 rb->Format = MESA_FORMAT_Z16;
68                 rb->DataType = GL_UNSIGNED_SHORT;
69                 s->cpp = 2;
70                 break;
71         case GL_DEPTH_COMPONENT:
72         case GL_DEPTH_COMPONENT24:
73         case GL_STENCIL_INDEX8_EXT:
74         case GL_DEPTH24_STENCIL8_EXT:
75                 rb->_BaseFormat  = GL_DEPTH_STENCIL;
76                 rb->Format = MESA_FORMAT_Z24_S8;
77                 rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
78                 s->cpp = 4;
79                 break;
80         default:
81                 return GL_FALSE;
82         }
83
84         s->format = rb->Format;
85
86         return GL_TRUE;
87 }
88
89 static GLboolean
90 nouveau_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
91                              GLenum internalFormat,
92                              GLuint width, GLuint height)
93 {
94         struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
95
96         if (!set_renderbuffer_format(rb, internalFormat))
97                 return GL_FALSE;
98
99         rb->Width = width;
100         rb->Height = height;
101
102         nouveau_surface_alloc(ctx, s, TILED, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP,
103                               rb->Format, width, height);
104
105         context_dirty(ctx, FRAMEBUFFER);
106         return GL_TRUE;
107 }
108
109 static void
110 nouveau_renderbuffer_del(struct gl_renderbuffer *rb)
111 {
112         struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
113
114         nouveau_surface_ref(NULL, s);
115         FREE(rb);
116 }
117
118 static struct gl_renderbuffer *
119 nouveau_renderbuffer_new(struct gl_context *ctx, GLuint name)
120 {
121         struct gl_renderbuffer *rb;
122
123         rb = (struct gl_renderbuffer *)
124                 CALLOC_STRUCT(nouveau_renderbuffer);
125         if (!rb)
126                 return NULL;
127
128         _mesa_init_renderbuffer(rb, name);
129
130         rb->AllocStorage = nouveau_renderbuffer_storage;
131         rb->Delete = nouveau_renderbuffer_del;
132
133         return rb;
134 }
135
136 static GLboolean
137 nouveau_renderbuffer_dri_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
138                                  GLenum internalFormat,
139                                  GLuint width, GLuint height)
140 {
141         if (!set_renderbuffer_format(rb, internalFormat))
142                 return GL_FALSE;
143
144         rb->Width = width;
145         rb->Height = height;
146
147         return GL_TRUE;
148 }
149
150 struct gl_renderbuffer *
151 nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable)
152 {
153         struct gl_renderbuffer *rb;
154
155         rb = nouveau_renderbuffer_new(NULL, 0);
156         if (!rb)
157                 return NULL;
158
159         rb->AllocStorage = nouveau_renderbuffer_dri_storage;
160
161         if (!set_renderbuffer_format(rb, format)) {
162                 nouveau_renderbuffer_del(rb);
163                 return NULL;
164         }
165
166         return rb;
167 }
168
169 static struct gl_framebuffer *
170 nouveau_framebuffer_new(struct gl_context *ctx, GLuint name)
171 {
172         struct nouveau_framebuffer *nfb;
173
174         nfb = CALLOC_STRUCT(nouveau_framebuffer);
175         if (!nfb)
176                 return NULL;
177
178         _mesa_initialize_user_framebuffer(&nfb->base, name);
179
180         return &nfb->base;
181 }
182
183 struct gl_framebuffer *
184 nouveau_framebuffer_dri_new(const struct gl_config *visual)
185 {
186         struct nouveau_framebuffer *nfb;
187
188         nfb = CALLOC_STRUCT(nouveau_framebuffer);
189         if (!nfb)
190                 return NULL;
191
192         _mesa_initialize_window_framebuffer(&nfb->base, visual);
193         nfb->need_front = !visual->doubleBufferMode;
194
195         return &nfb->base;
196 }
197
198 static void
199 nouveau_bind_framebuffer(struct gl_context *ctx, GLenum target,
200                          struct gl_framebuffer *dfb,
201                          struct gl_framebuffer *rfb)
202 {
203         context_dirty(ctx, FRAMEBUFFER);
204 }
205
206 static void
207 nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
208                                  GLenum attachment, struct gl_renderbuffer *rb)
209 {
210         _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
211
212         context_dirty(ctx, FRAMEBUFFER);
213 }
214
215 static GLenum
216 get_tex_format(struct gl_texture_image *ti)
217 {
218         switch (ti->TexFormat) {
219         case MESA_FORMAT_ARGB8888:
220                 return GL_RGBA8;
221         case MESA_FORMAT_XRGB8888:
222                 return GL_RGB8;
223         case MESA_FORMAT_RGB565:
224                 return GL_RGB5;
225         default:
226                 return GL_NONE;
227         }
228 }
229
230 static void
231 nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
232                        struct gl_renderbuffer_attachment *att)
233 {
234         struct gl_renderbuffer *rb = att->Renderbuffer;
235         struct gl_texture_image *ti =
236                 att->Texture->Image[att->CubeMapFace][att->TextureLevel];
237
238         /* Allocate a renderbuffer object for the texture if we
239          * haven't already done so. */
240         if (!rb) {
241                 rb = nouveau_renderbuffer_new(ctx, ~0);
242                 assert(rb);
243
244                 rb->AllocStorage = NULL;
245                 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
246         }
247
248         /* Update the renderbuffer fields from the texture. */
249         set_renderbuffer_format(rb, get_tex_format(ti));
250         rb->Width = ti->Width;
251         rb->Height = ti->Height;
252         nouveau_surface_ref(&to_nouveau_teximage(ti)->surface,
253                             &to_nouveau_renderbuffer(rb)->surface);
254
255         context_dirty(ctx, FRAMEBUFFER);
256 }
257
258 static void
259 nouveau_finish_render_texture(struct gl_context *ctx,
260                               struct gl_renderbuffer_attachment *att)
261 {
262         texture_dirty(att->Texture);
263 }
264
265 void
266 nouveau_fbo_functions_init(struct dd_function_table *functions)
267 {
268 #if FEATURE_EXT_framebuffer_object
269         functions->NewFramebuffer = nouveau_framebuffer_new;
270         functions->NewRenderbuffer = nouveau_renderbuffer_new;
271         functions->BindFramebuffer = nouveau_bind_framebuffer;
272         functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer;
273         functions->RenderTexture = nouveau_render_texture;
274         functions->FinishRenderTexture = nouveau_finish_render_texture;
275 #endif
276 }