1 /* 2 * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #if sparc 27 28 /* #define DGA_DEBUG */ 29 30 #ifdef DGA_DEBUG 31 #define DEBUG_PRINT(x) printf x 32 #else 33 #define DEBUG_PRINT(x) 34 #endif 35 36 #include <dga/dga.h> 37 #include <unistd.h> /* ioctl */ 38 #include <stdlib.h> 39 #include <sys/mman.h> /* mmap */ 40 #include <sys/visual_io.h> 41 #include <string.h> 42 43 /* X11 */ 44 #include <X11/Xlib.h> 45 46 #include "jni.h" 47 #include "jvm_md.h" 48 #include "jdga.h" 49 #include "jdgadevice.h" 50 51 #include <dlfcn.h> 52 53 #define min(x, y) ((x) < (y) ? (x) : (y)) 54 #define max(x, y) ((x) > (y) ? (x) : (y)) 55 56 typedef struct _SolarisDgaLibInfo SolarisDgaLibInfo; 57 58 struct _SolarisDgaLibInfo { 59 /* The general (non-device specific) information */ 60 unsigned long count; 61 Drawable drawable; 62 Drawable virtual_drawable; 63 64 /* The device specific memory mapping information */ 65 SolarisJDgaDevInfo *devInfo; 66 SolarisJDgaWinInfo winInfo; 67 }; 68 69 typedef Bool IsXineramaOnFunc(Display *display); 70 typedef Drawable GetVirtualDrawableFunc(Display *display, Drawable drawable); 71 72 #define MAX_CACHED_INFO 16 73 static SolarisDgaLibInfo cachedInfo[MAX_CACHED_INFO]; 74 static jboolean needsSync = JNI_FALSE; 75 76 #define MAX_FB_TYPES 16 77 static SolarisJDgaDevInfo devicesInfo[MAX_FB_TYPES]; 78 79 static IsXineramaOnFunc *IsXineramaOn = NULL; 80 static GetVirtualDrawableFunc GetVirtualDrawableStub; 81 82 Drawable GetVirtualDrawableStub(Display *display, Drawable drawable) { 83 return drawable; 84 } 85 static GetVirtualDrawableFunc * GetVirtualDrawable = GetVirtualDrawableStub; 86 87 static void Solaris_DGA_XineramaInit(Display *display) { 88 void * handle = NULL; 89 if (IsXineramaOn == NULL) { 90 handle = dlopen(JNI_LIB_NAME("xinerama"), RTLD_NOW); 91 if (handle != NULL) { 92 void *sym = dlsym(handle, "IsXineramaOn"); 93 IsXineramaOn = (IsXineramaOnFunc *)sym; 94 if (IsXineramaOn != 0 && (*IsXineramaOn)(display)) { 95 sym = dlsym(handle, "GetVirtualDrawable"); 96 if (sym != 0) { 97 GetVirtualDrawable = (GetVirtualDrawableFunc *)sym; 98 } 99 } else { 100 dlclose(handle); 101 } 102 } 103 } 104 } 105 106 static SolarisJDgaDevInfo * getDevInfo(Dga_drawable dgadraw) { 107 void *handle = 0; 108 struct vis_identifier visid; 109 int fd; 110 char libName[64]; 111 int i; 112 SolarisJDgaDevInfo *curDevInfo = devicesInfo; 113 114 fd = dga_draw_devfd(dgadraw); 115 if (ioctl(fd, VIS_GETIDENTIFIER, &visid) != 1) { 116 /* check in the devices list */ 117 for (i = 0; (i < MAX_FB_TYPES) && (curDevInfo->visidName); 118 i++, curDevInfo++) { 119 if (strcmp(visid.name, curDevInfo->visidName) == 0) { 120 /* we already have such a device, return it */ 121 return curDevInfo; 122 } 123 } 124 if (i == MAX_FB_TYPES) { 125 /* we're out of slots, return NULL */ 126 return NULL; 127 } 128 129 strcpy(libName, "libjdga"); 130 strcat(libName, visid.name); 131 strcat(libName,".so"); 132 /* we use RTLD_NOW because of bug 4032715 */ 133 handle = dlopen(libName, RTLD_NOW); 134 if (handle != 0) { 135 JDgaStatus ret = JDGA_FAILED; 136 void *sym = dlsym(handle, "SolarisJDgaDevOpen"); 137 if (sym != 0) { 138 curDevInfo->majorVersion = JDGALIB_MAJOR_VERSION; 139 curDevInfo->minorVersion = JDGALIB_MINOR_VERSION; 140 ret = (*(SolarisJDgaDevOpenFunc *)sym)(curDevInfo); 141 } 142 if (ret == JDGA_SUCCESS) { 143 curDevInfo->visidName = strdup(visid.name); 144 return curDevInfo; 145 } 146 dlclose(handle); 147 } 148 } 149 return NULL; 150 } 151 static int 152 mmap_dgaDev(SolarisDgaLibInfo *libInfo, Dga_drawable dgadraw) 153 { 154 155 if (!libInfo->devInfo) { 156 libInfo->devInfo = getDevInfo(dgadraw); 157 if (!libInfo->devInfo) { 158 return JDGA_FAILED; 159 } 160 } 161 return (*libInfo->devInfo->function->winopen)(&(libInfo->winInfo)); 162 } 163 164 static void 165 unmap_dgaDev(SolarisDgaLibInfo *pDevInfo) 166 { 167 DEBUG_PRINT(("winclose() called\n")); 168 (*pDevInfo->devInfo->function->winclose)(&(pDevInfo->winInfo)); 169 } 170 171 static jboolean 172 Solaris_DGA_Available(Display *display) 173 { 174 Window root; 175 int screen; 176 Dga_drawable dgaDrawable; 177 SolarisJDgaDevInfo * devinfo; 178 179 /* return true if any screen supports DGA and we 180 have a library for this type of framebuffer */ 181 for (screen = 0; screen < XScreenCount(display); screen++) { 182 root = RootWindow(display, screen); 183 184 dgaDrawable = XDgaGrabDrawable(display, root); 185 if (dgaDrawable != 0) { 186 devinfo = getDevInfo(dgaDrawable); 187 XDgaUnGrabDrawable(dgaDrawable); 188 if (devinfo != NULL) { 189 return JNI_TRUE; 190 } 191 } 192 } 193 return JNI_FALSE; 194 } 195 196 static JDgaLibInitFunc Solaris_DGA_LibInit; 197 static JDgaGetLockFunc Solaris_DGA_GetLock; 198 static JDgaReleaseLockFunc Solaris_DGA_ReleaseLock; 199 static JDgaXRequestSentFunc Solaris_DGA_XRequestSent; 200 static JDgaLibDisposeFunc Solaris_DGA_LibDispose; 201 static int firstInitDone = 0; 202 203 #pragma weak JDgaLibInit = Solaris_DGA_LibInit 204 205 static JDgaStatus 206 Solaris_DGA_LibInit(JNIEnv *env, JDgaLibInfo *ppInfo) 207 { 208 /* Note: DGA_INIT can be called multiple times according to docs */ 209 DEBUG_PRINT(("DGA_INIT called\n")); 210 DGA_INIT(); 211 212 if (!Solaris_DGA_Available(ppInfo->display)) { 213 return JDGA_FAILED; 214 } 215 Solaris_DGA_XineramaInit(ppInfo->display); 216 217 ppInfo->pGetLock = Solaris_DGA_GetLock; 218 ppInfo->pReleaseLock = Solaris_DGA_ReleaseLock; 219 ppInfo->pXRequestSent = Solaris_DGA_XRequestSent; 220 ppInfo->pLibDispose = Solaris_DGA_LibDispose; 221 222 return JDGA_SUCCESS; 223 } 224 225 static JDgaStatus 226 Solaris_DGA_GetLock(JNIEnv *env, Display *display, void **dgaDev, 227 Drawable drawable, JDgaSurfaceInfo *pSurface, 228 jint lox, jint loy, jint hix, jint hiy) 229 { 230 SolarisDgaLibInfo *pDevInfo; 231 SolarisDgaLibInfo *pCachedInfo = cachedInfo; 232 int vis; 233 int dlox, dloy, dhix, dhiy; 234 int i; 235 int type, site; 236 unsigned long k; 237 Drawable prev_virtual_drawable = 0; 238 Dga_drawable dgaDrawable; 239 240 if (*dgaDev) { 241 if (((SolarisDgaLibInfo *)(*dgaDev))->drawable != drawable) { 242 *dgaDev = 0; 243 } 244 } 245 246 if (*dgaDev == 0) { 247 pCachedInfo = cachedInfo; 248 for (i = 0 ; (i < MAX_CACHED_INFO) && (pCachedInfo->drawable) ; 249 i++, pCachedInfo++) { 250 if (pCachedInfo->drawable == drawable) { 251 *dgaDev = pCachedInfo; 252 break; 253 } 254 } 255 if (*dgaDev == 0) { 256 if (i < MAX_CACHED_INFO) { /* slot can be used for new info */ 257 *dgaDev = pCachedInfo; 258 } else { 259 pCachedInfo = cachedInfo; 260 /* find the least used slot but does not handle an overflow of 261 the counter */ 262 for (i = 0, k = 0xffffffff; i < MAX_CACHED_INFO ; 263 i++, pCachedInfo++) { 264 if (k > pCachedInfo->count) { 265 k = pCachedInfo->count; 266 *dgaDev = pCachedInfo; 267 } 268 pCachedInfo->count = 0; /* reset all counters */ 269 } 270 pCachedInfo = *dgaDev; 271 if (pCachedInfo->winInfo.dgaDraw != 0) { 272 XDgaUnGrabDrawable(pCachedInfo->winInfo.dgaDraw); 273 } 274 pCachedInfo->winInfo.dgaDraw = 0; 275 /* the slot might be used for another device */ 276 pCachedInfo->devInfo = 0; 277 } 278 } 279 } 280 281 pDevInfo = *dgaDev; 282 pDevInfo->drawable = drawable; 283 284 prev_virtual_drawable = pDevInfo->virtual_drawable; 285 pDevInfo->virtual_drawable = GetVirtualDrawable(display, drawable); 286 if (pDevInfo->virtual_drawable == NULL) { 287 /* this usually means that the drawable is spanned across 288 screens in xinerama mode - we can't handle this for now */ 289 return JDGA_FAILED; 290 } else { 291 /* check if the drawable has been moved to another screen 292 since last time */ 293 if (pDevInfo->winInfo.dgaDraw != 0 && 294 pDevInfo->virtual_drawable != prev_virtual_drawable) { 295 XDgaUnGrabDrawable(pDevInfo->winInfo.dgaDraw); 296 pDevInfo->winInfo.dgaDraw = 0; 297 } 298 } 299 300 pDevInfo->count++; 301 302 if (pDevInfo->winInfo.dgaDraw == 0) { 303 pDevInfo->winInfo.dgaDraw = XDgaGrabDrawable(display, pDevInfo->virtual_drawable); 304 if (pDevInfo->winInfo.dgaDraw == 0) { 305 DEBUG_PRINT(("DgaGrabDrawable failed for 0x%08x\n", drawable)); 306 return JDGA_UNAVAILABLE; 307 } 308 type = dga_draw_type(pDevInfo->winInfo.dgaDraw); 309 if (type != DGA_DRAW_PIXMAP && 310 mmap_dgaDev(pDevInfo, pDevInfo->winInfo.dgaDraw) != JDGA_SUCCESS) { 311 DEBUG_PRINT(("memory map failed for 0x%08x (depth = %d)\n", 312 drawable, dga_draw_depth(pDevInfo->winInfo.dgaDraw))); 313 XDgaUnGrabDrawable(pDevInfo->winInfo.dgaDraw); 314 pDevInfo->winInfo.dgaDraw = 0; 315 return JDGA_UNAVAILABLE; 316 } 317 } else { 318 type = dga_draw_type(pDevInfo->winInfo.dgaDraw); 319 } 320 321 if (needsSync) { 322 XSync(display, False); 323 needsSync = JNI_FALSE; 324 } 325 326 dgaDrawable = pDevInfo->winInfo.dgaDraw; 327 328 DGA_DRAW_LOCK(dgaDrawable, -1); 329 330 site = dga_draw_site(dgaDrawable); 331 if (type == DGA_DRAW_PIXMAP) { 332 if (site == DGA_SITE_SYSTEM) { 333 pDevInfo->winInfo.mapDepth = dga_draw_depth(dgaDrawable); 334 pDevInfo->winInfo.mapAddr = dga_draw_address(dgaDrawable); 335 dga_draw_bbox(dgaDrawable, &dlox, &dloy, &dhix, &dhiy); 336 pDevInfo->winInfo.mapWidth = dhix; 337 pDevInfo->winInfo.mapHeight = dhiy; 338 if (pDevInfo->winInfo.mapDepth == 8) { 339 pDevInfo->winInfo.mapLineStride = dga_draw_linebytes(dgaDrawable); 340 pDevInfo->winInfo.mapPixelStride = 1; 341 } else { 342 pDevInfo->winInfo.mapLineStride = dga_draw_linebytes(dgaDrawable)/4; 343 pDevInfo->winInfo.mapPixelStride = 4; 344 } 345 } else { 346 XDgaUnGrabDrawable(dgaDrawable); 347 pDevInfo->winInfo.dgaDraw = 0; 348 return JDGA_UNAVAILABLE; 349 } 350 } else { 351 if (site == DGA_SITE_NULL) { 352 DEBUG_PRINT(("zombie drawable = 0x%08x\n", dgaDrawable)); 353 DGA_DRAW_UNLOCK(dgaDrawable); 354 unmap_dgaDev(pDevInfo); 355 XDgaUnGrabDrawable(dgaDrawable); 356 pDevInfo->winInfo.dgaDraw = 0; 357 return JDGA_UNAVAILABLE; 358 } 359 dga_draw_bbox(dgaDrawable, &dlox, &dloy, &dhix, &dhiy); 360 } 361 362 /* get the screen address of the drawable */ 363 dhix += dlox; 364 dhiy += dloy; 365 DEBUG_PRINT(("window at (%d, %d) => (%d, %d)\n", dlox, dloy, dhix, dhiy)); 366 pSurface->window.lox = dlox; 367 pSurface->window.loy = dloy; 368 pSurface->window.hix = dhix; 369 pSurface->window.hiy = dhiy; 370 371 /* translate rendering coordinates relative to device bbox */ 372 lox += dlox; 373 loy += dloy; 374 hix += dlox; 375 hiy += dloy; 376 DEBUG_PRINT(("render at (%d, %d) => (%d, %d)\n", lox, loy, hix, hiy)); 377 378 vis = dga_draw_visibility(dgaDrawable); 379 switch (vis) { 380 case DGA_VIS_UNOBSCURED: 381 pSurface->visible.lox = max(dlox, lox); 382 pSurface->visible.loy = max(dloy, loy); 383 pSurface->visible.hix = min(dhix, hix); 384 pSurface->visible.hiy = min(dhiy, hiy); 385 DEBUG_PRINT(("unobscured vis at (%d, %d) => (%d, %d)\n", 386 pSurface->visible.lox, 387 pSurface->visible.loy, 388 pSurface->visible.hix, 389 pSurface->visible.hiy)); 390 break; 391 case DGA_VIS_PARTIALLY_OBSCURED: { 392 /* 393 * fix for #4305271 394 * the dga_draw_clipinfo call returns the clipping bounds 395 * in short ints, but use only full size ints for all comparisons. 396 */ 397 short *ptr; 398 int x0, y0, x1, y1; 399 int cliplox, cliploy, cliphix, cliphiy; 400 401 /* 402 * iterate to find out whether the clipped blit draws to a 403 * single clipping rectangle 404 */ 405 cliplox = cliphix = lox; 406 cliploy = cliphiy = loy; 407 ptr = dga_draw_clipinfo(dgaDrawable); 408 while (*ptr != DGA_Y_EOL) { 409 y0 = *ptr++; 410 y1 = *ptr++; 411 DEBUG_PRINT(("DGA y range loy=%d hiy=%d\n", y0, y1)); 412 if (y0 < loy) { 413 y0 = loy; 414 } 415 if (y1 > hiy) { 416 y1 = hiy; 417 } 418 while (*ptr != DGA_X_EOL) { 419 x0 = *ptr++; 420 x1 = *ptr++; 421 DEBUG_PRINT((" DGA x range lox=%d hix=%d\n", x0, x1)); 422 if (x0 < lox) { 423 x0 = lox; 424 } 425 if (x1 > hix) { 426 x1 = hix; 427 } 428 if (x0 < x1 && y0 < y1) { 429 if (cliploy == cliphiy) { 430 /* First rectangle intersection */ 431 cliplox = x0; 432 cliploy = y0; 433 cliphix = x1; 434 cliphiy = y1; 435 } else { 436 /* Can we merge this rect with previous? */ 437 if (cliplox == x0 && cliphix == x1 && 438 cliploy <= y1 && cliphiy >= y0) 439 { 440 /* X ranges match, Y ranges touch */ 441 /* => absorb the Y ranges together */ 442 cliploy = min(cliploy, y0); 443 cliphiy = max(cliphiy, y1); 444 } else if (cliploy == y0 && cliphiy == y1 && 445 cliplox <= x1 && cliphix >= x0) 446 { 447 /* Y ranges match, X ranges touch */ 448 /* => Absorb the X ranges together */ 449 cliplox = min(cliplox, x0); 450 cliphix = max(cliphix, x1); 451 } else { 452 /* Assertion: any other combination */ 453 /* means non-rectangular intersect */ 454 DGA_DRAW_UNLOCK(dgaDrawable); 455 return JDGA_FAILED; 456 } 457 } 458 } 459 } 460 ptr++; /* advance past DGA_X_EOL */ 461 } 462 DEBUG_PRINT(("DGA drawable fits\n")); 463 pSurface->visible.lox = cliplox; 464 pSurface->visible.loy = cliploy; 465 pSurface->visible.hix = cliphix; 466 pSurface->visible.hiy = cliphiy; 467 break; 468 } 469 case DGA_VIS_FULLY_OBSCURED: 470 pSurface->visible.lox = 471 pSurface->visible.hix = lox; 472 pSurface->visible.loy = 473 pSurface->visible.hiy = loy; 474 DEBUG_PRINT(("fully obscured vis\n")); 475 break; 476 default: 477 DEBUG_PRINT(("unknown visibility = %d!\n", vis)); 478 DGA_DRAW_UNLOCK(dgaDrawable); 479 return JDGA_FAILED; 480 } 481 482 pSurface->basePtr = pDevInfo->winInfo.mapAddr; 483 pSurface->surfaceScan = pDevInfo->winInfo.mapLineStride; 484 pSurface->surfaceWidth = pDevInfo->winInfo.mapWidth; 485 pSurface->surfaceHeight = pDevInfo->winInfo.mapHeight; 486 pSurface->surfaceDepth = pDevInfo->winInfo.mapDepth; 487 488 return JDGA_SUCCESS; 489 } 490 491 static JDgaStatus 492 Solaris_DGA_ReleaseLock(JNIEnv *env, void *dgaDev, Drawable drawable) 493 { 494 SolarisDgaLibInfo *pDevInfo = (SolarisDgaLibInfo *) dgaDev; 495 496 if (pDevInfo != 0 && pDevInfo->drawable == drawable && 497 pDevInfo->winInfo.dgaDraw != 0) { 498 DGA_DRAW_UNLOCK(pDevInfo->winInfo.dgaDraw); 499 } 500 return JDGA_SUCCESS; 501 } 502 503 static void 504 Solaris_DGA_XRequestSent(JNIEnv *env, void *dgaDev, Drawable drawable) 505 { 506 needsSync = JNI_TRUE; 507 } 508 509 static void 510 Solaris_DGA_LibDispose(JNIEnv *env) 511 { 512 SolarisDgaLibInfo *pCachedInfo = cachedInfo; 513 SolarisJDgaDevInfo *curDevInfo = devicesInfo; 514 int i; 515 516 for (i = 0 ; (i < MAX_CACHED_INFO) && (pCachedInfo->drawable) ; 517 i++, pCachedInfo++) { 518 if (pCachedInfo->winInfo.dgaDraw != 0) { 519 if (dga_draw_type(pCachedInfo->winInfo.dgaDraw) == DGA_DRAW_WINDOW && 520 pCachedInfo->winInfo.mapDepth != 0) { 521 unmap_dgaDev(pCachedInfo); 522 } 523 XDgaUnGrabDrawable(pCachedInfo->winInfo.dgaDraw); 524 pCachedInfo->winInfo.dgaDraw = 0; 525 } 526 } 527 for (i = 0; (i < MAX_FB_TYPES) && (curDevInfo->visidName); 528 i++, curDevInfo++) { 529 curDevInfo->function->devclose(curDevInfo); 530 free(curDevInfo->visidName); 531 } 532 } 533 #endif