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
set_renderbuffer_format(struct gl_renderbuffer * rb,GLenum internalFormat)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
nouveau_renderbuffer_storage(struct gl_context * ctx,struct gl_renderbuffer * rb,GLenum internalFormat,GLuint width,GLuint height)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
nouveau_renderbuffer_del(struct gl_context * ctx,struct gl_renderbuffer * rb)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 *
nouveau_renderbuffer_new(struct gl_context * ctx,GLuint name)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
nouveau_renderbuffer_map(struct gl_context * ctx,struct gl_renderbuffer * rb,GLuint x,GLuint y,GLuint w,GLuint h,GLbitfield mode,GLubyte ** out_map,GLint * out_stride)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
nouveau_renderbuffer_unmap(struct gl_context * ctx,struct gl_renderbuffer * rb)166 nouveau_renderbuffer_unmap(struct gl_context *ctx,
167 struct gl_renderbuffer *rb)
168 {
169 }
170
171 static GLboolean
nouveau_renderbuffer_dri_storage(struct gl_context * ctx,struct gl_renderbuffer * rb,GLenum internalFormat,GLuint width,GLuint height)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 *
nouveau_renderbuffer_dri_new(GLenum format,__DRIdrawable * drawable)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 *
nouveau_framebuffer_new(struct gl_context * ctx,GLuint name)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 *
nouveau_framebuffer_dri_new(const struct gl_config * visual)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
nouveau_bind_framebuffer(struct gl_context * ctx,GLenum target,struct gl_framebuffer * dfb,struct gl_framebuffer * rfb)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
nouveau_framebuffer_renderbuffer(struct gl_context * ctx,struct gl_framebuffer * fb,GLenum attachment,struct gl_renderbuffer * rb)242 nouveau_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
243 GLenum attachment, struct gl_renderbuffer *rb)
244 {
245 _mesa_FramebufferRenderbuffer_sw(ctx, fb, attachment, rb);
246
247 context_dirty(ctx, FRAMEBUFFER);
248 }
249
250 static void
nouveau_render_texture(struct gl_context * ctx,struct gl_framebuffer * fb,struct gl_renderbuffer_attachment * att)251 nouveau_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
252 struct gl_renderbuffer_attachment *att)
253 {
254 struct gl_renderbuffer *rb = att->Renderbuffer;
255 struct gl_texture_image *ti = rb->TexImage;
256
257 /* Update the renderbuffer fields from the texture. */
258 nouveau_surface_ref(&to_nouveau_teximage(ti)->surface,
259 &to_nouveau_renderbuffer(rb)->surface);
260
261 context_dirty(ctx, FRAMEBUFFER);
262 }
263
264 static void
nouveau_finish_render_texture(struct gl_context * ctx,struct gl_renderbuffer * rb)265 nouveau_finish_render_texture(struct gl_context *ctx,
266 struct gl_renderbuffer *rb)
267 {
268 if (rb && rb->TexImage)
269 texture_dirty(rb->TexImage->TexObject);
270 }
271
272 static int
validate_format_bpp(mesa_format format)273 validate_format_bpp(mesa_format format)
274 {
275 switch (format) {
276 case MESA_FORMAT_B8G8R8X8_UNORM:
277 case MESA_FORMAT_B8G8R8A8_UNORM:
278 case MESA_FORMAT_S8_UINT_Z24_UNORM:
279 return 32;
280 case MESA_FORMAT_B5G6R5_UNORM:
281 case MESA_FORMAT_Z_UNORM16:
282 return 16;
283 default:
284 return 0;
285 }
286 }
287
288 static void
nouveau_check_framebuffer_complete(struct gl_context * ctx,struct gl_framebuffer * fb)289 nouveau_check_framebuffer_complete(struct gl_context *ctx,
290 struct gl_framebuffer *fb)
291 {
292 struct gl_renderbuffer_attachment *color =
293 &fb->Attachment[BUFFER_COLOR0];
294 struct gl_renderbuffer_attachment *depth =
295 &fb->Attachment[BUFFER_DEPTH];
296 int color_bpp = 0, zeta_bpp;
297
298 if (color->Type == GL_TEXTURE) {
299 color_bpp = validate_format_bpp(
300 color->Renderbuffer->TexImage->TexFormat);
301 if (!color_bpp)
302 goto err;
303 }
304
305 if (depth->Type == GL_TEXTURE) {
306 zeta_bpp = validate_format_bpp(
307 depth->Renderbuffer->TexImage->TexFormat);
308 if (!zeta_bpp)
309 goto err;
310 /* NV04/NV05 requires same bpp-ness for color/zeta */
311 if (context_chipset(ctx) < 0x10 &&
312 color_bpp && color_bpp != zeta_bpp)
313 goto err;
314 }
315
316 return;
317 err:
318 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
319 return;
320 }
321
322 void
nouveau_fbo_functions_init(struct dd_function_table * functions)323 nouveau_fbo_functions_init(struct dd_function_table *functions)
324 {
325 functions->NewFramebuffer = nouveau_framebuffer_new;
326 functions->NewRenderbuffer = nouveau_renderbuffer_new;
327 functions->MapRenderbuffer = nouveau_renderbuffer_map;
328 functions->UnmapRenderbuffer = nouveau_renderbuffer_unmap;
329 functions->BindFramebuffer = nouveau_bind_framebuffer;
330 functions->FramebufferRenderbuffer = nouveau_framebuffer_renderbuffer;
331 functions->RenderTexture = nouveau_render_texture;
332 functions->FinishRenderTexture = nouveau_finish_render_texture;
333 functions->ValidateFramebuffer = nouveau_check_framebuffer_complete;
334 }
335