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