1 /* Copyright (c) 1993, 1999, Oracle and/or its affiliates. All rights reserved.
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice (including the next
11 * paragraph) shall be included in all copies or substantial portions of the
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
25 * dga_db.c - the client side code for DGA double buffering
30 #include <sys/types.h>
38 #define FBIOVRTOFFSET (FIOC | 38)
40 #define FBIOVRTOFFSET _IOR(F, 38, int)
48 #include "dga_incls.h"
50 #define DGA_WIN_LOCK_NOMODIF(win) \
52 if ((((_Dga_window)(win))->w_lockcnt)++ == 0) { \
57 #define DGA_WIN_UNLOCK_NOMODIF(win) \
59 if (--(((_Dga_window)(win))->w_lockcnt) == 0) \
63 extern void *_dga_is_X_window(Dga_token token
, Display
**dpyp
, Window
*winp
);
66 static int _dga_db_vrtfunc_internal(Dga_window
);
69 static int _dga_db_vrtfunc_internal(Dga_window
);
71 static int _dga_db_vrtfunc_internal();
75 static u_int
*dga_vrt_access();
76 static void dga_vrt_release();
79 dga_db_access(wg_clientpi
)
80 Dga_window wg_clientpi
;
82 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
83 WXINFO
*infop
= wx_infop(wg_clientp
) ;
85 u_int
*dga_vrt_access();
87 if (wg_clientp
->db_enabled
)
89 if (infop
->wx_dbuf
.number_buffers
< 2)
92 cpage
= dga_vrt_access(wg_clientp
->w_devfd
);
96 wg_clientp
->db_enabled
= 1;
97 wg_clientp
->db_vrtcntrp
= cpage
;
98 wg_clientp
->db_lastvrtcntr
= *cpage
;
99 wg_clientp
->db_swapint
= 1;
100 wg_clientp
->vrt_func
= _dga_db_vrtfunc_internal
;
101 if ((infop
->wx_dbuf
.display_buffer
< 0) ||
102 (infop
->wx_dbuf
.display_buffer
> (infop
->wx_dbuf
.number_buffers
- 1)))
103 infop
->wx_dbuf
.display_buffer
= 0;
104 if ((infop
->wx_dbuf
.read_buffer
< 0) ||
105 (infop
->wx_dbuf
.read_buffer
> (infop
->wx_dbuf
.number_buffers
- 1)))
106 infop
->wx_dbuf
.read_buffer
= 1;
107 if ((infop
->wx_dbuf
.write_buffer
< 0) ||
108 (infop
->wx_dbuf
.write_buffer
> (infop
->wx_dbuf
.number_buffers
- 1)))
109 infop
->wx_dbuf
.write_buffer
= 1;
117 dga_db_release(wg_clientpi
)
118 Dga_window wg_clientpi
;
120 void dga_vrt_release();
121 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
123 if (wg_clientp
->db_vrtcntrp
)
124 dga_vrt_release(wg_clientp
->db_vrtcntrp
);
125 wg_clientp
->db_enabled
= 0;
131 dga_db_write(wg_clientpi
,buffer
,writefunc
,data
)
132 Dga_window wg_clientpi
;
135 int (*writefunc
)(void*, Dga_window
, int);
137 #if defined (__STDC__)
138 int (*writefunc
)(void*, Dga_window
, int);
145 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
147 DGA_WIN_LOCK_NOMODIF(wg_clientp
);
149 (*writefunc
) (data
,wg_clientpi
,buffer
);
150 wx_infop(wg_clientp
)->wx_dbuf
.write_buffer
= buffer
;
151 DGA_WIN_UNLOCK_NOMODIF(wg_clientp
);
155 dga_db_read(wg_clientpi
,buffer
,readfunc
,data
)
156 Dga_window wg_clientpi
;
159 int (*readfunc
)(void*, Dga_window
, int);
161 #if defined (__STDC__)
162 int (*readfunc
)(void*, Dga_window
, int);
169 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
171 DGA_WIN_LOCK_NOMODIF(wg_clientp
);
172 wx_infop(wg_clientp
)->wx_dbuf
.read_buffer
= buffer
;
174 (*readfunc
) (data
,wg_clientpi
,buffer
);
175 DGA_WIN_UNLOCK_NOMODIF(wg_clientp
);
180 dga_db_display(wg_clientpi
,buffer
,visfunc
,data
)
181 Dga_window wg_clientpi
;
184 int (*visfunc
)(void*, Dga_window
, int);
186 #if defined (__STDC__)
187 int (*visfunc
)(void*, Dga_window
, int);
194 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
196 if (!dga_db_interval_check(wg_clientpi
))
197 dga_db_interval_wait(wg_clientpi
);
199 (*visfunc
)(data
, wg_clientpi
, buffer
);
200 if (wg_clientp
->db_vrtcntrp
)
201 wg_clientp
->db_lastvrtcntr
= *wg_clientp
->db_vrtcntrp
;
202 wx_infop(wg_clientp
)->wx_dbuf
.display_buffer
= buffer
;
206 dga_db_interval(wg_clientpi
,interval
)
207 Dga_window wg_clientpi
;
208 int interval
; /* number of milliseconds */
212 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
214 ref_rate
= wx_infop(wg_clientp
)->w_refresh_period
;
215 if (ref_rate
== 0) ref_rate
= 66000;
219 if (interval
> ref_rate
)
221 rr
= ((float)ref_rate
)* 0.001;
222 wg_clientp
->db_swapint
= rr
* ((float)interval
* 0.001);
224 if (wg_clientp
->db_swapint
== 0)
225 wg_clientp
->db_swapint
= 1;
230 dga_db_interval_wait(wg_clientpi
)
231 Dga_window wg_clientpi
;
233 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
234 u_int
*counter
= wg_clientp
->db_vrtcntrp
;
236 /* Do a block if necessary and if vrt_func has been supplied */
238 if (!wg_clientp
->vrt_func
|| !wg_clientp
->db_vrtcntrp
) return;
240 while (((u_int
) (*counter
- wg_clientp
->db_lastvrtcntr
))
241 < wg_clientp
->db_swapint
)
243 if ((*(wg_clientp
->vrt_func
))(wg_clientpi
) < 0) return ;;
249 dga_db_interval_check(wg_clientpi
)
250 Dga_window wg_clientpi
;
252 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
253 u_int
*counter
= wg_clientp
->db_vrtcntrp
;
255 if ((wg_clientp
->db_vrtcntrp
) &&
256 ((u_int
) (*counter
- wg_clientp
->db_lastvrtcntr
))
257 < wg_clientp
->db_swapint
)
264 dga_db_write_inquire(wg_clientpi
)
265 Dga_window wg_clientpi
;
267 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
268 return(wx_infop(wg_clientp
)->wx_dbuf
.write_buffer
);
272 dga_db_read_inquire(wg_clientpi
)
273 Dga_window wg_clientpi
;
275 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
277 return(wx_infop(wg_clientp
)->wx_dbuf
.read_buffer
);
281 dga_db_display_inquire(wg_clientpi
)
282 Dga_window wg_clientpi
;
284 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
285 return(wx_infop(wg_clientp
)->wx_dbuf
.display_buffer
);
288 /* INTERNAL INTERFACE */
290 dga_db_display_complete(wg_clientpi
, flag
)
291 Dga_window wg_clientpi
;
294 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
295 if (wg_clientp
->db_vrtcntrp
&&
296 (wg_clientp
->db_lastvrtcntr
!= *(wg_clientp
->db_vrtcntrp
)))
300 if (ioctl(wg_clientp
->w_devfd
,FBIOVERTICAL
,0) < 0)
305 /* INTERNAL INTERFACE */
307 *dga_vrt_access(devfd
)
315 if (ioctl(devfd
, FBIOVRTOFFSET
, &dev_offset
) < 0)
319 pagesize
= sysconf(_SC_PAGESIZE
);
321 pagesize
= getpagesize();
325 * the driver provides the dev_offset into the mmaped page
326 * where the vertical retrace counter word is.
327 * We will mmap a shared memory page that is on a
328 * page boundary then modify the pointer to the
329 * vertical retrace counter to reflect the exact
330 * location where the counter word exists
333 cpage
= (u_int
*) mmap((char *)0,
335 PROT_READ
| PROT_WRITE
,
336 MAP_SHARED
| _MAP_NEW
,
338 (off_t
) (dev_offset
& ~(pagesize
- 1)));
340 /* if the mmap failed then return NULL otherwide return
341 * the computed address of the vertical retract counter
342 * by adding the beginning of the mmaped page to the
343 * dev_offset into the page returned by the device driver
346 if (cpage
== (u_int
*) -1)
349 return ((u_int
*) ((int) cpage
| (dev_offset
& (pagesize
- 1))));
353 dga_vrt_release(counter
)
360 pagesize
= sysconf(_SC_PAGESIZE
);
362 pagesize
= getpagesize();
365 /* Unmap the page for this client.
366 * remove the offset computation and munmap the
367 * vertical retrace counter page. we remove the
368 * offset by simply setting the lower bits of
372 counter_page
= (char *) (((int) counter
) & (~(pagesize
- 1)));
373 munmap(counter_page
, pagesize
) ;
377 /* New routines that will be exposed to the public */
380 dga_db_display_done(wg_clientpi
,flag
, display_done_func
)
381 Dga_window wg_clientpi
;
384 int (*display_done_func
)(Dga_window
);
386 int (*vrt_func
)(Dga_window
);
388 #if defined (__STDC__)
389 int (*display_done_func
)(Dga_window
);
391 int (*display_done_func
)();
394 #if defined (__STDC__)
395 int (*vrt_func
)(Dga_window
);
400 _Dga_window wg_clientp
= (struct dga_window
*)wg_clientpi
;
403 /* Return 1 = done, 0 = not done, -1 = error */
404 ret_val
= (*display_done_func
)(wg_clientpi
);
406 /* If the user does not want to block or if the
407 * display_done_func() returned a non-zero, we return
408 * else we try till success after each vrt_retrace()
410 if ((!flag
) || (ret_val
!= 0))
413 vrt_func
= wg_clientp
->vrt_func
;
414 if (!vrt_func
) return 1;
416 while((ret_val
= (*display_done_func
)(wg_clientpi
)) == 0)
417 if (vrt_func(wg_clientpi
) < 0) return -1;
421 /* Returns 0 on fail and non-zero on success */
423 dga_db_grab(clientpi
, nbuffers
, vrtfunc
, vrtcounterp
)
427 int (*vrtfunc
)(Dga_window
);
429 #if defined (__STDC__)
430 int (*vrtfunc
)(Dga_window
);
441 * Check for an invalid Dga_window
443 _Dga_window clientp
= (struct dga_window
*)clientpi
;
446 if ((clientp
== (_Dga_window
) NULL
)) {
448 (void) fprintf(stderr
, "dga_db_grab: passed null pointer\n");
454 * If the buffers has already been grabbed. Don't
457 if (clientp
->db_enabled
)
461 * Find out if this is an X window. If so get the Display and window
464 if (!_dga_is_X_window(clientp
->w_token
, &dpy
, &win
)) {
466 (void) fprintf(stderr
, "dga_db_grab: Unsupported window type\n");
472 * Request the server to allow DGA to the buffers associated
473 * with this Dga_window.
475 if (!XDgaGrabBuffers(dpy
, win
, nbuffers
)) {
477 (void) fprintf(stderr
, "dga_db_grab: XDgaGrabBuffers failed\n");
482 /* Now if they supplied vrtfunc, update the clientp
485 infop
=wx_infop(clientp
) ;
486 clientp
->vrt_func
= vrtfunc
;
488 /* Now update the clientp pointer with other info */
490 clientp
->db_enabled
= 1;
491 clientp
->db_vrtcntrp
= (u_int
*)vrtcounterp
;
492 clientp
->db_lastvrtcntr
= *vrtcounterp
;
493 clientp
->db_swapint
= 1;
494 if ((infop
->wx_dbuf
.display_buffer
< 0) ||
495 (infop
->wx_dbuf
.display_buffer
> (infop
->wx_dbuf
.number_buffers
- 1)))
496 infop
->wx_dbuf
.display_buffer
= 0;
497 if ((infop
->wx_dbuf
.read_buffer
< 0) ||
498 (infop
->wx_dbuf
.read_buffer
> (infop
->wx_dbuf
.number_buffers
- 1)))
499 infop
->wx_dbuf
.read_buffer
= 1;
500 if ((infop
->wx_dbuf
.write_buffer
< 0) ||
501 (infop
->wx_dbuf
.write_buffer
> (infop
->wx_dbuf
.number_buffers
- 1)))
502 infop
->wx_dbuf
.write_buffer
= 1;
506 /* Even though they have not supplied vrtp we allow the db_grab
507 * to succeed but we null out vrtfunc and set vrtcntrp to point
510 clientp
->db_enabled
= 1;
511 clientp
->vrt_func
= NULL
;
512 clientp
->db_vrtcntrp
= NULL
;
518 /* Returns 0 on failure and non-zero on success */
520 dga_db_ungrab(clientpi
)
523 _Dga_window clientp
= (struct dga_window
*)clientpi
;
529 * Check for an invalid Dga_window
531 if ((clientp
== (Dga_window
) NULL
)) {
533 (void) fprintf(stderr
, "dga_db_ungrab: passed null pointer\n");
538 /* If it wasm't grabbed in the first place. don't do anything */
539 if (!clientp
->db_enabled
)
544 * Find out if this is an X window. If so get the Display and window
547 if (!_dga_is_X_window(clientp
->w_token
, &dpy
, &win
)) {
549 (void) fprintf(stderr
, "dga_db_ungrab: Unsupported window type\n");
553 /* Mark the window as single buffered */
554 clientp
->db_enabled
= 0;
556 /* Tell server t ungrab */
557 return (XDgaUnGrabBuffers(dpy
, win
));
561 /* This is just for internal use */
563 _dga_db_vrtfunc_internal(wg_clientp
)
564 Dga_window wg_clientp
;
566 ( ioctl(((_Dga_window
)wg_clientp
)->w_devfd
,FBIOVERTICAL
,0));