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