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