radv: Only save the descriptor set if we have one.
[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_B8G8R8X8_UNORM;
48 s->cpp = 4;
49 break;
50 case GL_RGBA:
51 case GL_RGBA8:
52 rb->_BaseFormat = GL_RGBA;
53 rb->Format = MESA_FORMAT_B8G8R8A8_UNORM;
54 s->cpp = 4;
55 break;
56 case GL_RGB5:
57 rb->_BaseFormat = GL_RGB;
58 rb->Format = MESA_FORMAT_B5G6R5_UNORM;
59 s->cpp = 2;
60 break;
61 case GL_DEPTH_COMPONENT16:
62 rb->_BaseFormat = GL_DEPTH_COMPONENT;
63 rb->Format = MESA_FORMAT_Z_UNORM16;
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_S8_UINT_Z24_UNORM;
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 bool flip_y)
138 {
139 struct nouveau_surface *s = &to_nouveau_renderbuffer(rb)->surface;
140 GLubyte *map;
141 int stride;
142 int flags = 0;
143
144 /* driver does not support GL_FRAMEBUFFER_FLIP_Y_MESA */
145 assert((rb->Name == 0) == flip_y);
146
147 if (mode & GL_MAP_READ_BIT)
148 flags |= NOUVEAU_BO_RD;
149 if (mode & GL_MAP_WRITE_BIT)
150 flags |= NOUVEAU_BO_WR;
151
152 nouveau_bo_map(s->bo, flags, context_client(ctx));
153
154 map = s->bo->map;
155 stride = s->pitch;
156
157 if (rb->Name == 0) {
158 map += stride * (rb->Height - 1);
159 stride = -stride;
160 }
161
162 map += x * s->cpp;
163 map += (int)y * stride;
164
165 *out_map = map;
166 *out_stride = stride;
167 }
168
169 static void
170 nouveau_renderbuffer_unmap(struct gl_context *ctx,
171 struct gl_renderbuffer *rb)
172 {
173 }
174
175 static GLboolean
176 nouveau_renderbuffer_dri_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
177 GLenum internalFormat,
178 GLuint width, GLuint height)
179 {
180 if (!set_renderbuffer_format(rb, internalFormat))
181 return GL_FALSE;
182
183 rb->Width = width;
184 rb->Height = height;
185
186 return GL_TRUE;
187 }
188
189 struct gl_renderbuffer *
190 nouveau_renderbuffer_dri_new(GLenum format, __DRIdrawable *drawable)
191 {
192 struct gl_renderbuffer *rb;
193
194 rb = nouveau_renderbuffer_new(NULL, 0);
195 if (!rb)
196 return NULL;
197
198 rb->AllocStorage = nouveau_renderbuffer_dri_storage;
199
200 if (!set_renderbuffer_format(rb, format)) {
201 nouveau_renderbuffer_del(NULL, rb);
202 return NULL;
203 }
204
205 return rb;
206 }
207
208 static struct gl_framebuffer *
209 nouveau_framebuffer_new(struct gl_context *ctx, GLuint name)
210 {
211 struct nouveau_framebuffer *nfb;
212
213 nfb = CALLOC_STRUCT(nouveau_framebuffer);
214 if (!nfb)
215 return NULL;
216
217 _mesa_initialize_user_framebuffer(&nfb->base, name);
218
219 return &nfb->base;
220 }
221
222 struct gl_framebuffer *
223 nouveau_framebuffer_dri_new(const struct gl_config *visual)
224 {
225 struct nouveau_framebuffer *nfb;
226
227 nfb = CALLOC_STRUCT(nouveau_framebuffer);
228 if (!nfb)
229 return NULL;
230
231 _mesa_initialize_window_framebuffer(&nfb->base, visual);
232 nfb->need_front = !visual->doubleBufferMode;
233
234 return &nfb->base;
235 }
236
237 static void
238 nouveau_bind_framebuffer(struct gl_context *ctx, GLenum target,
239 struct gl_framebuffer *dfb,
240 struct gl_framebuffer *rfb)
241 {
242 context_dirty(ctx, FRAMEBUFFER);
243 }
244
245 static void
246 nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
247 GLenum attachment, struct gl_renderbuffer *rb)
248 {
249 _mesa_FramebufferRenderbuffer_sw(ctx, fb, attachment, rb);
250
251 context_dirty(ctx, FRAMEBUFFER);
252 }
253
254 static void
255 nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
256 struct gl_renderbuffer_attachment *att)
257 {
258 struct gl_renderbuffer *rb = att->Renderbuffer;
259 struct gl_texture_image *ti = rb->TexImage;
260
261 /* Update the renderbuffer fields from the texture. */
262 nouveau_surface_ref(&to_nouveau_teximage(ti)->surface,
263 &to_nouveau_renderbuffer(rb)->surface);
264
265 context_dirty(ctx, FRAMEBUFFER);
266 }
267
268 static void
269 nouveau_finish_render_texture(struct gl_context *ctx,
270 struct gl_renderbuffer *rb)
271 {
272 if (rb && rb->TexImage)
273 texture_dirty(rb->TexImage->TexObject);
274 }
275
276 static int
277 validate_format_bpp(mesa_format format)
278 {
279 switch (format) {
280 case MESA_FORMAT_B8G8R8X8_UNORM:
281 case MESA_FORMAT_B8G8R8A8_UNORM:
282 case MESA_FORMAT_S8_UINT_Z24_UNORM:
283 return 32;
284 case MESA_FORMAT_B5G6R5_UNORM:
285 case MESA_FORMAT_Z_UNORM16:
286 return 16;
287 default:
288 return 0;
289 }
290 }
291
292 static void
293 nouveau_check_framebuffer_complete(struct gl_context *ctx,
294 struct gl_framebuffer *fb)
295 {
296 struct gl_renderbuffer_attachment *color =
297 &fb->Attachment[BUFFER_COLOR0];
298 struct gl_renderbuffer_attachment *depth =
299 &fb->Attachment[BUFFER_DEPTH];
300 int color_bpp = 0, zeta_bpp;
301
302 if (color->Type == GL_TEXTURE) {
303 color_bpp = validate_format_bpp(
304 color->Renderbuffer->TexImage->TexFormat);
305 if (!color_bpp)
306 goto err;
307 }
308
309 if (depth->Type == GL_TEXTURE) {
310 zeta_bpp = validate_format_bpp(
311 depth->Renderbuffer->TexImage->TexFormat);
312 if (!zeta_bpp)
313 goto err;
314 /* NV04/NV05 requires same bpp-ness for color/zeta */
315 if (context_chipset(ctx) < 0x10 &&
316 color_bpp && color_bpp != zeta_bpp)
317 goto err;
318 }
319
320 return;
321 err:
322 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
323 return;
324 }
325
326 void
327 nouveau_fbo_functions_init(struct dd_function_table *functions)
328 {
329 functions->NewFramebuffer = nouveau_framebuffer_new;
330 functions->NewRenderbuffer = nouveau_renderbuffer_new;
331 functions->MapRenderbuffer = nouveau_renderbuffer_map;
332 functions->UnmapRenderbuffer = nouveau_renderbuffer_unmap;
333 functions->BindFramebuffer = nouveau_bind_framebuffer;
334 functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer;
335 functions->RenderTexture = nouveau_render_texture;
336 functions->FinishRenderTexture = nouveau_finish_render_texture;
337 functions->ValidateFramebuffer = nouveau_check_framebuffer_complete;
338 }