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 <stdio.h>
28 #include <xf86drm.h>
29 #include <nouveau_drm.h>
30 #include "nouveau_driver.h"
31 #include "nouveau_context.h"
32 #include "nouveau_fbo.h"
33 #include "nouveau_texture.h"
34 #include "nv04_driver.h"
35 #include "nv10_driver.h"
36 #include "nv20_driver.h"
37 
38 #include "main/framebuffer.h"
39 #include "main/fbobject.h"
40 #include "main/renderbuffer.h"
41 #include "util/u_memory.h"
42 #include "swrast/s_renderbuffer.h"
43 
44 #include <nvif/class.h>
45 #include <nvif/cl0080.h>
46 
47 static const __DRIextension *nouveau_screen_extensions[];
48 
49 static void
50 nouveau_destroy_screen(__DRIscreen *dri_screen);
51 
52 static const __DRIconfig **
nouveau_get_configs(uint32_t chipset)53 nouveau_get_configs(uint32_t chipset)
54 {
55 	__DRIconfig **configs = NULL;
56 	int i;
57 
58 	const uint8_t depth_bits[]   = { 0, 16, 24, 24 };
59 	const uint8_t stencil_bits[] = { 0,  0,  0,  8 };
60 	const uint8_t msaa_samples[] = { 0 };
61 
62 	static const mesa_format formats[3] = {
63 		MESA_FORMAT_B5G6R5_UNORM,
64 		MESA_FORMAT_B8G8R8A8_UNORM,
65 		MESA_FORMAT_B8G8R8X8_UNORM,
66 	};
67 
68 	const GLenum back_buffer_modes[] = {
69 		__DRI_ATTRIB_SWAP_NONE, __DRI_ATTRIB_SWAP_UNDEFINED
70 	};
71 
72 	for (i = 0; i < ARRAY_SIZE(formats); i++) {
73 		__DRIconfig **config;
74 
75 		config = driCreateConfigs(formats[i],
76 					  depth_bits, stencil_bits,
77 					  ARRAY_SIZE(depth_bits),
78 					  back_buffer_modes,
79 					  ARRAY_SIZE(back_buffer_modes),
80 					  msaa_samples,
81 					  ARRAY_SIZE(msaa_samples),
82 					  GL_TRUE, chipset < 0x10);
83 		assert(config);
84 
85 		configs = driConcatConfigs(configs, config);
86 	}
87 
88 	return (const __DRIconfig **)configs;
89 }
90 
91 static const __DRIconfig **
nouveau_init_screen2(__DRIscreen * dri_screen)92 nouveau_init_screen2(__DRIscreen *dri_screen)
93 {
94 	const __DRIconfig **configs;
95 	struct nouveau_screen *screen;
96 	int ret;
97 
98 	/* Allocate the screen. */
99 	screen = CALLOC_STRUCT(nouveau_screen);
100 	if (!screen)
101 		return NULL;
102 
103 	dri_screen->driverPrivate = screen;
104 
105 	/* Open the DRM device. */
106 	ret = nouveau_drm_new(dri_screen->fd, &screen->drm);
107 	if (ret) {
108 		nouveau_error("Error opening the DRM device.\n");
109 		goto fail;
110 	}
111 
112 	ret = nouveau_device_new(&screen->drm->client, NV_DEVICE,
113 				 &(struct nv_device_v0) {
114 					.device = ~0ULL,
115 				 }, sizeof(struct nv_device_v0),
116 				 &screen->device);
117 	if (ret) {
118 		nouveau_error("Error creating device object.\n");
119 		goto fail;
120 	}
121 
122 	/* Choose the card specific function pointers. */
123 	switch (screen->device->chipset & 0xf0) {
124 	case 0x00:
125 		screen->driver = &nv04_driver;
126 		dri_screen->max_gl_compat_version = 12;
127 		break;
128 	case 0x10:
129 		screen->driver = &nv10_driver;
130 		dri_screen->max_gl_compat_version = 12;
131 		dri_screen->max_gl_es1_version = 10;
132 		break;
133 	case 0x20:
134 	case 0x30:
135 		screen->driver = &nv20_driver;
136 		dri_screen->max_gl_compat_version = 13;
137 		dri_screen->max_gl_es1_version = 10;
138 		break;
139 	default:
140 		nouveau_error("Unknown chipset: %02X\n",
141 			      screen->device->chipset);
142 		goto fail;
143 	}
144 
145 	dri_screen->extensions = nouveau_screen_extensions;
146 	screen->dri_screen = dri_screen;
147 
148 	configs = nouveau_get_configs(screen->device->chipset);
149 	if (!configs)
150 		goto fail;
151 
152 	return configs;
153 fail:
154 	nouveau_destroy_screen(dri_screen);
155 	return NULL;
156 
157 }
158 
159 static int
nouveau_query_renderer_integer(__DRIscreen * psp,int param,unsigned int * value)160 nouveau_query_renderer_integer(__DRIscreen *psp, int param,
161 			       unsigned int *value)
162 {
163 	const struct nouveau_screen *const screen =
164 		(struct nouveau_screen *) psp->driverPrivate;
165 
166 	switch (param) {
167 	case __DRI2_RENDERER_VENDOR_ID:
168 		value[0] = 0x10de;
169 		return 0;
170 	case __DRI2_RENDERER_DEVICE_ID: {
171 		uint64_t device_id;
172 
173 		if (nouveau_getparam(screen->device,
174 				     NOUVEAU_GETPARAM_PCI_DEVICE,
175 				     &device_id)) {
176 			nouveau_error("Error retrieving the device PCIID.\n");
177 			device_id = -1;
178 		}
179 		value[0] = (unsigned int) device_id;
180 		return 0;
181 	}
182 	case __DRI2_RENDERER_ACCELERATED:
183 		value[0] = 1;
184 		return 0;
185 	case __DRI2_RENDERER_VIDEO_MEMORY:
186 		/* XXX: return vram_size or vram_limit ? */
187 		value[0] = screen->device->vram_size >> 20;
188 		return 0;
189 	case __DRI2_RENDERER_UNIFIED_MEMORY_ARCHITECTURE:
190 		value[0] = 0;
191 		return 0;
192 	default:
193 		return driQueryRendererIntegerCommon(psp, param, value);
194 	}
195 }
196 
197 static int
nouveau_query_renderer_string(__DRIscreen * psp,int param,const char ** value)198 nouveau_query_renderer_string(__DRIscreen *psp, int param, const char **value)
199 {
200 	const struct nouveau_screen *const screen =
201 		(struct nouveau_screen *) psp->driverPrivate;
202 
203 	switch (param) {
204 	case __DRI2_RENDERER_VENDOR_ID:
205 		value[0] = nouveau_vendor_string;
206 		return 0;
207 	case __DRI2_RENDERER_DEVICE_ID:
208 		value[0] = nouveau_get_renderer_string(screen->device->chipset);
209 		return 0;
210 	default:
211 		return -1;
212    }
213 }
214 
215 static const __DRI2rendererQueryExtension nouveau_renderer_query_extension = {
216 	.base = { __DRI2_RENDERER_QUERY, 1 },
217 
218 	.queryInteger        = nouveau_query_renderer_integer,
219 	.queryString         = nouveau_query_renderer_string
220 };
221 
222 static void
nouveau_destroy_screen(__DRIscreen * dri_screen)223 nouveau_destroy_screen(__DRIscreen *dri_screen)
224 {
225 	struct nouveau_screen *screen = dri_screen->driverPrivate;
226 
227 	if (!screen)
228 		return;
229 
230 	nouveau_device_del(&screen->device);
231 	nouveau_drm_del(&screen->drm);
232 
233 	free(screen);
234 	dri_screen->driverPrivate = NULL;
235 }
236 
237 static GLboolean
nouveau_create_buffer(__DRIscreen * dri_screen,__DRIdrawable * drawable,const struct gl_config * visual,GLboolean is_pixmap)238 nouveau_create_buffer(__DRIscreen *dri_screen,
239 		      __DRIdrawable *drawable,
240 		      const struct gl_config *visual,
241 		      GLboolean is_pixmap)
242 {
243 	struct gl_renderbuffer *rb;
244 	struct gl_framebuffer *fb;
245 	GLenum color_format;
246 
247 	if (is_pixmap)
248 		return GL_FALSE; /* not implemented */
249 
250 	if (visual->redBits == 5)
251 		color_format = GL_RGB5;
252 	else if (visual->alphaBits == 0)
253 		color_format = GL_RGB8;
254 	else
255 		color_format = GL_RGBA8;
256 
257 	fb = nouveau_framebuffer_dri_new(visual);
258 	if (!fb)
259 		return GL_FALSE;
260 
261 	/* Front buffer. */
262 	rb = nouveau_renderbuffer_dri_new(color_format, drawable);
263 	_mesa_attach_and_own_rb(fb, BUFFER_FRONT_LEFT, rb);
264 
265 	/* Back buffer */
266 	if (visual->doubleBufferMode) {
267 		rb = nouveau_renderbuffer_dri_new(color_format, drawable);
268 		_mesa_attach_and_own_rb(fb, BUFFER_BACK_LEFT, rb);
269 	}
270 
271 	/* Depth/stencil buffer. */
272 	if (visual->depthBits == 24 && visual->stencilBits == 8) {
273 		rb = nouveau_renderbuffer_dri_new(GL_DEPTH24_STENCIL8_EXT, drawable);
274 		_mesa_attach_and_own_rb(fb, BUFFER_DEPTH, rb);
275 		_mesa_attach_and_reference_rb(fb, BUFFER_STENCIL, rb);
276 
277 	} else if (visual->depthBits == 24) {
278 		rb = nouveau_renderbuffer_dri_new(GL_DEPTH_COMPONENT24, drawable);
279 		_mesa_attach_and_own_rb(fb, BUFFER_DEPTH, rb);
280 
281 	} else if (visual->depthBits == 16) {
282 		rb = nouveau_renderbuffer_dri_new(GL_DEPTH_COMPONENT16, drawable);
283 		_mesa_attach_and_own_rb(fb, BUFFER_DEPTH, rb);
284 	}
285 
286 	/* Software renderbuffers. */
287 	_swrast_add_soft_renderbuffers(fb, GL_FALSE, GL_FALSE, GL_FALSE,
288                                        visual->accumRedBits > 0,
289                                        GL_FALSE);
290 
291 	drawable->driverPrivate = fb;
292 
293 	return GL_TRUE;
294 }
295 
296 static void
nouveau_destroy_buffer(__DRIdrawable * drawable)297 nouveau_destroy_buffer(__DRIdrawable *drawable)
298 {
299 	_mesa_reference_framebuffer(
300 		(struct gl_framebuffer **)&drawable->driverPrivate, NULL);
301 }
302 
303 static void
nouveau_drawable_flush(__DRIdrawable * draw)304 nouveau_drawable_flush(__DRIdrawable *draw)
305 {
306 }
307 
308 static const struct __DRI2flushExtensionRec nouveau_flush_extension = {
309    .base = { __DRI2_FLUSH, 3 },
310 
311    .flush               = nouveau_drawable_flush,
312    .invalidate          = dri2InvalidateDrawable,
313 };
314 
315 static const struct __DRItexBufferExtensionRec nouveau_texbuffer_extension = {
316    .base = { __DRI_TEX_BUFFER, 3 },
317 
318    .setTexBuffer        = NULL,
319    .setTexBuffer2       = nouveau_set_texbuffer,
320    .releaseTexBuffer    = NULL,
321 };
322 
323 static const __DRIextension *nouveau_screen_extensions[] = {
324     &nouveau_flush_extension.base,
325     &nouveau_texbuffer_extension.base,
326     &nouveau_renderer_query_extension.base,
327     &dri2ConfigQueryExtension.base,
328     &dri2NoErrorExtension.base,
329     NULL
330 };
331 
332 const struct __DriverAPIRec nouveau_driver_api = {
333 	.InitScreen      = nouveau_init_screen2,
334 	.DestroyScreen   = nouveau_destroy_screen,
335 	.CreateBuffer    = nouveau_create_buffer,
336 	.DestroyBuffer   = nouveau_destroy_buffer,
337 	.CreateContext   = nouveau_context_create,
338 	.DestroyContext  = nouveau_context_destroy,
339 	.MakeCurrent     = nouveau_context_make_current,
340 	.UnbindContext   = nouveau_context_unbind,
341 };
342 
343 static const struct __DRIDriverVtableExtensionRec nouveau_vtable = {
344    .base = { __DRI_DRIVER_VTABLE, 1 },
345    .vtable = &nouveau_driver_api,
346 };
347 
348 /* This is the table of extensions that the loader will dlsym() for. */
349 static const __DRIextension *nouveau_driver_extensions[] = {
350 	&driCoreExtension.base,
351 	&driDRI2Extension.base,
352 	&nouveau_vtable.base,
353 	NULL
354 };
355 
__driDriverGetExtensions_nouveau_vieux(void)356 PUBLIC const __DRIextension **__driDriverGetExtensions_nouveau_vieux(void)
357 {
358    globalDriverAPI = &nouveau_driver_api;
359 
360    return nouveau_driver_extensions;
361 }
362