/* Copyright (c) 1993, 1999, Oracle and/or its affiliates. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * dga_db.c - the client side code for DGA double buffering */ #include #include #include #include #include #ifndef FBIOVRTOFFSET #ifdef SVR4 #define FBIOVRTOFFSET (FIOC | 38) #else #define FBIOVRTOFFSET _IOR(F, 38, int) #endif #endif #include #include #include #include "dga_incls.h" #define DGA_WIN_LOCK_NOMODIF(win) \ { \ if ((((_Dga_window)(win))->w_lockcnt)++ == 0) { \ DGA_LOCK(win); \ } \ } #define DGA_WIN_UNLOCK_NOMODIF(win) \ { \ if (--(((_Dga_window)(win))->w_lockcnt) == 0) \ DGA_UNLOCK(win); \ } extern void *_dga_is_X_window(Dga_token token, Display **dpyp, Window *winp); #ifdef _LP64 static int _dga_db_vrtfunc_internal(Dga_window); #else /* _LP64 */ #if defined(__STDC__) static int _dga_db_vrtfunc_internal(Dga_window); #else static int _dga_db_vrtfunc_internal(); #endif #endif /* _LP64 */ static u_int *dga_vrt_access(); static void dga_vrt_release(); int dga_db_access(wg_clientpi) Dga_window wg_clientpi ; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; WXINFO *infop = wx_infop(wg_clientp) ; u_int *cpage; u_int *dga_vrt_access(); if (wg_clientp->db_enabled) return 0; if (infop->wx_dbuf.number_buffers < 2) return 1; cpage = dga_vrt_access(wg_clientp->w_devfd); if (cpage) { wg_clientp->db_enabled = 1; wg_clientp->db_vrtcntrp = cpage; wg_clientp->db_lastvrtcntr = *cpage; wg_clientp->db_swapint = 1; wg_clientp->vrt_func = _dga_db_vrtfunc_internal ; if ((infop->wx_dbuf.display_buffer < 0) || (infop->wx_dbuf.display_buffer > (infop->wx_dbuf.number_buffers - 1))) infop->wx_dbuf.display_buffer = 0; if ((infop->wx_dbuf.read_buffer < 0) || (infop->wx_dbuf.read_buffer > (infop->wx_dbuf.number_buffers - 1))) infop->wx_dbuf.read_buffer = 1; if ((infop->wx_dbuf.write_buffer < 0) || (infop->wx_dbuf.write_buffer > (infop->wx_dbuf.number_buffers - 1))) infop->wx_dbuf.write_buffer = 1; return(0); } else return(1); } void dga_db_release(wg_clientpi) Dga_window wg_clientpi ; { void dga_vrt_release(); _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; if (wg_clientp->db_vrtcntrp) dga_vrt_release(wg_clientp->db_vrtcntrp); wg_clientp->db_enabled = 0; } void dga_db_write(wg_clientpi,buffer,writefunc,data) Dga_window wg_clientpi ; int buffer; #ifdef _LP64 int (*writefunc)(void*, Dga_window, int); #else /* _LP64 */ #if defined (__STDC__) int (*writefunc)(void*, Dga_window, int); #else int (*writefunc)(); #endif #endif /* _LP64 */ void* data; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; DGA_WIN_LOCK_NOMODIF(wg_clientp); if (writefunc) (*writefunc) (data,wg_clientpi,buffer); wx_infop(wg_clientp)->wx_dbuf.write_buffer = buffer; DGA_WIN_UNLOCK_NOMODIF(wg_clientp); } void dga_db_read(wg_clientpi,buffer,readfunc,data) Dga_window wg_clientpi ; int buffer; #ifdef _LP64 int (*readfunc)(void*, Dga_window, int); #else /* _LP64 */ #if defined (__STDC__) int (*readfunc)(void*, Dga_window, int); #else int (*readfunc)(); #endif #endif /* _LP64 */ void* data; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; DGA_WIN_LOCK_NOMODIF(wg_clientp); wx_infop(wg_clientp)->wx_dbuf.read_buffer = buffer; if (readfunc) (*readfunc) (data,wg_clientpi,buffer); DGA_WIN_UNLOCK_NOMODIF(wg_clientp); } void dga_db_display(wg_clientpi,buffer,visfunc,data) Dga_window wg_clientpi ; int buffer; #ifdef _LP64 int (*visfunc)(void*, Dga_window, int); #else /* _LP64 */ #if defined (__STDC__) int (*visfunc)(void*, Dga_window, int); #else int (*visfunc)(); #endif #endif /* _LP64 */ void* data; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; if (!dga_db_interval_check(wg_clientpi)) dga_db_interval_wait(wg_clientpi); if (visfunc) (*visfunc)(data, wg_clientpi, buffer); if (wg_clientp->db_vrtcntrp) wg_clientp->db_lastvrtcntr = *wg_clientp->db_vrtcntrp; wx_infop(wg_clientp)->wx_dbuf.display_buffer = buffer; } void dga_db_interval(wg_clientpi,interval) Dga_window wg_clientpi ; int interval; /* number of milliseconds */ { int ref_rate; float rr; _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; ref_rate = wx_infop(wg_clientp)->w_refresh_period; if (ref_rate == 0) ref_rate = 66000; if (interval < 0) interval = 0; if (interval > ref_rate) interval = ref_rate; rr = ((float)ref_rate)* 0.001; wg_clientp->db_swapint = rr * ((float)interval* 0.001); if (wg_clientp->db_swapint == 0) wg_clientp->db_swapint = 1; } void dga_db_interval_wait(wg_clientpi) Dga_window wg_clientpi ; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; u_int *counter = wg_clientp->db_vrtcntrp; /* Do a block if necessary and if vrt_func has been supplied */ if (!wg_clientp->vrt_func || !wg_clientp->db_vrtcntrp) return; while (((u_int) (*counter - wg_clientp->db_lastvrtcntr)) < wg_clientp->db_swapint) { if ((*(wg_clientp->vrt_func))(wg_clientpi) < 0) return ;; } return; } int dga_db_interval_check(wg_clientpi) Dga_window wg_clientpi ; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; u_int *counter = wg_clientp->db_vrtcntrp; if ((wg_clientp->db_vrtcntrp) && ((u_int) (*counter - wg_clientp->db_lastvrtcntr)) < wg_clientp->db_swapint) return(0); else return(1); } int dga_db_write_inquire(wg_clientpi) Dga_window wg_clientpi ; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; return(wx_infop(wg_clientp)->wx_dbuf.write_buffer); } int dga_db_read_inquire(wg_clientpi) Dga_window wg_clientpi ; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; return(wx_infop(wg_clientp)->wx_dbuf.read_buffer); } int dga_db_display_inquire(wg_clientpi) Dga_window wg_clientpi ; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; return(wx_infop(wg_clientp)->wx_dbuf.display_buffer); } /* INTERNAL INTERFACE */ int dga_db_display_complete(wg_clientpi, flag) Dga_window wg_clientpi ; int flag; { _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; if (wg_clientp->db_vrtcntrp && (wg_clientp->db_lastvrtcntr != *(wg_clientp->db_vrtcntrp))) return 1; if (flag == 0) return 0; if (ioctl(wg_clientp->w_devfd,FBIOVERTICAL,0) < 0) return 0; return 1; } /* INTERNAL INTERFACE */ static u_int *dga_vrt_access(devfd) int devfd; { u_int *cpage; u_int dev_offset; u_int pagesize; dev_offset = 0; if (ioctl(devfd, FBIOVRTOFFSET, &dev_offset) < 0) return (NULL); #ifdef SVR4 pagesize = sysconf(_SC_PAGESIZE); #else pagesize = getpagesize(); #endif /* * the driver provides the dev_offset into the mmaped page * where the vertical retrace counter word is. * We will mmap a shared memory page that is on a * page boundary then modify the pointer to the * vertical retrace counter to reflect the exact * location where the counter word exists */ cpage = (u_int *) mmap((char *)0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED | _MAP_NEW, devfd, (off_t) (dev_offset & ~(pagesize - 1))); /* if the mmap failed then return NULL otherwide return * the computed address of the vertical retract counter * by adding the beginning of the mmaped page to the * dev_offset into the page returned by the device driver */ if (cpage == (u_int *) -1) return NULL; return ((u_int *) ((int) cpage | (dev_offset & (pagesize - 1)))); } static void dga_vrt_release(counter) u_int *counter; { char *counter_page; int pagesize; #ifdef SVR4 pagesize = sysconf(_SC_PAGESIZE); #else pagesize = getpagesize(); #endif /* Unmap the page for this client. * remove the offset computation and munmap the * vertical retrace counter page. we remove the * offset by simply setting the lower bits of * the address to 0 */ counter_page = (char *) (((int) counter) & (~(pagesize - 1))); munmap(counter_page, pagesize) ; return; } /* New routines that will be exposed to the public */ int dga_db_display_done(wg_clientpi,flag, display_done_func) Dga_window wg_clientpi; int flag; #ifdef _LP64 int (*display_done_func)(Dga_window); { int (*vrt_func)(Dga_window); #else /* _LP64 */ #if defined (__STDC__) int (*display_done_func)(Dga_window); #else int (*display_done_func)(); #endif { #if defined (__STDC__) int (*vrt_func)(Dga_window); #else int (*vrt_func)(); #endif #endif /* _LP64 */ _Dga_window wg_clientp = (struct dga_window *)wg_clientpi; int ret_val; /* Return 1 = done, 0 = not done, -1 = error */ ret_val = (*display_done_func)(wg_clientpi); /* If the user does not want to block or if the * display_done_func() returned a non-zero, we return * else we try till success after each vrt_retrace() */ if ((!flag) || (ret_val != 0)) return (ret_val); vrt_func = wg_clientp->vrt_func; if (!vrt_func) return 1; while((ret_val = (*display_done_func)(wg_clientpi)) == 0) if (vrt_func(wg_clientpi) < 0) return -1; return (ret_val); } /* Returns 0 on fail and non-zero on success */ int dga_db_grab(clientpi, nbuffers, vrtfunc, vrtcounterp) Dga_window clientpi; int nbuffers; #ifdef _LP64 int (*vrtfunc)(Dga_window); #else /* _LP64 */ #if defined (__STDC__) int (*vrtfunc)(Dga_window); #else int (*vrtfunc)(); #endif #endif /* _LP64 */ u_int *vrtcounterp; { Display *dpy; Window win; /* * Check for an invalid Dga_window */ _Dga_window clientp = (struct dga_window *)clientpi; WXINFO *infop; if ((clientp == (_Dga_window) NULL)) { #ifdef DEBUG (void) fprintf(stderr, "dga_db_grab: passed null pointer\n"); #endif return (0); } /* * If the buffers has already been grabbed. Don't * do anything. */ if (clientp->db_enabled) return (1); /* * Find out if this is an X window. If so get the Display and window * id. */ if (!_dga_is_X_window(clientp->w_token, &dpy, &win)) { #ifdef DEBUG (void) fprintf(stderr, "dga_db_grab: Unsupported window type\n"); #endif return (0); } /* * Request the server to allow DGA to the buffers associated * with this Dga_window. */ if (!XDgaGrabBuffers(dpy, win, nbuffers)) { #ifdef DEBUG (void) fprintf(stderr, "dga_db_grab: XDgaGrabBuffers failed\n"); #endif return (0); } /* Now if they supplied vrtfunc, update the clientp */ infop =wx_infop(clientp) ; clientp->vrt_func = vrtfunc; /* Now update the clientp pointer with other info */ if (vrtcounterp) { clientp->db_enabled = 1; clientp->db_vrtcntrp = (u_int *)vrtcounterp; clientp->db_lastvrtcntr = *vrtcounterp; clientp->db_swapint = 1; if ((infop->wx_dbuf.display_buffer < 0) || (infop->wx_dbuf.display_buffer > (infop->wx_dbuf.number_buffers - 1))) infop->wx_dbuf.display_buffer = 0; if ((infop->wx_dbuf.read_buffer < 0) || (infop->wx_dbuf.read_buffer > (infop->wx_dbuf.number_buffers - 1))) infop->wx_dbuf.read_buffer = 1; if ((infop->wx_dbuf.write_buffer < 0) || (infop->wx_dbuf.write_buffer > (infop->wx_dbuf.number_buffers - 1))) infop->wx_dbuf.write_buffer = 1; return(1); } else { /* Even though they have not supplied vrtp we allow the db_grab * to succeed but we null out vrtfunc and set vrtcntrp to point * to itself! */ clientp->db_enabled = 1; clientp->vrt_func = NULL; clientp->db_vrtcntrp = NULL; return(1); } } /* Returns 0 on failure and non-zero on success */ int dga_db_ungrab(clientpi) Dga_window clientpi; { _Dga_window clientp = (struct dga_window *)clientpi; Display *dpy; Window win; int status = -1; /* * Check for an invalid Dga_window */ if ((clientp == (Dga_window) NULL)) { #ifdef DEBUG (void) fprintf(stderr, "dga_db_ungrab: passed null pointer\n"); #endif return (0); } /* If it wasm't grabbed in the first place. don't do anything */ if (!clientp->db_enabled) return 1; /* * Find out if this is an X window. If so get the Display and window * id. */ if (!_dga_is_X_window(clientp->w_token, &dpy, &win)) { #ifdef DEBUG (void) fprintf(stderr, "dga_db_ungrab: Unsupported window type\n"); #endif return (0); } /* Mark the window as single buffered */ clientp->db_enabled = 0; /* Tell server t ungrab */ return (XDgaUnGrabBuffers(dpy, win)); } /* This is just for internal use */ static int _dga_db_vrtfunc_internal(wg_clientp) Dga_window wg_clientp; { ( ioctl(((_Dga_window)wg_clientp)->w_devfd,FBIOVERTICAL,0)); return(1); }