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
46static const __DRIextension *nouveau_screen_extensions[];
47
48static void
49nouveau_destroy_screen(__DRIscreen *dri_screen);
50
51static const __DRIconfig **
52nouveau_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		GLX_NONE, GLX_SWAP_UNDEFINED_OML
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
90static const __DRIconfig **
91nouveau_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;
152fail:
153	nouveau_destroy_screen(dri_screen);
154	return NULL;
155
156}
157
158static int
159nouveau_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
196static int
197nouveau_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
214static 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
221static void
222nouveau_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
236static GLboolean
237nouveau_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_add_renderbuffer(fb, BUFFER_FRONT_LEFT, rb);
263
264	/* Back buffer */
265	if (visual->doubleBufferMode) {
266		rb = nouveau_renderbuffer_dri_new(color_format, drawable);
267		_mesa_add_renderbuffer(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_add_renderbuffer(fb, BUFFER_DEPTH, rb);
274		_mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
275
276	} else if (visual->depthBits == 24) {
277		rb = nouveau_renderbuffer_dri_new(GL_DEPTH_COMPONENT24, drawable);
278		_mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
279
280	} else if (visual->depthBits == 16) {
281		rb = nouveau_renderbuffer_dri_new(GL_DEPTH_COMPONENT16, drawable);
282		_mesa_add_renderbuffer(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
295static void
296nouveau_destroy_buffer(__DRIdrawable *drawable)
297{
298	_mesa_reference_framebuffer(
299		(struct gl_framebuffer **)&drawable->driverPrivate, NULL);
300}
301
302static void
303nouveau_drawable_flush(__DRIdrawable *draw)
304{
305}
306
307static const struct __DRI2flushExtensionRec nouveau_flush_extension = {
308   .base = { __DRI2_FLUSH, 3 },
309
310   .flush               = nouveau_drawable_flush,
311   .invalidate          = dri2InvalidateDrawable,
312};
313
314static 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
322static 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    NULL
328};
329
330const struct __DriverAPIRec nouveau_driver_api = {
331	.InitScreen      = nouveau_init_screen2,
332	.DestroyScreen   = nouveau_destroy_screen,
333	.CreateBuffer    = nouveau_create_buffer,
334	.DestroyBuffer   = nouveau_destroy_buffer,
335	.CreateContext   = nouveau_context_create,
336	.DestroyContext  = nouveau_context_destroy,
337	.MakeCurrent     = nouveau_context_make_current,
338	.UnbindContext   = nouveau_context_unbind,
339};
340
341static const struct __DRIDriverVtableExtensionRec nouveau_vtable = {
342   .base = { __DRI_DRIVER_VTABLE, 1 },
343   .vtable = &nouveau_driver_api,
344};
345
346/* This is the table of extensions that the loader will dlsym() for. */
347static const __DRIextension *nouveau_driver_extensions[] = {
348	&driCoreExtension.base,
349	&driDRI2Extension.base,
350	&nouveau_vtable.base,
351	NULL
352};
353
354PUBLIC const __DRIextension **__driDriverGetExtensions_nouveau_vieux(void)
355{
356   globalDriverAPI = &nouveau_driver_api;
357
358   return nouveau_driver_extensions;
359}
360