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