summaryrefslogtreecommitdiff
path: root/src/glx/mini/dri_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glx/mini/dri_util.c')
-rw-r--r--src/glx/mini/dri_util.c715
1 files changed, 715 insertions, 0 deletions
diff --git a/src/glx/mini/dri_util.c b/src/glx/mini/dri_util.c
new file mode 100644
index 0000000000..6d79d2037c
--- /dev/null
+++ b/src/glx/mini/dri_util.c
@@ -0,0 +1,715 @@
+/**
+ * \file dri_util.c
+ * \brief 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 <fcntl.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/fb.h>
+#include <linux/vt.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+
+#include "sarea.h"
+#include "dri_util.h"
+
+/**
+ * \brief Print message to \c stderr if the \c LIBGL_DEBUG environment variable
+ * is set.
+ *
+ * Is called from the drivers.
+ *
+ * \param f \e printf like format.
+ *
+ * \internal
+ * This function is a wrapper around vfprintf().
+ */
+void
+__driUtilMessage(const char *f, ...)
+{
+ va_list args;
+
+ if (getenv("LIBGL_DEBUG")) {
+ fprintf(stderr, "libGL error: \n");
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ }
+}
+
+
+/*****************************************************************/
+/** \name Visual utility functions */
+/*****************************************************************/
+/*@{*/
+
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context (un)binding functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Unbind context.
+ *
+ * \param drawable __DRIdrawable
+ * \param context __DRIcontext
+ * \param will_rebind not used.
+ *
+ * \return GL_TRUE on success, or 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 null.
+ */
+static GLboolean driUnbindContext(__DRIdrawable *drawable,
+ __DRIcontext *context)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+ __DRIscreenPrivate *psp;
+
+ if (pdp == NULL || pcp == NULL)
+ return GL_FALSE;
+
+ if (!(psp = (__DRIscreenPrivate *)pdp->driScreenPriv))
+ return GL_FALSE;
+
+ /* Let driver unbind drawable from context */
+ (*psp->DriverAPI.UnbindContext)(pcp);
+
+ if (pdp->refcount == 0)
+ return GL_FALSE;
+
+ --pdp->refcount;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * \brief Unbind context.
+ *
+ * \param pDRIScreen __DRIscreen
+ * \param drawable __DRIdrawable
+ * \param context __DRIcontext
+ *
+ * \internal
+ * This function and increments __DRIdrawablePrivateRec::refcount and calls
+ * __DriverAPIRec::MakeCurrent to binds the drawable.
+ *
+ * While casting the opaque private pointers into their
+ * respective real types it also assures they are not null.
+ */
+static GLboolean driBindContext(__DRIscreen *screen, __DRIdrawable *drawable,
+ __DRIcontext *context)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+
+ if (psp == NULL)
+ return GL_FALSE;
+
+ if (pdp == NULL || pcp == NULL) {
+ (*psp->DriverAPI.MakeCurrent)(0, 0, 0);
+ return GL_TRUE;
+ }
+
+ /* Bind the drawable to the context */
+ pcp->driDrawablePriv = pdp;
+ pdp->driContextPriv = pcp;
+ pdp->refcount++;
+
+ /* Call device-specific MakeCurrent */
+ (*psp->DriverAPI.MakeCurrent)(pcp, pdp, pdp);
+
+ return GL_TRUE;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Drawable handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Update private drawable information.
+ *
+ * \param pdp pointer to the private drawable information to update.
+ *
+ * \internal
+ * This function is a no-op. Should never be called but is referenced as an
+ * external symbol from client drivers.
+ */
+void __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
+{
+ __DRIscreenPrivate *psp = pdp->driScreenPriv;
+
+ pdp->numClipRects = psp->pSAREA->drawableTable[pdp->index].flags ? 1 : 0;
+ pdp->lastStamp = *(pdp->pStamp);
+}
+
+
+/**
+ * \brief Swap buffers.
+ *
+ * \param pDRIscreen __DRIscreen
+ * \param drawablePrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DRIdrawablePrivate::swapBuffers.
+ *
+ * Is called directly from glXSwapBuffers().
+ */
+static void driSwapBuffers(__DRIdrawable *drawable)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ if (pdp)
+ pdp->swapBuffers(pdp);
+}
+
+
+/**
+ * \brief Destroy per-drawable private information.
+ *
+ * \param pDRIscreen __DRIscreen
+ * \param drawablePrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyBuffer on \p drawablePrivate,
+ * frees the clip rects if any, and finally frees \p drawablePrivate itself.
+ */
+static void driDestroyDrawable(__DRIdrawable *drawable)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIscreenPrivate *psp;
+
+ if (pdp) {
+ psp = pdp->driScreenPriv;
+ (*psp->DriverAPI.DestroyBuffer)(pdp);
+ if (pdp->pClipRects)
+ free(pdp->pClipRects);
+ free(pdp);
+ }
+}
+
+
+/**
+ * \brief Create the per-drawable private driver information.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param draw the GLX drawable info.
+ * \param vid visual ID.
+ * \param pdraw will receive the drawable dependent methods.
+ *
+ *
+ * \returns a opaque pointer to the per-drawable private info on success, or NULL
+ * on failure.
+ *
+ * \internal
+ * This function allocates and fills a __DRIdrawablePrivateRec structure,
+ * initializing the invariant window dimensions and clip rects. It obtains the
+ * visual config, converts it into a __GLcontextModesRec and passes it to
+ * __DriverAPIRec::CreateBuffer to create a buffer.
+ */
+static void *driCreateDrawable(__DRIscreen *screen,
+ int width, int height, int index,
+ const __GLcontextModes *glVisual)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIdrawablePrivate *pdp;
+
+ if (!psp)
+ return NULL;
+
+ if (!(pdp = (__DRIdrawablePrivate *)malloc(sizeof(__DRIdrawablePrivate))))
+ return NULL;
+
+ pdp->index = index;
+ pdp->refcount = 0;
+ pdp->lastStamp = -1;
+ pdp->numBackClipRects = 0;
+ pdp->pBackClipRects = NULL;
+
+ /* Initialize with the invariant window dimensions and clip rects here.
+ */
+ pdp->x = 0;
+ pdp->y = 0;
+ pdp->w = width;
+ pdp->h = height;
+ pdp->numClipRects = 0;
+ pdp->pClipRects = (XF86DRIClipRectPtr) malloc(sizeof(XF86DRIClipRectRec));
+ (pdp->pClipRects)[0].x1 = 0;
+ (pdp->pClipRects)[0].y1 = 0;
+ (pdp->pClipRects)[0].x2 = width;
+ (pdp->pClipRects)[0].y2 = height;
+
+ pdp->driScreenPriv = psp;
+ pdp->driContextPriv = 0;
+
+ pdp->frontBuffer = psp->pFB;
+ pdp->currentBuffer = pdp->frontBuffer;
+ pdp->currentPitch = psp->fbStride;
+ pdp->backBuffer = psp->pFB + psp->fbStride * psp->fbHeight;
+
+ if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, glVisual, GL_FALSE)) {
+ free(pdp);
+ return NULL;
+ }
+
+ pdp->entry.destroyDrawable = driDestroyDrawable;
+ pdp->entry.swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
+ pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
+
+ pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
+ return (void *) pdp;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Destroy the per-context private information.
+ *
+ * \param contextPrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
+ * drmDestroyContext(), and finally frees \p contextPrivate.
+ */
+static void driDestroyContext(__DRIcontext *context)
+{
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+ __DRIscreenPrivate *psp = NULL;
+
+ if (pcp) {
+ (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
+ psp = pcp->driDrawablePriv->driScreenPriv;
+ if (psp->fd) {
+ printf(">>> drmDestroyContext(0x%x)\n", (int) pcp->hHWContext);
+ drmDestroyContext(psp->fd, pcp->hHWContext);
+ }
+ free(pcp);
+ }
+}
+
+/**
+ * \brief Create the per-drawable private driver information.
+ *
+ * \param dpy the display handle.
+ * \param vis the visual information.
+ * \param sharedPrivate the shared context dependent methods or NULL if non-existent.
+ * \param pctx will receive the context dependent methods.
+ *
+ * \returns a opaque pointer to the per-context private information on success, or NULL
+ * on failure.
+ *
+ * \internal
+ * This function allocates and fills a __DRIcontextPrivateRec structure. It
+ * gets the visual, converts it into a __GLcontextModesRec and passes it
+ * to __DriverAPIRec::CreateContext to create the context.
+ */
+static void *driCreateContext(__DRIscreen *screen,
+ const __GLcontextModes *glVisual,
+ void *sharedPrivate)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIcontextPrivate *pcp;
+ __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
+ void *shareCtx;
+
+ if (!psp)
+ return NULL;
+
+ if (!(pcp = (__DRIcontextPrivate *)malloc(sizeof(__DRIcontextPrivate))))
+ return NULL;
+
+ pcp->driScreenPriv = psp;
+ pcp->driDrawablePriv = NULL;
+
+ if (psp->fd) {
+ if (drmCreateContext(psp->fd, &pcp->hHWContext)) {
+ fprintf(stderr, ">>> drmCreateContext failed\n");
+ free(pcp);
+ return NULL;
+ }
+ }
+
+ shareCtx = pshare ? pshare->driverPrivate : NULL;
+
+ if (!(*psp->DriverAPI.CreateContext)(glVisual, pcp, shareCtx)) {
+ if (psp->fd)
+ (void) drmDestroyContext(psp->fd, pcp->hHWContext);
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->entry.destroyContext = driDestroyContext;
+ pcp->entry.bindContext = driBindContext;
+ pcp->entry.unbindContext = driUnbindContext;
+
+ return pcp;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Screen handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Destroy the per-screen private information.
+ *
+ * \param pDRIscreen __DRIscreen
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
+ * drmClose(), and finally frees \p screenPrivate.
+ */
+static void driDestroyScreen(__DRIscreen *screen)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ if (psp) {
+ if (psp->DriverAPI.DestroyScreen)
+ (*psp->DriverAPI.DestroyScreen)(psp);
+
+ if (psp->fd)
+ (void)drmClose(psp->fd);
+
+ free(psp->pDevPriv);
+ free(psp);
+ }
+}
+
+
+/**
+ * \brief Create the per-screen private information.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param psc will receive the screen dependent methods.
+ * \param numConfigs number of visuals.
+ * \param config visuals.
+ * \param driverAPI driver callbacks structure.
+ *
+ * \return a pointer to the per-screen private information.
+ *
+ * \internal
+ * This function allocates and fills a __DRIscreenPrivateRec structure. It
+ * opens the DRM device verifying that the exported version matches the
+ * expected. It copies the driver callback functions and calls
+ * __DriverAPIRec::InitDriver.
+ *
+ * If a client maps the framebuffer and SAREA regions.
+ */
+__DRIscreenPrivate *
+__driUtilCreateScreen(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI)
+{
+ __DRIscreenPrivate *psp;
+
+ if(!(psp = (__DRIscreenPrivate *)malloc(sizeof(__DRIscreenPrivate))))
+ return NULL;
+
+ psp->fd = drmOpen(NULL, driverContext->pciBusID);
+ if (psp->fd < 0) {
+ fprintf(stderr, "libGL error: failed to open DRM: %s\n",
+ strerror(-psp->fd));
+ free(psp);
+ return NULL;
+ }
+
+ {
+ drmVersionPtr version = drmGetVersion(psp->fd);
+ if (version) {
+ psp->drmMajor = version->version_major;
+ psp->drmMinor = version->version_minor;
+ psp->drmPatch = version->version_patchlevel;
+ drmFreeVersion(version);
+ }
+ else {
+ fprintf(stderr, "libGL error: failed to get drm version: %s\n",
+ strerror(-psp->fd));
+ free(psp);
+ return NULL;
+ }
+ }
+
+ /*
+ * Fake various version numbers.
+ */
+ psp->ddxMajor = 4;
+ psp->ddxMinor = 0;
+ psp->ddxPatch = 1;
+ psp->driMajor = 4;
+ psp->driMinor = 1;
+ psp->driPatch = 0;
+
+ /* install driver's callback functions */
+ psp->DriverAPI = *driverAPI;
+
+ /*
+ * Get device-specific info. pDevPriv will point to a struct
+ * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
+ * that has information about the screen size, depth, pitch,
+ * ancilliary buffers, DRM mmap handles, etc.
+ */
+ psp->fbOrigin = driverContext->shared.fbOrigin;
+ psp->fbSize = driverContext->shared.fbSize;
+ psp->fbStride = driverContext->shared.fbStride;
+ psp->devPrivSize = driverContext->driverClientMsgSize;
+ psp->pDevPriv = driverContext->driverClientMsg;
+ psp->fbWidth = driverContext->shared.virtualWidth;
+ psp->fbHeight = driverContext->shared.virtualHeight;
+ psp->fbBPP = driverContext->bpp;
+
+ if ((driverContext->FBAddress != NULL) && (driverContext->pSAREA != NULL)) {
+ /* Already mapped in server */
+ psp->pFB = driverContext->FBAddress;
+ psp->pSAREA = driverContext->pSAREA;
+ } else {
+ /*
+ * Map the framebuffer region.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hFrameBuffer, psp->fbSize,
+ (drmAddressPtr)&psp->pFB)) {
+ fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+ /*
+ * Map the SAREA region. Further mmap regions may be setup in
+ * each DRI driver's "createScreen" function.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hSAREA,
+ driverContext->shared.SAREASize,
+ (drmAddressPtr)&psp->pSAREA)) {
+ fprintf(stderr, "libGL error: drmMap of sarea failed\n");
+ (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+#ifdef _EMBEDDED
+ mprotect(psp->pSAREA, driverContext->shared.SAREASize, PROT_READ);
+#endif
+ }
+
+
+ /* Initialize the screen specific GLX driver */
+ if (psp->DriverAPI.InitDriver) {
+ if (!(*psp->DriverAPI.InitDriver)(psp)) {
+ fprintf(stderr, "libGL error: InitDriver failed\n");
+ free(psp->pDevPriv);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+ }
+
+ psp->entry.destroyScreen = driDestroyScreen;
+ psp->entry.createContext = driCreateContext;
+ psp->entry.createDrawable = driCreateDrawable;
+
+ return psp;
+}
+
+
+
+/**
+ * \brief Create the per-screen private information.
+ *
+ * Version for drivers without a DRM module.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param numConfigs number of visuals.
+ * \param config visuals.
+ * \param driverAPI driver callbacks structure.
+ *
+ * \internal
+ * Same as __driUtilCreateScreen() but without opening the DRM device.
+ */
+__DRIscreenPrivate *
+__driUtilCreateScreenNoDRM(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI)
+{
+ __DRIscreenPrivate *psp;
+
+ psp = (__DRIscreenPrivate *)calloc(1, sizeof(__DRIscreenPrivate));
+ if (!psp)
+ return NULL;
+
+ psp->ddxMajor = 4;
+ psp->ddxMinor = 0;
+ psp->ddxPatch = 1;
+ psp->driMajor = 4;
+ psp->driMinor = 1;
+ psp->driPatch = 0;
+ psp->fd = 0;
+
+ psp->fbOrigin = driverContext->shared.fbOrigin;
+ psp->fbSize = driverContext->shared.fbSize;
+ psp->fbStride = driverContext->shared.fbStride;
+ psp->devPrivSize = driverContext->driverClientMsgSize;
+ psp->pDevPriv = driverContext->driverClientMsg;
+ psp->fbWidth = driverContext->shared.virtualWidth;
+ psp->fbHeight = driverContext->shared.virtualHeight;
+ psp->fbBPP = driverContext->bpp;
+
+ psp->pFB = driverContext->FBAddress;
+
+ /* install driver's callback functions */
+ psp->DriverAPI = *driverAPI;
+
+ if ((driverContext->FBAddress != NULL) && (driverContext->pSAREA != NULL)) {
+ /* Already mapped in server */
+ psp->pFB = driverContext->FBAddress;
+ psp->pSAREA = driverContext->pSAREA;
+ } else {
+ psp->fd = open("/dev/mem", O_RDWR, 0);
+ /*
+ * Map the framebuffer region.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hFrameBuffer, psp->fbSize,
+ (drmAddressPtr)&psp->pFB)) {
+ fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+ driverContext->FBAddress = psp->pFB;
+
+ /*
+ * Map the SAREA region. Non-DRM drivers use a shmem SAREA
+ */
+ int id;
+ id = shmget(driverContext->shared.hSAREA, driverContext->shared.SAREASize, 0);
+ driverContext->pSAREA = shmat(id, NULL, 0);
+ if (!driverContext->pSAREA) {
+ fprintf(stderr, "libGL error: shmget of sarea failed\n");
+ (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+ close(psp->fd);
+ psp->fd = 0;
+ }
+
+ /* Initialize the screen specific GLX driver */
+ if (psp->DriverAPI.InitDriver) {
+ if (!(*psp->DriverAPI.InitDriver)(psp)) {
+ fprintf(stderr, "libGL error: InitDriver failed\n");
+ free(psp->pDevPriv);
+ free(psp);
+ return NULL;
+ }
+ }
+
+ psp->entry.destroyScreen = driDestroyScreen;
+ psp->entry.createContext = driCreateContext;
+ psp->entry.createDrawable = driCreateDrawable;
+
+ return psp;
+}
+
+/**
+ * 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().
+ */
+float
+driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
+ int64_t current_ust )
+{
+ return 0.0f;
+}
+
+/**
+ * Compare the current GLX API version with a driver supplied required version.
+ *
+ * The minimum required version is compared with the API version exported by
+ * the \c __glXGetInternalVersion function (in libGL.so).
+ *
+ * \param required_version Minimum required internal GLX API version.
+ * \return A tri-value return, as from strcmp is returned. A value less
+ * than, equal to, or greater than zero will be returned if the
+ * internal GLX API version is less than, equal to, or greater
+ * than \c required_version.
+ *
+ * \sa __glXGetInternalVersion().
+ */
+int driCompareGLXAPIVersion( GLuint required_version )
+{
+ return 0;
+}
+
+/*@}*/