nouveau_screen.c revision 4a7e9b5df453055ed6eedce1ea5c1d4a2f810fa7
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_context.h"
29#include "nouveau_fbo.h"
30#include "nouveau_texture.h"
31#include "nouveau_drmif.h"
32#include "nv04_driver.h"
33#include "nv10_driver.h"
34#include "nv20_driver.h"
35
36#include "main/framebuffer.h"
37#include "main/renderbuffer.h"
38
39static const __DRIextension *nouveau_screen_extensions[];
40
41static void
42nouveau_destroy_screen(__DRIscreen *dri_screen);
43
44static const __DRIconfig **
45nouveau_get_configs(void)
46{
47	__DRIconfig **configs = NULL;
48	int i;
49
50	const uint8_t depth_bits[]   = { 0, 16, 24, 24 };
51	const uint8_t stencil_bits[] = { 0,  0,  0,  8 };
52	const uint8_t msaa_samples[] = { 0 };
53
54	const struct {
55		GLenum format;
56		GLenum type;
57	} fb_formats[] = {
58		{ GL_RGB , GL_UNSIGNED_SHORT_5_6_5     },
59		{ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
60		{ GL_BGR , GL_UNSIGNED_INT_8_8_8_8_REV },
61	};
62
63	const GLenum back_buffer_modes[] = {
64		GLX_NONE, GLX_SWAP_UNDEFINED_OML
65	};
66
67	for (i = 0; i < Elements(fb_formats); i++) {
68		__DRIconfig **config;
69
70		config = driCreateConfigs(fb_formats[i].format,
71					  fb_formats[i].type,
72					  depth_bits, stencil_bits,
73					  Elements(depth_bits),
74					  back_buffer_modes,
75					  Elements(back_buffer_modes),
76					  msaa_samples,
77					  Elements(msaa_samples),
78					  GL_TRUE);
79		assert(config);
80
81		configs = configs ? driConcatConfigs(configs, config)
82			: config;
83	}
84
85	return (const __DRIconfig **)configs;
86}
87
88static const __DRIconfig **
89nouveau_init_screen2(__DRIscreen *dri_screen)
90{
91	const __DRIconfig **configs;
92	struct nouveau_screen *screen;
93	int ret;
94
95	/* Allocate the screen. */
96	screen = CALLOC_STRUCT(nouveau_screen);
97	if (!screen)
98		return NULL;
99
100	dri_screen->private = screen;
101	dri_screen->extensions = nouveau_screen_extensions;
102	screen->dri_screen = dri_screen;
103
104	/* Open the DRM device. */
105	ret = nouveau_device_open_existing(&screen->device, 0, dri_screen->fd,
106					   0);
107	if (ret) {
108		nouveau_error("Error opening the DRM device.\n");
109		goto fail;
110	}
111
112	/* Choose the card specific function pointers. */
113	switch (screen->device->chipset & 0xf0) {
114	case 0x00:
115		screen->driver = &nv04_driver;
116		break;
117	case 0x10:
118		screen->driver = &nv10_driver;
119		break;
120	case 0x20:
121		screen->driver = &nv20_driver;
122		break;
123	default:
124		assert(0);
125	}
126
127	configs = nouveau_get_configs();
128	if (!configs)
129		goto fail;
130
131	return configs;
132fail:
133	nouveau_destroy_screen(dri_screen);
134	return NULL;
135
136}
137
138static void
139nouveau_destroy_screen(__DRIscreen *dri_screen)
140{
141	struct nouveau_screen *screen = dri_screen->private;
142
143	if (!screen)
144		return;
145
146	if (screen->device)
147		nouveau_device_close(&screen->device);
148
149	FREE(screen);
150	dri_screen->private = NULL;
151}
152
153static GLboolean
154nouveau_create_buffer(__DRIscreen *dri_screen,
155		      __DRIdrawable *drawable,
156		      const __GLcontextModes *visual,
157		      GLboolean is_pixmap)
158{
159	struct gl_renderbuffer  *rb;
160	struct gl_framebuffer *fb;
161	GLenum color_format;
162
163	if (is_pixmap)
164		return GL_FALSE; /* not implemented */
165
166	if (visual->redBits == 5)
167		color_format = GL_RGB5;
168	else if (visual->alphaBits == 0)
169		color_format = GL_RGB8;
170	else
171		color_format = GL_RGBA8;
172
173	fb = nouveau_framebuffer_dri_new(visual);
174	if (!fb)
175		return GL_FALSE;
176
177	/* Front buffer. */
178	rb = nouveau_renderbuffer_dri_new(color_format, drawable);
179	_mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, rb);
180
181	/* Back buffer */
182	if (visual->doubleBufferMode) {
183		rb = nouveau_renderbuffer_dri_new(color_format, drawable);
184		_mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, rb);
185	}
186
187	/* Depth/stencil buffer. */
188	if (visual->depthBits == 24 && visual->stencilBits == 8) {
189		rb = nouveau_renderbuffer_dri_new(GL_DEPTH24_STENCIL8_EXT, drawable);
190		_mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
191		_mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
192
193	} else if (visual->depthBits == 24) {
194		rb = nouveau_renderbuffer_dri_new(GL_DEPTH_COMPONENT24, drawable);
195		_mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
196
197	} else if (visual->depthBits == 16) {
198		rb = nouveau_renderbuffer_dri_new(GL_DEPTH_COMPONENT16, drawable);
199		_mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
200	}
201
202	/* Software renderbuffers. */
203	_mesa_add_soft_renderbuffers(fb, GL_FALSE, GL_FALSE, GL_FALSE,
204				     visual->accumRedBits > 0,
205				     GL_FALSE, GL_FALSE);
206
207	drawable->driverPrivate = fb;
208
209	return GL_TRUE;
210}
211
212static void
213nouveau_destroy_buffer(__DRIdrawable *drawable)
214{
215	_mesa_reference_framebuffer(
216		(struct gl_framebuffer **)&drawable->driverPrivate, NULL);
217}
218
219static void
220nouveau_drawable_flush(__DRIdrawable *draw)
221{
222}
223
224static const struct __DRI2flushExtensionRec nouveau_flush_extension = {
225    { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
226    nouveau_drawable_flush,
227    dri2InvalidateDrawable,
228};
229
230static const struct __DRItexBufferExtensionRec nouveau_texbuffer_extension = {
231    { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
232    NULL,
233    nouveau_set_texbuffer,
234};
235
236static const __DRIextension *nouveau_screen_extensions[] = {
237    &nouveau_flush_extension.base,
238    &nouveau_texbuffer_extension.base,
239    NULL
240};
241
242const struct __DriverAPIRec driDriverAPI = {
243	.InitScreen2     = nouveau_init_screen2,
244	.DestroyScreen   = nouveau_destroy_screen,
245	.CreateBuffer    = nouveau_create_buffer,
246	.DestroyBuffer   = nouveau_destroy_buffer,
247	.CreateContext   = nouveau_context_create,
248	.DestroyContext  = nouveau_context_destroy,
249	.MakeCurrent     = nouveau_context_make_current,
250	.UnbindContext   = nouveau_context_unbind,
251};
252
253/* This is the table of extensions that the loader will dlsym() for. */
254PUBLIC const __DRIextension *__driDriverExtensions[] = {
255	&driCoreExtension.base,
256	&driDRI2Extension.base,
257	NULL
258};
259