mesa: Make core Mesa allocate the texture renderbuffer wrapper.
[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
36 static GLboolean
37 set_renderbuffer_format(struct gl_renderbuffer *rb, GLenum internalFormat)
38 {
39 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
40
41 rb->InternalFormat = internalFormat;
42
43 switch (internalFormat) {
44 case GL_RGB:
45 case GL_RGB8:
46 rb->_BaseFormat = GL_RGB;
47 rb->Format = MESA_FORMAT_XRGB8888;
48 s->cpp = 4;
49 break;
50 case GL_RGBA:
51 case GL_RGBA8:
52 rb->_BaseFormat = GL_RGBA;
53 rb->Format = MESA_FORMAT_ARGB8888;
54 s->cpp = 4;
55 break;
56 case GL_RGB5:
57 rb->_BaseFormat = GL_RGB;
58 rb->Format = MESA_FORMAT_RGB565;
59 s->cpp = 2;
60 break;
61 case GL_DEPTH_COMPONENT16:
62 rb->_BaseFormat = GL_DEPTH_COMPONENT;
63 rb->Format = MESA_FORMAT_Z16;
64 s->cpp = 2;
65 break;
66 case GL_DEPTH_COMPONENT:
67 case GL_DEPTH_COMPONENT24:
68 case GL_STENCIL_INDEX8_EXT:
69 case GL_DEPTH24_STENCIL8_EXT:
70 rb->_BaseFormat = GL_DEPTH_STENCIL;
71 rb->Format = MESA_FORMAT_Z24_S8;
72 s->cpp = 4;
73 break;
74 default:
75 return GL_FALSE;
76 }
77
78 s->format = rb->Format;
79
80 return GL_TRUE;
81 }
82
83 static GLboolean
84 nouveau_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
85 GLenum internalFormat,
86 GLuint width, GLuint height)
87 {
88 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
89
90 if (!set_renderbuffer_format(rb, internalFormat))
91 return GL_FALSE;
92
93 rb->Width = width;
94 rb->Height = height;
95
96 nouveau_surface_alloc(ctx, s, TILED, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP,
97 rb->Format, width, height);
98
99 context_dirty(ctx, FRAMEBUFFER);
100 return GL_TRUE;
101 }
102
103 static void
104 nouveau_renderbuffer_del(struct gl_context *ctx, struct gl_renderbuffer *rb)
105 {
106 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
107
108 nouveau_surface_ref(NULL, s);
109 _mesa_delete_renderbuffer(ctx, rb);
110 }
111
112 static struct gl_renderbuffer *
113 nouveau_renderbuffer_new(struct gl_context *ctx, GLuint name)
114 {
115 struct gl_renderbuffer *rb;
116
117 rb = (struct gl_renderbuffer *)
118 CALLOC_STRUCT(nouveau_renderbuffer);
119 if (!rb)
120 return NULL;
121
122 _mesa_init_renderbuffer(rb, name);
123
124 rb->AllocStorage = nouveau_renderbuffer_storage;
125 rb->Delete = nouveau_renderbuffer_del;
126
127 return rb;
128 }
129
130 static void
131 nouveau_renderbuffer_map(struct gl_context *ctx,
132 struct gl_renderbuffer *rb,
133 GLuint x, GLuint y, GLuint w, GLuint h,
134 GLbitfield mode,
135 GLubyte **out_map,
136 GLint *out_stride)
137 {
138 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
139 GLubyte *map;
140 int stride;
141 int flags = 0;
142
143 if (mode & GL_MAP_READ_BIT)
144 flags |= NOUVEAU_BO_RD;
145 if (mode & GL_MAP_WRITE_BIT)
146 flags |= NOUVEAU_BO_WR;
147
148 nouveau_bo_map(s->bo, flags, context_client(ctx));
149
150 map = s->bo->map;
151 stride = s->pitch;
152
153 if (rb->Name == 0) {
154 map += stride * (rb->Height - 1);
155 stride = -stride;
156 }
157
158 map += x * s->cpp;
159 map += (int)y * stride;
160
161 *out_map = map;
162 *out_stride = stride;
163 }
164
165 static void
166 nouveau_renderbuffer_unmap(struct gl_context *ctx,
167 struct gl_renderbuffer *rb)
168 {
169 }
170
171 static GLboolean
172 nouveau_renderbuffer_dri_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
173 GLenum internalFormat,
174 GLuint width, GLuint height)
175 {
176 if (!set_renderbuffer_format(rb, internalFormat))
177 return GL_FALSE;
178
179 rb->Width = width;
180 rb->Height = height;
181
182 return GL_TRUE;
183 }
184
185 struct gl_renderbuffer *
186 nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable)
187 {
188 struct gl_renderbuffer *rb;
189
190 rb = nouveau_renderbuffer_new(NULL, 0);
191 if (!rb)
192 return NULL;
193
194 rb->AllocStorage = nouveau_renderbuffer_dri_storage;
195
196 if (!set_renderbuffer_format(rb, format)) {
197 nouveau_renderbuffer_del(NULL, rb);
198 return NULL;
199 }
200
201 return rb;
202 }
203
204 static struct gl_framebuffer *
205 nouveau_framebuffer_new(struct gl_context *ctx, GLuint name)
206 {
207 struct nouveau_framebuffer *nfb;
208
209 nfb = CALLOC_STRUCT(nouveau_framebuffer);
210 if (!nfb)
211 return NULL;
212
213 _mesa_initialize_user_framebuffer(&nfb->base, name);
214
215 return &nfb->base;
216 }
217
218 struct gl_framebuffer *
219 nouveau_framebuffer_dri_new(const struct gl_config *visual)
220 {
221 struct nouveau_framebuffer *nfb;
222
223 nfb = CALLOC_STRUCT(nouveau_framebuffer);
224 if (!nfb)
225 return NULL;
226
227 _mesa_initialize_window_framebuffer(&nfb->base, visual);
228 nfb->need_front = !visual->doubleBufferMode;
229
230 return &nfb->base;
231 }
232
233 static void
234 nouveau_bind_framebuffer(struct gl_context *ctx, GLenum target,
235 struct gl_framebuffer *dfb,
236 struct gl_framebuffer *rfb)
237 {
238 context_dirty(ctx, FRAMEBUFFER);
239 }
240
241 static void
242 nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
243 GLenum attachment, struct gl_renderbuffer *rb)
244 {
245 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
246
247 context_dirty(ctx, FRAMEBUFFER);
248 }
249
250 static GLenum
251 get_tex_format(struct gl_texture_image *ti)
252 {
253 switch (ti->TexFormat) {
254 case MESA_FORMAT_ARGB8888:
255 return GL_RGBA8;
256 case MESA_FORMAT_XRGB8888:
257 return GL_RGB8;
258 case MESA_FORMAT_RGB565:
259 return GL_RGB5;
260 default:
261 return GL_NONE;
262 }
263 }
264
265 static void
266 nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
267 struct gl_renderbuffer_attachment *att)
268 {
269 struct gl_renderbuffer *rb = att->Renderbuffer;
270 struct gl_texture_image *ti =
271 att->Texture->Image[att->CubeMapFace][att->TextureLevel];
272
273 /* Update the renderbuffer fields from the texture. */
274 set_renderbuffer_format(rb, get_tex_format(ti));
275 rb->Width = ti->Width;
276 rb->Height = ti->Height;
277 nouveau_surface_ref(&to_nouveau_teximage(ti)->surface,
278 &to_nouveau_renderbuffer(rb)->surface);
279
280 context_dirty(ctx, FRAMEBUFFER);
281 }
282
283 static void
284 nouveau_finish_render_texture(struct gl_context *ctx,
285 struct gl_renderbuffer_attachment *att)
286 {
287 texture_dirty(att->Texture);
288 }
289
290 void
291 nouveau_fbo_functions_init(struct dd_function_table *functions)
292 {
293 functions->NewFramebuffer = nouveau_framebuffer_new;
294 functions->NewRenderbuffer = nouveau_renderbuffer_new;
295 functions->MapRenderbuffer = nouveau_renderbuffer_map;
296 functions->UnmapRenderbuffer = nouveau_renderbuffer_unmap;
297 functions->BindFramebuffer = nouveau_bind_framebuffer;
298 functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer;
299 functions->RenderTexture = nouveau_render_texture;
300 functions->FinishRenderTexture = nouveau_finish_render_texture;
301 }