• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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