Home | History | Annotate | Download | only in nouveau
      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 **
     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 		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 
     90 static const __DRIconfig **
     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
    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
    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
    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
    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_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 
    295 static void
    296 nouveau_destroy_buffer(__DRIdrawable *drawable)
    297 {
    298 	_mesa_reference_framebuffer(
    299 		(struct gl_framebuffer **)&drawable->driverPrivate, NULL);
    300 }
    301 
    302 static void
    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     NULL
    328 };
    329 
    330 const 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 
    341 static 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. */
    347 static const __DRIextension *nouveau_driver_extensions[] = {
    348 	&driCoreExtension.base,
    349 	&driDRI2Extension.base,
    350 	&nouveau_vtable.base,
    351 	NULL
    352 };
    353 
    354 PUBLIC const __DRIextension **__driDriverGetExtensions_nouveau_vieux(void)
    355 {
    356    globalDriverAPI = &nouveau_driver_api;
    357 
    358    return nouveau_driver_extensions;
    359 }
    360