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