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
GetVirtualDrawableStub(Display * display,Drawable drawable)82 Drawable GetVirtualDrawableStub(Display *display, Drawable drawable) {
83 return drawable;
84 }
85 static GetVirtualDrawableFunc * GetVirtualDrawable = GetVirtualDrawableStub;
86
Solaris_DGA_XineramaInit(Display * display)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
getDevInfo(Dga_drawable dgadraw)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
mmap_dgaDev(SolarisDgaLibInfo * libInfo,Dga_drawable dgadraw)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
unmap_dgaDev(SolarisDgaLibInfo * pDevInfo)165 unmap_dgaDev(SolarisDgaLibInfo *pDevInfo)
166 {
167 DEBUG_PRINT(("winclose() called\n"));
168 (*pDevInfo->devInfo->function->winclose)(&(pDevInfo->winInfo));
169 }
170
171 static jboolean
Solaris_DGA_Available(Display * display)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
Solaris_DGA_LibInit(JNIEnv * env,JDgaLibInfo * ppInfo)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
Solaris_DGA_GetLock(JNIEnv * env,Display * display,void ** dgaDev,Drawable drawable,JDgaSurfaceInfo * pSurface,jint lox,jint loy,jint hix,jint hiy)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
Solaris_DGA_ReleaseLock(JNIEnv * env,void * dgaDev,Drawable drawable)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
Solaris_DGA_XRequestSent(JNIEnv * env,void * dgaDev,Drawable drawable)504 Solaris_DGA_XRequestSent(JNIEnv *env, void *dgaDev, Drawable drawable)
505 {
506 needsSync = JNI_TRUE;
507 }
508
509 static void
Solaris_DGA_LibDispose(JNIEnv * env)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
534