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
47static const __DRIextension *nouveau_screen_extensions[];
48
49static void
50nouveau_destroy_screen(__DRIscreen *dri_screen);
51
52static const __DRIconfig **
53nouveau_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
91static const __DRIconfig **
92nouveau_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;
153fail:
154	nouveau_destroy_screen(dri_screen);
155	return NULL;
156
157}
158
159static int
160nouveau_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
197static int
198nouveau_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
215static 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
222static void
223nouveau_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
237static GLboolean
238nouveau_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
296static void
297nouveau_destroy_buffer(__DRIdrawable *drawable)
298{
299	_mesa_reference_framebuffer(
300		(struct gl_framebuffer **)&drawable->driverPrivate, NULL);
301}
302
303static void
304nouveau_drawable_flush(__DRIdrawable *draw)
305{
306}
307
308static const struct __DRI2flushExtensionRec nouveau_flush_extension = {
309   .base = { __DRI2_FLUSH, 3 },
310
311   .flush               = nouveau_drawable_flush,
312   .invalidate          = dri2InvalidateDrawable,
313};
314
315static 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
323static 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
332const 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
343static 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. */
349static const __DRIextension *nouveau_driver_extensions[] = {
350	&driCoreExtension.base,
351	&driDRI2Extension.base,
352	&nouveau_vtable.base,
353	NULL
354};
355
356PUBLIC const __DRIextension **__driDriverGetExtensions_nouveau_vieux(void)
357{
358   globalDriverAPI = &nouveau_driver_api;
359
360   return nouveau_driver_extensions;
361}
362