/* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */
/**
* \file dri_util.c
* DRI utility functions.
*
* This module acts as glue between GLX and the actual hardware driver. A DRI
* driver doesn't really \e have to use any of this - it's optional. But, some
* useful stuff is done here that otherwise would have to be duplicated in most
* drivers.
*
* Basically, these utility functions take care of some of the dirty details of
* screen initialization, context creation, context binding, DRM setup, etc.
*
* These functions are compiled into each DRI driver so libGL.so knows nothing
* about them.
*/
#include <assert.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>
#ifndef MAP_FAILED
#endif
#include "imports.h"
#define None 0
#include "dri_util.h"
#include "drm_sarea.h"
#include "utils.h"
#ifndef GLX_OML_sync_control
typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator);
#endif
/**
* This is just a token extension used to signal that the driver
* supports setting a read drawable.
*/
};
/**
* Print message to \c stderr if the \c LIBGL_DEBUG environment variable
* is set.
*
* Is called from the drivers.
*
* \param f \c printf like format string.
*/
void
__driUtilMessage(const char *f, ...)
{
if (getenv("LIBGL_DEBUG")) {
}
}
{
}
/*****************************************************************/
/** \name Context (un)binding functions */
/*****************************************************************/
/*@{*/
/**
* Unbind context.
*
* \param scrn the screen.
* \param gc context.
*
* \return \c GL_TRUE on success, or \c GL_FALSE on failure.
*
* \internal
* This function calls __DriverAPIRec::UnbindContext, and then decrements
* __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
* return.
*
* While casting the opaque private pointers associated with the parameters
* into their respective real types it also assures they are not \c NULL.
*/
{
/*
** Assume error checking is done properly in glXMakeCurrent before
** calling driUnbindContext.
*/
return GL_FALSE;
/* Let driver unbind drawable from context */
/* ERROR!!! */
return GL_FALSE;
}
/* ERROR!!! */
return GL_FALSE;
}
}
/* XXX this is disabled so that if we call SwapBuffers on an unbound
* window we can determine the last context bound to the window and
* use that context's lock. (BrianP, 2-Dec-2000)
*/
#if 0
/* Unbind the drawable */
#endif
return GL_TRUE;
}
/**
* This function takes both a read buffer and a draw buffer. This is needed
* for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
* function.
*/
{
/*
** Assume error checking is done properly in glXMakeCurrent before
** calling driBindContext.
*/
return GL_FALSE;
/* Bind the drawable to the context */
}
/*
** Now that we have a context associated with this drawable, we can
** initialize the drawable information if has not been done before.
*/
} else {
}
}
}
/* Call device-specific MakeCurrent */
return GL_TRUE;
}
/*@}*/
/*****************************************************************/
/** \name Drawable handling functions */
/*****************************************************************/
/*@{*/
/**
* Update private drawable information.
*
* \param pdp pointer to the private drawable information to update.
*
* This function basically updates the __DRIdrawablePrivate struct's
* cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
* This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
* compares the __DRIdrwablePrivate pStamp and lastStamp values. If
* the values are different that means we have to update the clipping
* info.
*/
void
{
if (!pcp
/* ERROR!!!
* ...but we must ignore it. There can be many contexts bound to a
* drawable.
*/
}
if (pdp->pClipRects) {
}
if (pdp->pBackClipRects) {
}
pdp->loaderPrivate)) {
/* Error -- eg the window may have been destroyed. Keep going
* with no cliprects.
*/
pdp->numClipRects = 0;
pdp->numBackClipRects = 0;
}
else
}
int
{
unsigned char *data;
/* Check for wraparound. */
/* If prealloc overlaps into what we just parsed, the
* server overwrote it and we have to reset our tail
* pointer. */
pdp->loaderPrivate);
}
changed = 0;
size = DRI2_EVENT_SIZE(*p);
/* illegal data, bail out. */
break;
}
switch (DRI2_EVENT_TYPE(*p)) {
dc = (__DRIDrawableConfigEvent *) p;
break;
case DRI2_EVENT_BUFFER_ATTACH:
ba = (__DRIBufferAttachEvent *) p;
break;
}
}
if (last_dc) {
changed = 1;
}
/* We only care about the most recent drawable config. */
/* Front buffer attachments are special, they typically mean that
* we're rendering to a redirected window (or a child window of a
* redirected window) and that it got resized. Resizing the root
* window on randr events is a special case of this. Other causes
* may be a window transitioning between redirected and
* non-redirected, or a window getting reparented between parents
* with different window pixmaps (eg two redirected windows).
* These events are special in that the X server allocates the
* buffer and that the buffer may be shared by other child
* windows. When our window share the window pixmap with its
* parent, drawable config events doesn't affect the front buffer.
* We only care about the last such event in the buffer; in fact,
* older events will refer to invalid buffer objects.*/
if (last_ba)
/* If there was a drawable config event in the buffer and it
* changed the size of the window, all buffer auxiliary buffer
* attachments prior to that are invalid (as opposed to the front
* buffer case discussed above). In that case we can start
* looking for buffer attachment after the last drawable config
* event. If there is no drawable config event in this batch of
* events, we have to assume that the last batch might have had
* one and process all buffer attach events.*/
else
continue;
continue;
continue;
changed = 1;
}
}
/*@}*/
/*****************************************************************/
/** \name GLX callbacks */
/*****************************************************************/
/*@{*/
{
/* Check that we actually have the new damage report method */
pdp->loaderPrivate);
/* Report the damage. Currently, all our drivers draw
* directly to the front buffer, so we report the damage there
* rather than to the backing storein (if any).
*/
}
}
/**
* Swap buffers.
*
* \param drawablePrivate opaque pointer to the per-drawable private info.
*
* \internal
* This function calls __DRIdrawablePrivate::swapBuffers.
*
* Is called directly from glXSwapBuffers().
*/
{
if (!dPriv->numClipRects)
return;
}
{
}
{
int status;
msc );
/* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
* is supported but GLX_OML_sync_control is not. Therefore, don't return
* an error value if GetSwapInfo() is not implemented.
*/
if ( status == 0
}
return status;
}
};
int x, int y, int w, int h)
{
}
};
{
}
{
return dPriv->swap_interval;
}
};
/**
* This is called via __DRIscreenRec's createNewDrawable pointer.
*/
static __DRIdrawable *
{
/* Since pbuffers are not yet supported, no drawable attributes are
* supported either.
*/
(void) attrs;
if (!pdp) {
return NULL;
}
pdp->x = 0;
pdp->y = 0;
pdp->w = 0;
pdp->h = 0;
pdp->numClipRects = 0;
pdp->numBackClipRects = 0;
renderType == GLX_PIXMAP_BIT)) {
return NULL;
}
/* This special default value is replaced with the configured
* default value when the drawable is first bound to a direct
* rendering context.
*/
return pdp;
}
static __DRIdrawable *
{
if (!pdraw)
return NULL;
return pdraw;
}
static void
{
if (pdp) {
if (pdp->pClipRects) {
}
if (pdp->pBackClipRects) {
}
}
}
/*@}*/
/*****************************************************************/
/** \name Context handling functions */
/*****************************************************************/
/*@{*/
/**
* Destroy the per-context private information.
*
* \internal
* This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
* drmDestroyContext(), and finally frees \p contextPrivate.
*/
static void
{
if (pcp) {
}
}
/**
* Create the per-drawable private driver information.
*
* \param render_type Type of rendering target. \c GLX_RGBA is the only
* type likely to ever be supported for direct-rendering.
* \param shared Context with which to share textures, etc. or NULL
*
* \returns An opaque pointer to the per-context private information on
* success, or \c NULL on failure.
*
* \internal
* This function allocates and fills a __DRIcontextPrivateRec structure. It
* performs some device independent initialization and passes all the
* relevant information to __DriverAPIRec::CreateContext to create the
* context.
*
*/
static __DRIcontext *
{
if (!pcp)
return NULL;
/* When the first context is created for a screen, initialize a "dummy"
* context.
*/
/* No other fields should be used! */
}
return NULL;
}
return pcp;
}
static __DRIcontext *
{
/* DRI2 doesn't use kernel with context IDs, we just need an ID that's
* different from the kernel context ID to make drmLock() happy. */
do {
} while (ret);
}
static int
{
return GL_FALSE;
}
/*@}*/
/*****************************************************************/
/** \name Screen handling functions */
/*****************************************************************/
/*@{*/
/**
* Destroy the per-screen private information.
*
* \internal
* This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
* drmClose(), and finally frees \p screenPrivate.
*/
{
if (psp) {
/* No interaction with the X-server is possible at this point. This
* routine is called after XCloseDisplay, so there is no protocol
* stream open to the X-server anymore.
*/
#ifdef TTM_API
#endif
} else {
}
}
}
static void
const __DRIextension **extensions)
{
int i;
for (i = 0; extensions[i]; i++) {
}
}
/**
* This is the bootstrap function for the driver. libGL supplies all of the
* requisite information about the system, and the driver initializes itself.
* This routine also fills in the linked list pointed to by \c driver_modes
* with the \c __GLcontextModes that the driver can support for windows or
* pbuffers.
*
* For legacy DRI.
*
* \param scrn Index of the screen
* \param ddx_version Version of the 2D DDX. This may not be meaningful for
* all drivers.
* \param dri_version Version of the "server-side" DRI.
* \param drm_version Version of the kernel DRM.
* \param frame_buffer Data describing the location and layout of the
* framebuffer.
* \param pSAREA Pointer the the SAREA.
* \param fd Device handle for the DRM.
* \param extensions ??
* \param driver_modes Returns modes supported by the driver
* \param loaderPrivate ??
*
* \note There is no need to check the minimum API version in this
* function. Since the name of this function is versioned, it is
* impossible for a loader that is too old to even load this driver.
*/
static __DRIscreen *
const __DRIversion *ddx_version,
const __DRIversion *dri_version,
const __DRIversion *drm_version,
const __DRIframebuffer *frame_buffer,
const __DRIextension **extensions,
const __DRIconfig ***driver_modes,
void *loaderPrivate)
{
if (!psp)
return NULL;
/*
** NOT_DONE: This is used by the X server to detect when the client
** has died while holding the drawable lock. The client sets the
** drawable lock to this value.
*/
/*
** Do not init dummy context here; actual initialization will be
** done when the first DRI context is created. Init screen priv ptr
** to NULL to let CreateContext routine that it needs to be inited.
*/
if (*driver_modes == NULL) {
return NULL;
}
return psp;
}
/**
* DRI2
*/
static __DRIscreen *
const __DRIextension **extensions,
{
#ifdef TTM_API
unsigned int *p;
return NULL;
if (!psp)
return NULL;
if (version) {
}
return NULL;
}
return NULL;
}
while (DRI2_SAREA_BLOCK_TYPE(*p)) {
switch (DRI2_SAREA_BLOCK_TYPE(*p)) {
case DRI2_SAREA_BLOCK_LOCK:
break;
break;
}
p = DRI2_SAREA_BLOCK_NEXT(p);
}
if (*driver_configs == NULL) {
return NULL;
}
return psp;
#else
return NULL;
#endif
}
{
return psp->extensions;
}
/** Legacy DRI interface */
};
/** DRI2 interface */
{ __DRI_CORE, __DRI_CORE_VERSION },
};
/* This is the table of extensions that the loader will dlsym() for. */
};
static int
{
return GLX_BAD_CONTEXT;
}
static int
float * lastMissedUsage, float * usage)
{
int status;
if ( status == 0 ) {
}
return status;
}
};
/**
* Calculate amount of swap interval used between GLX buffer swaps.
*
* The usage value, on the range [0,max], is the fraction of total swap
* interval time used between GLX buffer swaps is calculated.
*
* \f$p = t_d / (i * t_r)\f$
*
* Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
* swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
* required for a single vertical refresh period (as returned by \c
* glXGetMscRateOML).
*
* See the documentation for the GLX_MESA_swap_frame_usage extension for more
* details.
*
* \param dPriv Pointer to the private drawable structure.
* \return If less than a single swap interval time period was required
* between GLX buffer swaps, a number greater than 0 and less than
* 1.0 is returned. If exactly one swap interval time period is
* required, 1.0 is returned, and if more than one is required then
* a number greater than 1.0 will be returned.
*
* \sa glXSwapIntervalSGI glXGetMscRateOML
*
* \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
* be possible to cache the sync rate?
*/
float
{
int32_t n;
int32_t d;
int interval;
/* We want to calculate
* (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
* current_UST by calling __glXGetUST. last_swap_UST is stored in
* dPriv->swap_ust. interval has already been calculated.
*
* The only tricky part is us_per_refresh. us_per_refresh is
* 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
* around and say us_per_refresh = 1000000 * d / n. Since this goes in
* the denominator of the final calculation, we calculate
* (interval * 1000000 * d) and move n into the numerator.
*/
usage *= n;
usage /= 1000000.0;
}
return usage;
}
/*@}*/