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
36static GLboolean
37set_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
83static GLboolean
84nouveau_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
103static void
104nouveau_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
112static struct gl_renderbuffer *
113nouveau_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
130static void
131nouveau_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
165static void
166nouveau_renderbuffer_unmap(struct gl_context *ctx,
167			   struct gl_renderbuffer *rb)
168{
169}
170
171static GLboolean
172nouveau_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
185struct gl_renderbuffer *
186nouveau_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
204static struct gl_framebuffer *
205nouveau_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
218struct gl_framebuffer *
219nouveau_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
233static void
234nouveau_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
241static void
242nouveau_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
250static void
251nouveau_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
264static void
265nouveau_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
272static int
273validate_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
288static void
289nouveau_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;
317err:
318	fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
319	return;
320}
321
322void
323nouveau_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