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