xorg_crtc.c revision c7c1e5338cd4d47168fd2654ae951955578bef8d
1/* 2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * 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, sub license, 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 portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * 26 * Author: Alan Hourihane <alanh@tungstengraphics.com> 27 * Author: Jakob Bornecrantz <wallbraker@gmail.com> 28 * 29 */ 30 31#include <unistd.h> 32#include <string.h> 33#include <assert.h> 34#include <stdlib.h> 35#include <math.h> 36#include <stdint.h> 37 38#include "xorg-server.h" 39#include <xf86.h> 40#include <xf86i2c.h> 41#include <xf86Crtc.h> 42#include <cursorstr.h> 43#include "xorg_tracker.h" 44#include "xf86Modes.h" 45 46#ifdef HAVE_XEXTPROTO_71 47#include <X11/extensions/dpmsconst.h> 48#else 49#define DPMS_SERVER 50#include <X11/extensions/dpms.h> 51#endif 52 53#include "state_tracker/drm_driver.h" 54#include "util/u_inlines.h" 55#include "util/u_rect.h" 56 57#ifdef HAVE_LIBKMS 58#include "libkms.h" 59#endif 60 61struct crtc_private 62{ 63 drmModeCrtcPtr drm_crtc; 64 65 /* hwcursor */ 66 struct pipe_resource *cursor_tex; 67 struct kms_bo *cursor_bo; 68 69 unsigned cursor_handle; 70}; 71 72static void 73crtc_dpms(xf86CrtcPtr crtc, int mode) 74{ 75 /* ScrnInfoPtr pScrn = crtc->scrn; */ 76 77 switch (mode) { 78 case DPMSModeOn: 79 case DPMSModeStandby: 80 case DPMSModeSuspend: 81 break; 82 case DPMSModeOff: 83 break; 84 } 85} 86 87static Bool 88crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 89 Rotation rotation, int x, int y) 90{ 91 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 92 modesettingPtr ms = modesettingPTR(crtc->scrn); 93 xf86OutputPtr output = NULL; 94 struct crtc_private *crtcp = crtc->driver_private; 95 drmModeCrtcPtr drm_crtc = crtcp->drm_crtc; 96 drmModeModeInfo drm_mode; 97 int i, ret; 98 unsigned int connector_id; 99 100 for (i = 0; i < config->num_output; output = NULL, i++) { 101 output = config->output[i]; 102 103 if (output->crtc == crtc) 104 break; 105 } 106 107 if (!output) 108 return FALSE; 109 110 connector_id = xorg_output_get_id(output); 111 112 drm_mode.clock = mode->Clock; 113 drm_mode.hdisplay = mode->HDisplay; 114 drm_mode.hsync_start = mode->HSyncStart; 115 drm_mode.hsync_end = mode->HSyncEnd; 116 drm_mode.htotal = mode->HTotal; 117 drm_mode.vdisplay = mode->VDisplay; 118 drm_mode.vsync_start = mode->VSyncStart; 119 drm_mode.vsync_end = mode->VSyncEnd; 120 drm_mode.vtotal = mode->VTotal; 121 drm_mode.flags = mode->Flags; 122 drm_mode.hskew = mode->HSkew; 123 drm_mode.vscan = mode->VScan; 124 drm_mode.vrefresh = mode->VRefresh; 125 if (!mode->name) 126 xf86SetModeDefaultName(mode); 127 strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1); 128 drm_mode.name[DRM_DISPLAY_MODE_LEN - 1] = '\0'; 129 130 ret = drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, ms->fb_id, x, y, 131 &connector_id, 1, &drm_mode); 132 133 if (ret) 134 return FALSE; 135 136 /* Only set gamma when needed, to avoid unneeded delays. */ 137#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 138 if (!crtc->active) 139#endif 140 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 141 crtc->gamma_blue, crtc->gamma_size); 142 143#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 144 crtc->active = TRUE; 145#endif 146 crtc->x = x; 147 crtc->y = y; 148 crtc->mode = *mode; 149 crtc->rotation = rotation; 150 151 return TRUE; 152} 153 154static void 155crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue, 156 int size) 157{ 158 modesettingPtr ms = modesettingPTR(crtc->scrn); 159 struct crtc_private *crtcp = crtc->driver_private; 160 161 drmModeCrtcSetGamma(ms->fd, crtcp->drm_crtc->crtc_id, size, red, green, blue); 162} 163 164#if 0 /* Implement and enable to enable rotation and reflection. */ 165static void * 166crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 167{ 168 /* ScrnInfoPtr pScrn = crtc->scrn; */ 169 170 return NULL; 171} 172 173static PixmapPtr 174crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 175{ 176 /* ScrnInfoPtr pScrn = crtc->scrn; */ 177 178 return NULL; 179} 180 181static void 182crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 183{ 184 /* ScrnInfoPtr pScrn = crtc->scrn; */ 185} 186 187#endif 188 189/* 190 * Cursor functions 191 */ 192 193static void 194crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 195{ 196 /* XXX: See if this one is needed, as we only support ARGB cursors */ 197} 198 199static void 200crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 201{ 202 modesettingPtr ms = modesettingPTR(crtc->scrn); 203 struct crtc_private *crtcp = crtc->driver_private; 204 205 drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y); 206} 207 208static void 209crtc_load_cursor_argb_ga3d(xf86CrtcPtr crtc, CARD32 * image) 210{ 211 unsigned char *ptr; 212 modesettingPtr ms = modesettingPTR(crtc->scrn); 213 struct crtc_private *crtcp = crtc->driver_private; 214 struct pipe_transfer *transfer; 215 216 if (!crtcp->cursor_tex) { 217 struct pipe_resource templat; 218 struct winsys_handle whandle; 219 220 memset(&templat, 0, sizeof(templat)); 221 templat.bind |= PIPE_BIND_RENDER_TARGET; 222 templat.bind |= PIPE_BIND_SCANOUT; 223 templat.target = PIPE_TEXTURE_2D; 224 templat.last_level = 0; 225 templat.depth0 = 1; 226 templat.array_size = 1; 227 templat.format = PIPE_FORMAT_B8G8R8A8_UNORM; 228 templat.width0 = 64; 229 templat.height0 = 64; 230 231 memset(&whandle, 0, sizeof(whandle)); 232 whandle.type = DRM_API_HANDLE_TYPE_KMS; 233 234 crtcp->cursor_tex = ms->screen->resource_create(ms->screen, 235 &templat); 236 ms->screen->resource_get_handle(ms->screen, crtcp->cursor_tex, &whandle); 237 238 crtcp->cursor_handle = whandle.handle; 239 } 240 241 transfer = pipe_get_transfer(ms->ctx, crtcp->cursor_tex, 242 0, 0, 243 PIPE_TRANSFER_WRITE, 244 0, 0, 64, 64); 245 ptr = ms->ctx->transfer_map(ms->ctx, transfer); 246 util_copy_rect(ptr, crtcp->cursor_tex->format, 247 transfer->stride, 0, 0, 248 64, 64, (void*)image, 64 * 4, 0, 0); 249 ms->ctx->transfer_unmap(ms->ctx, transfer); 250 ms->ctx->transfer_destroy(ms->ctx, transfer); 251 252 if (crtc->cursor_shown) 253 drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 254 crtcp->cursor_handle, 64, 64); 255} 256 257#if HAVE_LIBKMS 258static void 259crtc_load_cursor_argb_kms(xf86CrtcPtr crtc, CARD32 * image) 260{ 261 modesettingPtr ms = modesettingPTR(crtc->scrn); 262 struct crtc_private *crtcp = crtc->driver_private; 263 unsigned char *ptr; 264 265 if (!crtcp->cursor_bo) { 266 unsigned attr[8]; 267 268 attr[0] = KMS_BO_TYPE; 269#ifdef KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8 270 attr[1] = KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8; 271#else 272 attr[1] = KMS_BO_TYPE_CURSOR; 273#endif 274 attr[2] = KMS_WIDTH; 275 attr[3] = 64; 276 attr[4] = KMS_HEIGHT; 277 attr[5] = 64; 278 attr[6] = 0; 279 280 if (kms_bo_create(ms->kms, attr, &crtcp->cursor_bo)) 281 return; 282 283 if (kms_bo_get_prop(crtcp->cursor_bo, KMS_HANDLE, 284 &crtcp->cursor_handle)) 285 goto err_bo_destroy; 286 } 287 288 kms_bo_map(crtcp->cursor_bo, (void**)&ptr); 289 memcpy(ptr, image, 64*64*4); 290 kms_bo_unmap(crtcp->cursor_bo); 291 292 if (crtc->cursor_shown) 293 drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 294 crtcp->cursor_handle, 64, 64); 295 296 return; 297 298err_bo_destroy: 299 kms_bo_destroy(&crtcp->cursor_bo); 300} 301#endif 302 303static void 304crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 305{ 306 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 307 modesettingPtr ms = modesettingPTR(crtc->scrn); 308 309 /* Older X servers have cursor reference counting bugs leading to use of 310 * freed memory and consequently random crashes. Should be fixed as of 311 * xserver 1.8, but this workaround shouldn't hurt anyway. 312 */ 313 if (config->cursor) 314 config->cursor->refcnt++; 315 316 if (ms->cursor) 317 FreeCursor(ms->cursor, None); 318 319 ms->cursor = config->cursor; 320 321 if (ms->screen) 322 crtc_load_cursor_argb_ga3d(crtc, image); 323#ifdef HAVE_LIBKMS 324 else if (ms->kms) 325 crtc_load_cursor_argb_kms(crtc, image); 326#endif 327} 328 329static void 330crtc_show_cursor(xf86CrtcPtr crtc) 331{ 332 modesettingPtr ms = modesettingPTR(crtc->scrn); 333 struct crtc_private *crtcp = crtc->driver_private; 334 335 if (crtcp->cursor_tex || crtcp->cursor_bo) 336 drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 337 crtcp->cursor_handle, 64, 64); 338} 339 340static void 341crtc_hide_cursor(xf86CrtcPtr crtc) 342{ 343 modesettingPtr ms = modesettingPTR(crtc->scrn); 344 struct crtc_private *crtcp = crtc->driver_private; 345 346 drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0); 347} 348 349/** 350 * Called at vt leave 351 */ 352void 353xorg_crtc_cursor_destroy(xf86CrtcPtr crtc) 354{ 355 struct crtc_private *crtcp = crtc->driver_private; 356 357 if (crtcp->cursor_tex) 358 pipe_resource_reference(&crtcp->cursor_tex, NULL); 359#ifdef HAVE_LIBKMS 360 if (crtcp->cursor_bo) 361 kms_bo_destroy(&crtcp->cursor_bo); 362#endif 363} 364 365/* 366 * Misc functions 367 */ 368 369static void 370crtc_destroy(xf86CrtcPtr crtc) 371{ 372 struct crtc_private *crtcp = crtc->driver_private; 373 374 xorg_crtc_cursor_destroy(crtc); 375 376 drmModeFreeCrtc(crtcp->drm_crtc); 377 378 free(crtcp); 379 crtc->driver_private = NULL; 380} 381 382static const xf86CrtcFuncsRec crtc_funcs = { 383 .dpms = crtc_dpms, 384 .set_mode_major = crtc_set_mode_major, 385 386 .set_cursor_colors = crtc_set_cursor_colors, 387 .set_cursor_position = crtc_set_cursor_position, 388 .show_cursor = crtc_show_cursor, 389 .hide_cursor = crtc_hide_cursor, 390 .load_cursor_argb = crtc_load_cursor_argb, 391 392 .shadow_create = NULL, 393 .shadow_allocate = NULL, 394 .shadow_destroy = NULL, 395 396 .gamma_set = crtc_gamma_set, 397 .destroy = crtc_destroy, 398}; 399 400void 401xorg_crtc_init(ScrnInfoPtr pScrn) 402{ 403 modesettingPtr ms = modesettingPTR(pScrn); 404 xf86CrtcPtr crtc; 405 drmModeResPtr res; 406 drmModeCrtcPtr drm_crtc = NULL; 407 struct crtc_private *crtcp; 408 int c; 409 410 res = drmModeGetResources(ms->fd); 411 if (res == 0) { 412 ErrorF("Failed drmModeGetResources %d\n", errno); 413 return; 414 } 415 416 for (c = 0; c < res->count_crtcs; c++) { 417 drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]); 418 419 if (!drm_crtc) 420 continue; 421 422 crtc = xf86CrtcCreate(pScrn, &crtc_funcs); 423 if (crtc == NULL) 424 goto out; 425 426 crtcp = calloc(1, sizeof(struct crtc_private)); 427 if (!crtcp) { 428 xf86CrtcDestroy(crtc); 429 goto out; 430 } 431 432 crtcp->drm_crtc = drm_crtc; 433 434 crtc->driver_private = crtcp; 435 } 436 437 out: 438 drmModeFreeResources(res); 439} 440 441/* vim: set sw=4 ts=8 sts=4: */ 442